13 #define TRACE_VAR_LOOKUPS 0
14 #define TRACE_NODE_RETURNS 0
17 extern tSpiderFunction *gpExports_First;
21 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
22 tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
23 tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value);
25 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
26 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
27 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
28 void Variable_Destroy(tAST_Variable *Variable);
30 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
31 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
34 int giNextBlockIdent = 1;
37 tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments)
43 // Build a block State
47 bs.BaseNamespace = &Script->Variant->RootNamespace;
48 bs.CurNamespace = NULL;
50 bs.Ident = giNextBlockIdent ++;
53 for( i = 0; i < Fcn->ArgumentCount; i ++ )
55 if( i >= NArguments ) break; // TODO: Return gracefully
58 Fcn->Arguments[i].Type, Fcn->Arguments[i].Name,
63 ret = AST_ExecuteNode(&bs, Fcn->ASTFcn);
66 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
67 ret = bs.RetVal; // Set to return value of block
72 tAST_Variable *nextVar = bs.FirstVar->Next;
73 Variable_Destroy( bs.FirstVar );
74 bs.FirstVar = nextVar;
80 * \brief Execute a script function
81 * \param Script Script context to execute in
82 * \param Namespace Namespace to search for the function
83 * \param Function Function name to execute
84 * \param NArguments Number of arguments to pass
85 * \param Arguments Arguments passed
87 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
88 tSpiderNamespace *Namespace, const char *Function,
89 int NArguments, tSpiderValue **Arguments)
91 int bFound = 0; // Used to keep nesting levels down
92 tSpiderValue *ret = ERRPTR;
94 // First: Find the function in the script
96 tScript_Function *fcn;
97 for( fcn = Script->Functions; fcn; fcn = fcn->Next )
99 if( strcmp(fcn->Name, Function) == 0 )
105 ret = AST_ExecuteFunction(Script, fcn, NArguments, Arguments);
110 // Didn't find it in script?
113 tSpiderFunction *fcn;
114 fcn = NULL; // Just to allow the below code to be neat
116 // Second: Scan current namespace
117 if( !fcn && Namespace )
119 for( fcn = Namespace->Functions; fcn; fcn = fcn->Next )
121 if( strcmp( fcn->Name, Function ) == 0 )
126 // Third: Search the variant's global exports
129 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
131 if( strcmp( fcn->Name, Function ) == 0 )
136 // Fourth: Search language exports
139 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
141 if( strcmp( fcn->Name, Function ) == 0 )
149 // TODO: Type Checking
150 ret = fcn->Handler( Script, NArguments, Arguments );
158 fprintf(stderr, "Undefined reference to function '%s' (ns='%s')\n",
159 Function, Namespace->Name);
167 * \brief Execute an object method function
168 * \param Script Script context to execute in
169 * \param Object Object in which to find the method
170 * \param MethodName Name of method to call
171 * \param NArguments Number of arguments to pass
172 * \param Arguments Arguments passed
174 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
175 tSpiderObject *Object, const char *MethodName,
176 int NArguments, tSpiderValue **Arguments)
178 tSpiderFunction *fcn;
180 tSpiderValue *newargs[NArguments+1];
183 // TODO: Support program defined objects
185 // Search for the function
186 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
188 if( strcmp(fcn->Name, MethodName) == 0 )
194 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
195 Object->Type->Name, MethodName);
199 // Create the "this" argument
200 this.Type = SS_DATATYPE_OBJECT;
201 this.ReferenceCount = 1;
202 this.Object = Object;
204 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
206 // Check the type of the arguments
207 for( i = 0; fcn->ArgTypes[i]; i ++ )
209 if( i >= NArguments ) {
210 for( ; fcn->ArgTypes[i]; i ++ ) ;
211 AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
215 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
217 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
218 Arguments[i]->Type, fcn->ArgTypes[i]);
224 return fcn->Handler(Script, NArguments+1, newargs);
228 * \brief Execute a script function
229 * \param Script Script context to execute in
230 * \param Function Function name to execute
231 * \param NArguments Number of arguments to pass
232 * \param Arguments Arguments passed
234 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
235 tSpiderNamespace *Namespace, const char *ClassName,
236 int NArguments, tSpiderValue **Arguments)
238 int bFound = 0; // Used to keep nesting levels down
239 tSpiderValue *ret = ERRPTR;
240 tSpiderObjectDef *class;
242 // First: Find the function in the script
243 // TODO: Implement script-defined classes
246 tAST_Function *astClass;
247 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
249 if( strcmp(astClass->Name, ClassName) == 0 )
259 // Build a block State
263 bs.BaseNamespace = &Script->Variant->RootNamespace;
264 bs.CurNamespace = NULL;
266 bs.Ident = giNextBlockIdent ++;
268 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
270 if( i >= NArguments ) break; // TODO: Return gracefully
273 arg->DefVar.DataType, arg->DefVar.Name,
278 ret = AST_ExecuteNode(&bs, astFcn->Code);
281 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
282 ret = bs.RetVal; // Set to return value of block
288 tAST_Variable *nextVar = bs.FirstVar->Next;
289 Variable_Destroy( bs.FirstVar );
290 bs.FirstVar = nextVar;
296 // Didn't find it in script?
299 class = NULL; // Just to allow the below code to be neat
302 // Namespace = &Script->Variant->RootNamespace;
304 // Second: Scan current namespace
305 if( !class && Namespace )
307 for( class = Namespace->Classes; class; class = class->Next )
309 if( strcmp( class->Name, ClassName ) == 0 )
315 // Third: Search the variant's global exports
318 for( class = Script->Variant->Classes; class; class = fcn->Next )
320 if( strcmp( class->Name, Function ) == 0 )
327 // Fourth: Search language exports
330 for( class = gpExports_First; class; class = fcn->Next )
332 if( strcmp( class->Name, ClassName ) == 0 )
342 // TODO: Type Checking
345 obj = class->Constructor( NArguments, Arguments );
346 if( obj == NULL || obj == ERRPTR )
349 // Creatue return object
350 ret = malloc( sizeof(tSpiderValue) );
351 ret->Type = SS_DATATYPE_OBJECT;
352 ret->ReferenceCount = 1;
361 fprintf(stderr, "Undefined reference to class '%s'\n", ClassName);
370 * \brief Execute an AST node and return its value
371 * \param Block Execution context
372 * \param Node Node to execute
374 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
377 tSpiderValue *ret = NULL, *tmpobj;
378 tSpiderValue *op1, *op2; // Binary operations
379 int cmp; // Used in comparisons
392 tAST_BlockState blockInfo;
393 blockInfo.Parent = Block;
394 blockInfo.Script = Block->Script;
395 blockInfo.FirstVar = NULL;
396 blockInfo.RetVal = NULL;
397 blockInfo.BaseNamespace = Block->BaseNamespace;
398 blockInfo.CurNamespace = NULL;
399 blockInfo.BreakTarget = NULL;
400 blockInfo.Ident = giNextBlockIdent ++;
402 // Loop over all nodes, or until the return value is set
403 for(node = Node->Block.FirstChild;
404 node && !blockInfo.RetVal && !blockInfo.BreakTarget;
405 node = node->NextSibling )
407 ret = AST_ExecuteNode(&blockInfo, node);
408 if(ret == ERRPTR) break; // Error check
409 if(ret != NULL) SpiderScript_DereferenceValue(ret); // Free unused value
411 // Clean up variables
412 while(blockInfo.FirstVar)
414 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
415 Variable_Destroy( blockInfo.FirstVar );
416 blockInfo.FirstVar = nextVar;
418 // Clear ret if not an error
419 if(ret != ERRPTR) ret = NULL;
421 // Set parent's return value if needed
422 if( blockInfo.RetVal )
423 Block->RetVal = blockInfo.RetVal;
424 if( blockInfo.BreakTarget ) {
425 Block->BreakTarget = blockInfo.BreakTarget;
426 Block->BreakType = blockInfo.BreakType;
429 // TODO: Unset break if break type deontes a block break
435 case NODETYPE_ASSIGN:
436 // TODO: Support assigning to object attributes
437 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
438 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
441 ret = AST_ExecuteNode(Block, Node->Assign.Value);
442 if(ret == ERRPTR) return ERRPTR;
444 // Perform assignment operation
445 if( Node->Assign.Operation != NODETYPE_NOP )
447 tSpiderValue *varVal, *value;
449 varVal = Variable_GetValue(Block, Node->Assign.Dest);
450 if(varVal == ERRPTR) return ERRPTR;
453 if(varVal && varVal->ReferenceCount == 2) {
454 SpiderScript_DereferenceValue(varVal);
455 // printf("pre: (%s) varVal->ReferenceCount = %i\n",
456 // Node->Assign.Dest->Variable.Name,
457 // varVal->ReferenceCount);
460 value = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Assign.Operation, varVal, ret);
461 if(value == ERRPTR) return ERRPTR;
463 if(ret) SpiderScript_DereferenceValue(ret);
465 if(varVal) SpiderScript_DereferenceValue(varVal);
467 if(varVal && varVal->ReferenceCount == 1) {
468 SpiderScript_ReferenceValue(varVal);
469 // printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
470 break; // If varVal was non-null, it has been updated by _BinOp
473 // Else, it was NULL, so has to be assigned
477 // Set the variable value
478 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
479 SpiderScript_DereferenceValue( ret );
484 // Post increment/decrement
485 case NODETYPE_POSTINC:
486 case NODETYPE_POSTDEC:
488 tSpiderValue *varVal, *value;
489 static tSpiderValue one = {
490 .Type = SS_DATATYPE_INTEGER,
495 // TODO: Support assigning to object attributes
496 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
497 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
501 // Get values (current variable contents and a static one)
502 varVal = Variable_GetValue(Block, Node->UniOp.Value);
504 if( Node->Type == NODETYPE_POSTDEC )
505 value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_SUBTRACT, varVal, &one);
507 value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_ADD, varVal, &one);
508 if( value == ERRPTR )
513 if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
514 SpiderScript_DereferenceValue( ret );
517 SpiderScript_DereferenceValue( value );
522 case NODETYPE_METHODCALL:
523 case NODETYPE_FUNCTIONCALL:
524 case NODETYPE_CREATEOBJECT:
525 // Logical block (used to allocate `params`)
527 tSpiderNamespace *ns = Block->CurNamespace;
528 tSpiderValue *params[Node->FunctionCall.NumArgs];
530 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
532 params[i] = AST_ExecuteNode(Block, node);
533 if( params[i] == ERRPTR ) {
534 while(i--) SpiderScript_DereferenceValue(params[i]);
541 if( !ns ) ns = Block->BaseNamespace;
544 if( Node->Type == NODETYPE_CREATEOBJECT )
546 ret = SpiderScript_CreateObject(Block->Script,
548 Node->FunctionCall.Name,
549 Node->FunctionCall.NumArgs, params
552 else if( Node->Type == NODETYPE_METHODCALL )
554 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
555 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
556 AST_RuntimeError(Node->FunctionCall.Object,
557 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
558 while(i--) SpiderScript_DereferenceValue(params[i]);
562 ret = SpiderScript_ExecuteMethod(Block->Script,
563 obj->Object, Node->FunctionCall.Name,
564 Node->FunctionCall.NumArgs, params
566 SpiderScript_DereferenceValue(obj);
570 ret = SpiderScript_ExecuteFunction(Block->Script,
571 ns, Node->FunctionCall.Name,
572 Node->FunctionCall.NumArgs, params
577 // Dereference parameters
578 while(i--) SpiderScript_DereferenceValue(params[i]);
586 ret = AST_ExecuteNode(Block, Node->If.Condition);
587 if( ret == ERRPTR ) break;
588 if( SpiderScript_IsValueTrue(ret) ) {
589 tmpobj = AST_ExecuteNode(Block, Node->If.True);
592 tmpobj = AST_ExecuteNode(Block, Node->If.False);
594 SpiderScript_DereferenceValue(ret);
595 if( tmpobj == ERRPTR ) return ERRPTR;
596 SpiderScript_DereferenceValue(tmpobj);
603 ret = AST_ExecuteNode(Block, Node->For.Init);
604 if(ret == ERRPTR) break;
606 // Check initial condition
607 if( !Node->For.bCheckAfter )
609 SpiderScript_DereferenceValue(ret);
611 ret = AST_ExecuteNode(Block, Node->For.Condition);
612 if(ret == ERRPTR) return ERRPTR;
613 if(!SpiderScript_IsValueTrue(ret)) {
614 SpiderScript_DereferenceValue(ret);
623 SpiderScript_DereferenceValue(ret);
626 ret = AST_ExecuteNode(Block, Node->For.Code);
627 if(ret == ERRPTR) return ERRPTR;
628 SpiderScript_DereferenceValue(ret);
630 if(Block->BreakTarget)
632 if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
635 free((void*)Block->BreakTarget); Block->BreakTarget = NULL;
636 if( Block->BreakType == NODETYPE_CONTINUE ) {
637 // Continue, just keep going
643 break; // Break out of this loop
647 ret = AST_ExecuteNode(Block, Node->For.Increment);
648 if(ret == ERRPTR) return ERRPTR;
649 SpiderScript_DereferenceValue(ret);
652 ret = AST_ExecuteNode(Block, Node->For.Condition);
653 if(ret == ERRPTR) return ERRPTR;
654 if(!SpiderScript_IsValueTrue(ret)) break;
656 SpiderScript_DereferenceValue(ret);
661 case NODETYPE_RETURN:
662 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
663 if(ret == ERRPTR) break;
664 Block->RetVal = ret; // Return value set
665 ret = NULL; // the `return` statement does not return a value
669 case NODETYPE_CONTINUE:
670 Block->BreakTarget = strdup(Node->Variable.Name);
671 Block->BreakType = Node->Type;
675 case NODETYPE_DEFVAR:
676 if( Node->DefVar.InitialValue ) {
677 tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
678 if(tmpobj == ERRPTR) return ERRPTR;
683 // TODO: Handle arrays
685 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
687 SpiderScript_DereferenceValue(tmpobj);
693 tSpiderNamespace *ns;
695 // Set current namespace if unset
696 if( !Block->CurNamespace )
697 Block->CurNamespace = Block->BaseNamespace;
699 // Empty string means use the root namespace
700 if( Node->Scope.Name[0] == '\0' )
702 ns = &Block->Script->Variant->RootNamespace;
706 // Otherwise scan the current namespace for the element
707 for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
709 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
714 AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
718 Block->CurNamespace = ns;
720 ret = AST_ExecuteNode(Block, Node->Scope.Element);
725 case NODETYPE_VARIABLE:
726 ret = Variable_GetValue( Block, Node );
729 // Element of an Object
730 case NODETYPE_ELEMENT:
731 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
732 if(tmpobj == ERRPTR) return ERRPTR;
733 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
735 AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
740 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
742 if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
744 ret = tmpobj->Object->Attributes[i];
745 SpiderScript_ReferenceValue(ret);
749 if( i == tmpobj->Object->Type->NAttributes )
751 AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
752 Node->Scope.Name, tmpobj->Object->Type->Name);
757 // Cast a value to another
760 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
761 if(tmpobj == ERRPTR) return ERRPTR;
762 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
763 SpiderScript_DereferenceValue(tmpobj);
767 // Index into an array
769 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
770 if(op1 == ERRPTR) return ERRPTR;
771 op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
773 SpiderScript_DereferenceValue(op1);
777 if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
779 // TODO: Implement "operator []" on objects
780 AST_RuntimeError(Node, "Indexing non-array");
785 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
786 AST_RuntimeError(Node, "Array index is not an integer");
791 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
793 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
794 SpiderScript_DereferenceValue(op2);
798 if( op2->Integer >= op1->Array.Length ) {
799 AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
800 op2->Integer, op1->Array.Length);
805 ret = op1->Array.Items[ op2->Integer ];
806 SpiderScript_ReferenceValue(ret);
808 SpiderScript_DereferenceValue(op1);
809 SpiderScript_DereferenceValue(op2);
812 // TODO: Implement runtime constants
813 case NODETYPE_CONSTANT:
814 // TODO: Scan namespace for constant name
815 AST_RuntimeError(Node, "TODO - Runtime Constants");
820 case NODETYPE_STRING:
821 case NODETYPE_INTEGER:
823 ret = &Node->Constant;
824 SpiderScript_ReferenceValue(ret);
827 // --- Operations ---
828 // Boolean Operations
829 case NODETYPE_LOGICALNOT: // Logical NOT (!)
830 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
831 if(op1 == ERRPTR) return ERRPTR;
832 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
833 SpiderScript_DereferenceValue(op1);
835 case NODETYPE_LOGICALAND: // Logical AND (&&)
836 case NODETYPE_LOGICALOR: // Logical OR (||)
837 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
838 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
839 if(op1 == ERRPTR) return ERRPTR;
840 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
842 SpiderScript_DereferenceValue(op1);
848 case NODETYPE_LOGICALAND:
849 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
851 case NODETYPE_LOGICALOR:
852 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
854 case NODETYPE_LOGICALXOR:
855 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
860 // Free intermediate objects
861 SpiderScript_DereferenceValue(op1);
862 SpiderScript_DereferenceValue(op2);
866 case NODETYPE_EQUALS:
867 case NODETYPE_LESSTHAN:
868 case NODETYPE_GREATERTHAN:
869 case NODETYPE_LESSTHANEQUAL:
870 case NODETYPE_GREATERTHANEQUAL:
871 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
872 if(op1 == ERRPTR) return ERRPTR;
873 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
875 SpiderScript_DereferenceValue(op1);
881 AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
882 if(op1) SpiderScript_DereferenceValue(op1);
883 if(op2) SpiderScript_DereferenceValue(op2);
884 ret = SpiderScript_CreateInteger( !op1 && !op2 );
889 if( op1->Type != op2->Type ) {
890 // If dynamically typed, convert op2 to op1's type
891 if(Block->Script->Variant->bImplicitCasts)
894 op2 = SpiderScript_CastValueTo(op1->Type, op2);
895 SpiderScript_DereferenceValue(tmpobj);
897 SpiderScript_DereferenceValue(op1);
901 // If statically typed, this should never happen, but catch it anyway
903 AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
904 op1->Type, op2->Type);
912 // - String Compare (does a strcmp, well memcmp)
913 case SS_DATATYPE_STRING:
914 // Call memcmp to do most of the work
916 op1->String.Data, op2->String.Data,
917 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
919 // Handle reaching the end of the string
921 if( op1->String.Length == op2->String.Length )
923 else if( op1->String.Length < op2->String.Length )
930 // - Integer Comparisons
931 case SS_DATATYPE_INTEGER:
932 if( op1->Integer == op2->Integer )
934 else if( op1->Integer < op2->Integer )
939 // - Real Number Comparisons
940 case SS_DATATYPE_REAL:
941 cmp = (op1->Real - op2->Real) / op2->Real * 10000; // < 0.1% difference is equality
944 AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
949 // Free intermediate objects
950 SpiderScript_DereferenceValue(op1);
951 SpiderScript_DereferenceValue(op2);
960 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
961 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
962 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
963 case NODETYPE_LESSTHANEQUAL: ret = SpiderScript_CreateInteger(cmp <= 0); break;
964 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0); break;
966 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
972 // General Unary Operations
973 case NODETYPE_BWNOT: // Bitwise NOT (~)
974 case NODETYPE_NEGATE: // Negation (-)
975 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
976 if(op1 == ERRPTR) return ERRPTR;
977 ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
978 SpiderScript_DereferenceValue(op1);
981 // General Binary Operations
983 case NODETYPE_SUBTRACT:
984 case NODETYPE_MULTIPLY:
985 case NODETYPE_DIVIDE:
986 case NODETYPE_MODULO:
990 case NODETYPE_BITSHIFTLEFT:
991 case NODETYPE_BITSHIFTRIGHT:
992 case NODETYPE_BITROTATELEFT:
994 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
995 if(op1 == ERRPTR) return ERRPTR;
996 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
998 SpiderScript_DereferenceValue(op1);
1002 ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
1004 // Free intermediate objects
1005 SpiderScript_DereferenceValue(op1);
1006 SpiderScript_DereferenceValue(op2);
1011 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
1015 // Reset namespace when no longer needed
1016 if( Node->Type != NODETYPE_SCOPE )
1017 Block->CurNamespace = NULL;
1019 #if TRACE_NODE_RETURNS
1020 if(ret && ret != ERRPTR) {
1021 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
1024 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
1031 tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
1035 if( Value->Type == SS_DATATYPE_OBJECT )
1037 const char *fcnname;
1040 case NODETYPE_NEGATE: fcnname = "-ve"; break;
1041 case NODETYPE_BWNOT: fcnname = "~"; break;
1042 default: fcnname = NULL; break;
1047 ret = Object_ExecuteMethod(Value->Object, fcnname, );
1055 // Integer Operations
1056 case SS_DATATYPE_INTEGER:
1057 if( Value->ReferenceCount == 1 )
1058 SpiderScript_ReferenceValue(ret = Value);
1060 ret = SpiderScript_CreateInteger(0);
1063 case NODETYPE_NEGATE: ret->Integer = -Value->Integer; break;
1064 case NODETYPE_BWNOT: ret->Integer = ~Value->Integer; break;
1066 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1067 SpiderScript_DereferenceValue(ret);
1072 // Real number Operations
1073 case SS_DATATYPE_REAL:
1076 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
1078 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1085 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1093 tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1095 tSpiderValue *preCastValue = Right;
1099 if( Left && Right && Left->Type != Right->Type )
1103 // - Operator overload functions
1104 if( Left->Type == SS_DATATYPE_OBJECT )
1106 const char *fcnname;
1109 case NODETYPE_ADD: fcnname = "+"; break;
1110 case NODETYPE_SUBTRACT: fcnname = "-"; break;
1111 case NODETYPE_MULTIPLY: fcnname = "*"; break;
1112 case NODETYPE_DIVIDE: fcnname = "/"; break;
1113 case NODETYPE_MODULO: fcnname = "%"; break;
1114 case NODETYPE_BWAND: fcnname = "&"; break;
1115 case NODETYPE_BWOR: fcnname = "|"; break;
1116 case NODETYPE_BWXOR: fcnname = "^"; break;
1117 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
1118 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
1119 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
1120 default: fcnname = NULL; break;
1125 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1128 // Fall through and try casting (which will usually fail)
1133 // If implicit casts are allowed, convert Right to Left's type
1134 if(Script->Variant->bImplicitCasts)
1136 Right = SpiderScript_CastValueTo(Left->Type, Right);
1140 // If statically typed, this should never happen, but catch it anyway
1142 AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
1148 if( Left == NULL || Right == NULL ) {
1149 if(Right && Right != preCastValue) free(Right);
1156 // String Concatenation
1157 case SS_DATATYPE_STRING:
1160 case NODETYPE_ADD: // Concatenate
1161 ret = SpiderScript_StringConcat(Left, Right);
1163 // TODO: Support python style 'i = %i' % i ?
1164 // Might do it via a function call
1165 // Implement it via % with an array, but getting past the cast will be fun
1166 // case NODETYPE_MODULUS:
1168 // TODO: Support string repititions
1169 // case NODETYPE_MULTIPLY:
1173 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1178 // Integer Operations
1179 case SS_DATATYPE_INTEGER:
1180 if( Left->ReferenceCount == 1 )
1181 SpiderScript_ReferenceValue(ret = Left);
1183 ret = SpiderScript_CreateInteger(0);
1186 case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
1187 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
1188 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
1189 case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
1190 case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
1191 case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
1192 case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
1193 case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
1194 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
1195 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
1196 case NODETYPE_BITROTATELEFT:
1197 ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
1200 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
1201 SpiderScript_DereferenceValue(ret);
1208 case SS_DATATYPE_REAL:
1209 if( Left->ReferenceCount == 1 )
1210 SpiderScript_ReferenceValue(ret = Left);
1212 ret = SpiderScript_CreateReal(0);
1215 case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
1216 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
1217 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
1218 case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
1220 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1221 SpiderScript_DereferenceValue(ret);
1228 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1233 if(Right && Right != preCastValue) free(Right);
1239 * \brief Define a variable
1240 * \param Block Current block state
1241 * \param Type Type of the variable
1242 * \param Name Name of the variable
1243 * \return Boolean Failure
1245 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1247 tAST_Variable *var, *prev = NULL;
1249 for( var = Block->FirstVar; var; prev = var, var = var->Next )
1251 if( strcmp(var->Name, Name) == 0 ) {
1252 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1257 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1260 var->Object = Value;
1261 if(Value) SpiderScript_ReferenceValue(Value);
1262 strcpy(var->Name, Name);
1264 if(prev) prev->Next = var;
1265 else Block->FirstVar = var;
1267 //printf("Defined variable %s (%i)\n", Name, Type);
1272 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1274 tAST_Variable *var = NULL;
1277 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1278 var = VarNode->ValueCache;
1279 #if TRACE_VAR_LOOKUPS
1280 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1281 VarNode->Variable.Name, var,
1282 VarNode->BlockState, VarNode->BlockIdent
1288 tAST_BlockState *bs;
1289 for( bs = Block; bs; bs = bs->Parent )
1291 for( var = bs->FirstVar; var; var = var->Next )
1293 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1301 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1303 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1307 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1312 #if TRACE_VAR_LOOKUPS
1313 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1314 VarNode->Variable.Name, var,
1315 Block, Block->Ident);
1318 VarNode->ValueCache = var;
1319 VarNode->BlockState = Block;
1320 VarNode->BlockIdent = Block->Ident;
1327 * \brief Set the value of a variable
1328 * \return Boolean Failure
1330 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1334 var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1336 if( !var ) return -1;
1338 if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1340 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1341 VarNode->Variable.Name);
1345 // printf("Assign %p to '%s'\n", Value, var->Name);
1346 SpiderScript_ReferenceValue(Value);
1347 SpiderScript_DereferenceValue(var->Object);
1348 var->Object = Value;
1353 * \brief Get the value of a variable
1355 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1357 tAST_Variable *var = Variable_Lookup(Block, VarNode, 0);
1359 if( !var ) return ERRPTR;
1361 SpiderScript_ReferenceValue(var->Object);
1366 * \brief Destorys a variable
1368 void Variable_Destroy(tAST_Variable *Variable)
1370 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1371 SpiderScript_DereferenceValue(Variable->Object);
1375 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
1380 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1382 fprintf(stderr, "%s: ", Type);
1383 va_start(args, Format);
1384 vfprintf(stderr, Format, args);
1386 fprintf(stderr, "\n");
1388 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1393 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1395 fprintf(stderr, "error: ");
1396 va_start(args, Format);
1397 vfprintf(stderr, Format, args);
1399 fprintf(stderr, "\n");