12 #define TRACE_VAR_LOOKUPS 0
13 #define TRACE_NODE_RETURNS 0
16 extern tSpiderFunction *gpExports_First;
20 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
21 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
22 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value);
24 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
25 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
26 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
27 void Variable_Destroy(tAST_Variable *Variable);
29 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
30 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
33 int giNextBlockIdent = 1;
37 * \brief Execute a script function
38 * \param Script Script context to execute in
39 * \param Namespace Namespace to search for the function
40 * \param Function Function name to execute
41 * \param NArguments Number of arguments to pass
42 * \param Arguments Arguments passed
44 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
45 tSpiderNamespace *Namespace, const char *Function,
46 int NArguments, tSpiderValue **Arguments)
48 int bFound = 0; // Used to keep nesting levels down
49 tSpiderValue *ret = ERRPTR;
52 // First: Find the function in the script
54 tAST_Function *astFcn;
55 for( astFcn = Script->Script->Functions; astFcn; astFcn = astFcn->Next )
57 if( strcmp(astFcn->Name, Function) == 0 )
67 // Build a block State
71 bs.BaseNamespace = &Script->Variant->RootNamespace;
72 bs.CurNamespace = NULL;
74 bs.Ident = giNextBlockIdent ++;
77 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
79 if( i >= NArguments ) break; // TODO: Return gracefully
82 arg->DefVar.DataType, arg->DefVar.Name,
87 ret = AST_ExecuteNode(&bs, astFcn->Code);
90 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
91 ret = bs.RetVal; // Set to return value of block
97 tAST_Variable *nextVar = bs.FirstVar->Next;
98 Variable_Destroy( bs.FirstVar );
99 bs.FirstVar = nextVar;
104 // Didn't find it in script?
107 fcn = NULL; // Just to allow the below code to be neat
109 // Second: Scan current namespace
110 if( !fcn && Namespace )
112 for( fcn = Namespace->Functions; fcn; fcn = fcn->Next )
114 if( strcmp( fcn->Name, Function ) == 0 )
119 // Third: Search the variant's global exports
122 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
124 if( strcmp( fcn->Name, Function ) == 0 )
129 // Fourth: Search language exports
132 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
134 if( strcmp( fcn->Name, Function ) == 0 )
142 // TODO: Type Checking
143 ret = fcn->Handler( Script, NArguments, Arguments );
151 fprintf(stderr, "Undefined reference to function '%s' (ns='%s')\n",
152 Function, Namespace->Name);
160 * \brief Execute an object method function
161 * \param Script Script context to execute in
162 * \param Object Object in which to find the method
163 * \param MethodName Name of method to call
164 * \param NArguments Number of arguments to pass
165 * \param Arguments Arguments passed
167 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
168 tSpiderObject *Object, const char *MethodName,
169 int NArguments, tSpiderValue **Arguments)
171 tSpiderFunction *fcn;
173 tSpiderValue *newargs[NArguments+1];
176 // TODO: Support program defined objects
178 // Search for the function
179 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
181 if( strcmp(fcn->Name, MethodName) == 0 )
187 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
188 Object->Type->Name, MethodName);
192 // Create the "this" argument
193 this.Type = SS_DATATYPE_OBJECT;
194 this.ReferenceCount = 1;
195 this.Object = Object;
197 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
199 // Check the type of the arguments
200 for( i = 0; fcn->ArgTypes[i]; i ++ )
202 if( i >= NArguments ) {
203 for( ; fcn->ArgTypes[i]; i ++ ) ;
204 AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
208 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
210 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
211 Arguments[i]->Type, fcn->ArgTypes[i]);
217 return fcn->Handler(Script, NArguments+1, newargs);
221 * \brief Execute a script function
222 * \param Script Script context to execute in
223 * \param Function Function name to execute
224 * \param NArguments Number of arguments to pass
225 * \param Arguments Arguments passed
227 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
228 tSpiderNamespace *Namespace, const char *ClassName,
229 int NArguments, tSpiderValue **Arguments)
231 int bFound = 0; // Used to keep nesting levels down
232 tSpiderValue *ret = ERRPTR;
233 tSpiderObjectDef *class;
235 // First: Find the function in the script
236 // TODO: Implement script-defined classes
239 tAST_Function *astClass;
240 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
242 if( strcmp(astClass->Name, ClassName) == 0 )
252 // Build a block State
256 bs.BaseNamespace = &Script->Variant->RootNamespace;
257 bs.CurNamespace = NULL;
259 bs.Ident = giNextBlockIdent ++;
261 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
263 if( i >= NArguments ) break; // TODO: Return gracefully
266 arg->DefVar.DataType, arg->DefVar.Name,
271 ret = AST_ExecuteNode(&bs, astFcn->Code);
274 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
275 ret = bs.RetVal; // Set to return value of block
281 tAST_Variable *nextVar = bs.FirstVar->Next;
282 Variable_Destroy( bs.FirstVar );
283 bs.FirstVar = nextVar;
289 // Didn't find it in script?
292 class = NULL; // Just to allow the below code to be neat
295 // Namespace = &Script->Variant->RootNamespace;
297 // Second: Scan current namespace
298 if( !class && Namespace )
300 for( class = Namespace->Classes; class; class = class->Next )
302 if( strcmp( class->Name, ClassName ) == 0 )
308 // Third: Search the variant's global exports
311 for( class = Script->Variant->Classes; class; class = fcn->Next )
313 if( strcmp( class->Name, Function ) == 0 )
320 // Fourth: Search language exports
323 for( class = gpExports_First; class; class = fcn->Next )
325 if( strcmp( class->Name, ClassName ) == 0 )
335 // TODO: Type Checking
338 obj = class->Constructor( NArguments, Arguments );
339 if( obj == NULL || obj == ERRPTR )
342 // Creatue return object
343 ret = malloc( sizeof(tSpiderValue) );
344 ret->Type = SS_DATATYPE_OBJECT;
345 ret->ReferenceCount = 1;
354 fprintf(stderr, "Undefined reference to class '%s'\n", ClassName);
363 * \brief Execute an AST node and return its value
364 * \param Block Execution context
365 * \param Node Node to execute
367 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
370 tSpiderValue *ret = NULL, *tmpobj;
371 tSpiderValue *op1, *op2; // Binary operations
372 int cmp; // Used in comparisons
385 tAST_BlockState blockInfo;
386 blockInfo.Parent = Block;
387 blockInfo.Script = Block->Script;
388 blockInfo.FirstVar = NULL;
389 blockInfo.RetVal = NULL;
390 blockInfo.BaseNamespace = Block->BaseNamespace;
391 blockInfo.CurNamespace = NULL;
392 blockInfo.BreakTarget = NULL;
393 blockInfo.Ident = giNextBlockIdent ++;
395 // Loop over all nodes, or until the return value is set
396 for(node = Node->Block.FirstChild;
397 node && !blockInfo.RetVal && !blockInfo.BreakTarget;
398 node = node->NextSibling )
400 ret = AST_ExecuteNode(&blockInfo, node);
401 if(ret == ERRPTR) break; // Error check
402 if(ret != NULL) SpiderScript_DereferenceValue(ret); // Free unused value
404 // Clean up variables
405 while(blockInfo.FirstVar)
407 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
408 Variable_Destroy( blockInfo.FirstVar );
409 blockInfo.FirstVar = nextVar;
411 // Clear ret if not an error
412 if(ret != ERRPTR) ret = NULL;
414 // Set parent's return value if needed
415 if( blockInfo.RetVal )
416 Block->RetVal = blockInfo.RetVal;
417 if( blockInfo.BreakTarget ) {
418 Block->BreakTarget = blockInfo.BreakTarget;
419 Block->BreakType = blockInfo.BreakType;
422 // TODO: Unset break if break type deontes a block break
428 case NODETYPE_ASSIGN:
429 // TODO: Support assigning to object attributes
430 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
431 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
434 ret = AST_ExecuteNode(Block, Node->Assign.Value);
435 if(ret == ERRPTR) return ERRPTR;
437 // Perform assignment operation
438 if( Node->Assign.Operation != NODETYPE_NOP )
440 tSpiderValue *varVal, *value;
442 varVal = Variable_GetValue(Block, Node->Assign.Dest);
443 if(varVal == ERRPTR) return ERRPTR;
446 if(varVal && varVal->ReferenceCount == 2) {
447 SpiderScript_DereferenceValue(varVal);
448 // printf("pre: (%s) varVal->ReferenceCount = %i\n",
449 // Node->Assign.Dest->Variable.Name,
450 // varVal->ReferenceCount);
453 value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
454 if(value == ERRPTR) return ERRPTR;
456 if(ret) SpiderScript_DereferenceValue(ret);
458 if(varVal) SpiderScript_DereferenceValue(varVal);
460 if(varVal && varVal->ReferenceCount == 1) {
461 SpiderScript_ReferenceValue(varVal);
462 // printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
463 break; // If varVal was non-null, it has been updated by _BinOp
466 // Else, it was NULL, so has to be assigned
470 // Set the variable value
471 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
472 SpiderScript_DereferenceValue( ret );
477 // Post increment/decrement
478 case NODETYPE_POSTINC:
479 case NODETYPE_POSTDEC:
481 tSpiderValue *varVal, *value;
482 static tSpiderValue one = {
483 .Type = SS_DATATYPE_INTEGER,
488 // TODO: Support assigning to object attributes
489 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
490 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
494 // Get values (current variable contents and a static one)
495 varVal = Variable_GetValue(Block, Node->UniOp.Value);
497 if( Node->Type == NODETYPE_POSTDEC )
498 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_SUBTRACT, varVal, &one);
500 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_ADD, varVal, &one);
501 if( value == ERRPTR )
506 if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
507 SpiderScript_DereferenceValue( ret );
510 SpiderScript_DereferenceValue( value );
515 case NODETYPE_METHODCALL:
516 case NODETYPE_FUNCTIONCALL:
517 case NODETYPE_CREATEOBJECT:
518 // Logical block (used to allocate `params`)
520 tSpiderNamespace *ns = Block->CurNamespace;
521 tSpiderValue *params[Node->FunctionCall.NumArgs];
523 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
525 params[i] = AST_ExecuteNode(Block, node);
526 if( params[i] == ERRPTR ) {
527 while(i--) SpiderScript_DereferenceValue(params[i]);
534 if( !ns ) ns = Block->BaseNamespace;
537 if( Node->Type == NODETYPE_CREATEOBJECT )
539 ret = SpiderScript_CreateObject(Block->Script,
541 Node->FunctionCall.Name,
542 Node->FunctionCall.NumArgs, params
545 else if( Node->Type == NODETYPE_METHODCALL )
547 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
548 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
549 AST_RuntimeError(Node->FunctionCall.Object,
550 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
551 while(i--) SpiderScript_DereferenceValue(params[i]);
555 ret = SpiderScript_ExecuteMethod(Block->Script,
556 obj->Object, Node->FunctionCall.Name,
557 Node->FunctionCall.NumArgs, params
559 SpiderScript_DereferenceValue(obj);
563 ret = SpiderScript_ExecuteFunction(Block->Script,
564 ns, Node->FunctionCall.Name,
565 Node->FunctionCall.NumArgs, params
570 // Dereference parameters
571 while(i--) SpiderScript_DereferenceValue(params[i]);
579 ret = AST_ExecuteNode(Block, Node->If.Condition);
580 if( ret == ERRPTR ) break;
581 if( SpiderScript_IsValueTrue(ret) ) {
582 tmpobj = AST_ExecuteNode(Block, Node->If.True);
585 tmpobj = AST_ExecuteNode(Block, Node->If.False);
587 SpiderScript_DereferenceValue(ret);
588 if( tmpobj == ERRPTR ) return ERRPTR;
589 SpiderScript_DereferenceValue(tmpobj);
596 ret = AST_ExecuteNode(Block, Node->For.Init);
597 if(ret == ERRPTR) break;
599 // Check initial condition
600 if( !Node->For.bCheckAfter )
602 SpiderScript_DereferenceValue(ret);
604 ret = AST_ExecuteNode(Block, Node->For.Condition);
605 if(ret == ERRPTR) return ERRPTR;
606 if(!SpiderScript_IsValueTrue(ret)) {
607 SpiderScript_DereferenceValue(ret);
616 SpiderScript_DereferenceValue(ret);
619 ret = AST_ExecuteNode(Block, Node->For.Code);
620 if(ret == ERRPTR) return ERRPTR;
621 SpiderScript_DereferenceValue(ret);
623 if(Block->BreakTarget)
625 if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
628 free((void*)Block->BreakTarget); Block->BreakTarget = NULL;
629 if( Block->BreakType == NODETYPE_CONTINUE ) {
630 // Continue, just keep going
636 break; // Break out of this loop
640 ret = AST_ExecuteNode(Block, Node->For.Increment);
641 if(ret == ERRPTR) return ERRPTR;
642 SpiderScript_DereferenceValue(ret);
645 ret = AST_ExecuteNode(Block, Node->For.Condition);
646 if(ret == ERRPTR) return ERRPTR;
647 if(!SpiderScript_IsValueTrue(ret)) break;
649 SpiderScript_DereferenceValue(ret);
654 case NODETYPE_RETURN:
655 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
656 if(ret == ERRPTR) break;
657 Block->RetVal = ret; // Return value set
658 ret = NULL; // the `return` statement does not return a value
662 case NODETYPE_CONTINUE:
663 Block->BreakTarget = strdup(Node->Variable.Name);
664 Block->BreakType = Node->Type;
668 case NODETYPE_DEFVAR:
669 if( Node->DefVar.InitialValue ) {
670 tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
671 if(tmpobj == ERRPTR) return ERRPTR;
676 // TODO: Handle arrays
678 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
680 SpiderScript_DereferenceValue(tmpobj);
686 tSpiderNamespace *ns;
688 // Set current namespace if unset
689 if( !Block->CurNamespace )
690 Block->CurNamespace = Block->BaseNamespace;
692 // Empty string means use the root namespace
693 if( Node->Scope.Name[0] == '\0' )
695 ns = &Block->Script->Variant->RootNamespace;
699 // Otherwise scan the current namespace for the element
700 for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
702 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
707 AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
711 Block->CurNamespace = ns;
713 ret = AST_ExecuteNode(Block, Node->Scope.Element);
718 case NODETYPE_VARIABLE:
719 ret = Variable_GetValue( Block, Node );
722 // Element of an Object
723 case NODETYPE_ELEMENT:
724 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
725 if(tmpobj == ERRPTR) return ERRPTR;
726 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
728 AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
733 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
735 if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
737 ret = tmpobj->Object->Attributes[i];
738 SpiderScript_ReferenceValue(ret);
742 if( i == tmpobj->Object->Type->NAttributes )
744 AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
745 Node->Scope.Name, tmpobj->Object->Type->Name);
750 // Cast a value to another
753 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
754 if(tmpobj == ERRPTR) return ERRPTR;
755 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
756 SpiderScript_DereferenceValue(tmpobj);
760 // Index into an array
762 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
763 if(op1 == ERRPTR) return ERRPTR;
764 op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
766 SpiderScript_DereferenceValue(op1);
770 if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
772 // TODO: Implement "operator []" on objects
773 AST_RuntimeError(Node, "Indexing non-array");
778 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
779 AST_RuntimeError(Node, "Array index is not an integer");
784 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
786 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
787 SpiderScript_DereferenceValue(op2);
791 if( op2->Integer >= op1->Array.Length ) {
792 AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
793 op2->Integer, op1->Array.Length);
798 ret = op1->Array.Items[ op2->Integer ];
799 SpiderScript_ReferenceValue(ret);
801 SpiderScript_DereferenceValue(op1);
802 SpiderScript_DereferenceValue(op2);
805 // TODO: Implement runtime constants
806 case NODETYPE_CONSTANT:
807 // TODO: Scan namespace for constant name
808 AST_RuntimeError(Node, "TODO - Runtime Constants");
813 case NODETYPE_STRING:
814 case NODETYPE_INTEGER:
816 ret = &Node->Constant;
817 SpiderScript_ReferenceValue(ret);
820 // --- Operations ---
821 // Boolean Operations
822 case NODETYPE_LOGICALNOT: // Logical NOT (!)
823 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
824 if(op1 == ERRPTR) return ERRPTR;
825 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
826 SpiderScript_DereferenceValue(op1);
828 case NODETYPE_LOGICALAND: // Logical AND (&&)
829 case NODETYPE_LOGICALOR: // Logical OR (||)
830 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
831 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
832 if(op1 == ERRPTR) return ERRPTR;
833 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
835 SpiderScript_DereferenceValue(op1);
841 case NODETYPE_LOGICALAND:
842 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
844 case NODETYPE_LOGICALOR:
845 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
847 case NODETYPE_LOGICALXOR:
848 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
853 // Free intermediate objects
854 SpiderScript_DereferenceValue(op1);
855 SpiderScript_DereferenceValue(op2);
859 case NODETYPE_EQUALS:
860 case NODETYPE_LESSTHAN:
861 case NODETYPE_GREATERTHAN:
862 case NODETYPE_LESSTHANEQUAL:
863 case NODETYPE_GREATERTHANEQUAL:
864 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
865 if(op1 == ERRPTR) return ERRPTR;
866 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
868 SpiderScript_DereferenceValue(op1);
874 AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
875 if(op1) SpiderScript_DereferenceValue(op1);
876 if(op2) SpiderScript_DereferenceValue(op2);
877 ret = SpiderScript_CreateInteger( !op1 && !op2 );
882 if( op1->Type != op2->Type ) {
883 // If dynamically typed, convert op2 to op1's type
884 if(Block->Script->Variant->bImplicitCasts)
887 op2 = SpiderScript_CastValueTo(op1->Type, op2);
888 SpiderScript_DereferenceValue(tmpobj);
890 SpiderScript_DereferenceValue(op1);
894 // If statically typed, this should never happen, but catch it anyway
896 AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
897 op1->Type, op2->Type);
905 // - String Compare (does a strcmp, well memcmp)
906 case SS_DATATYPE_STRING:
907 // Call memcmp to do most of the work
909 op1->String.Data, op2->String.Data,
910 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
912 // Handle reaching the end of the string
914 if( op1->String.Length == op2->String.Length )
916 else if( op1->String.Length < op2->String.Length )
923 // - Integer Comparisons
924 case SS_DATATYPE_INTEGER:
925 if( op1->Integer == op2->Integer )
927 else if( op1->Integer < op2->Integer )
932 // - Real Number Comparisons
933 case SS_DATATYPE_REAL:
934 cmp = (op1->Real - op2->Real) / op2->Real * 10000; // < 0.1% difference is equality
937 AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
942 // Free intermediate objects
943 SpiderScript_DereferenceValue(op1);
944 SpiderScript_DereferenceValue(op2);
953 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
954 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
955 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
956 case NODETYPE_LESSTHANEQUAL: ret = SpiderScript_CreateInteger(cmp <= 0); break;
957 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0); break;
959 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
965 // General Unary Operations
966 case NODETYPE_BWNOT: // Bitwise NOT (~)
967 case NODETYPE_NEGATE: // Negation (-)
968 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
969 if(op1 == ERRPTR) return ERRPTR;
970 ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
971 SpiderScript_DereferenceValue(op1);
974 // General Binary Operations
976 case NODETYPE_SUBTRACT:
977 case NODETYPE_MULTIPLY:
978 case NODETYPE_DIVIDE:
979 case NODETYPE_MODULO:
983 case NODETYPE_BITSHIFTLEFT:
984 case NODETYPE_BITSHIFTRIGHT:
985 case NODETYPE_BITROTATELEFT:
987 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
988 if(op1 == ERRPTR) return ERRPTR;
989 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
991 SpiderScript_DereferenceValue(op1);
995 ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
997 // Free intermediate objects
998 SpiderScript_DereferenceValue(op1);
999 SpiderScript_DereferenceValue(op2);
1004 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
1008 // Reset namespace when no longer needed
1009 if( Node->Type != NODETYPE_SCOPE )
1010 Block->CurNamespace = NULL;
1012 #if TRACE_NODE_RETURNS
1013 if(ret && ret != ERRPTR) {
1014 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
1017 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
1024 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value)
1028 if( Value->Type == SS_DATATYPE_OBJECT )
1030 const char *fcnname;
1033 case NODETYPE_NEGATE: fcnname = "-ve"; break;
1034 case NODETYPE_BWNOT: fcnname = "~"; break;
1035 default: fcnname = NULL; break;
1040 ret = Object_ExecuteMethod(Value->Object, fcnname, );
1048 // Integer Operations
1049 case SS_DATATYPE_INTEGER:
1050 if( Value->ReferenceCount == 1 )
1051 SpiderScript_ReferenceValue(ret = Value);
1053 ret = SpiderScript_CreateInteger(0);
1056 case NODETYPE_NEGATE: ret->Integer = -Value->Integer; break;
1057 case NODETYPE_BWNOT: ret->Integer = ~Value->Integer; break;
1059 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1060 SpiderScript_DereferenceValue(ret);
1065 // Real number Operations
1066 case SS_DATATYPE_REAL:
1069 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
1071 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1078 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1086 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1088 tSpiderValue *preCastValue = Right;
1092 if( Left && Right && Left->Type != Right->Type )
1096 // - Operator overload functions
1097 if( Left->Type == SS_DATATYPE_OBJECT )
1099 const char *fcnname;
1102 case NODETYPE_ADD: fcnname = "+"; break;
1103 case NODETYPE_SUBTRACT: fcnname = "-"; break;
1104 case NODETYPE_MULTIPLY: fcnname = "*"; break;
1105 case NODETYPE_DIVIDE: fcnname = "/"; break;
1106 case NODETYPE_MODULO: fcnname = "%"; break;
1107 case NODETYPE_BWAND: fcnname = "&"; break;
1108 case NODETYPE_BWOR: fcnname = "|"; break;
1109 case NODETYPE_BWXOR: fcnname = "^"; break;
1110 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
1111 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
1112 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
1113 default: fcnname = NULL; break;
1118 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1121 // Fall through and try casting (which will usually fail)
1126 // If implicit casts are allowed, convert Right to Left's type
1127 if(Block->Script->Variant->bImplicitCasts)
1129 Right = SpiderScript_CastValueTo(Left->Type, Right);
1133 // If statically typed, this should never happen, but catch it anyway
1135 AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
1141 if( Left == NULL || Right == NULL ) {
1142 if(Right && Right != preCastValue) free(Right);
1149 // String Concatenation
1150 case SS_DATATYPE_STRING:
1153 case NODETYPE_ADD: // Concatenate
1154 ret = SpiderScript_StringConcat(Left, Right);
1156 // TODO: Support python style 'i = %i' % i ?
1157 // Might do it via a function call
1158 // Implement it via % with an array, but getting past the cast will be fun
1159 // case NODETYPE_MODULUS:
1161 // TODO: Support string repititions
1162 // case NODETYPE_MULTIPLY:
1166 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1171 // Integer Operations
1172 case SS_DATATYPE_INTEGER:
1173 if( Left->ReferenceCount == 1 )
1174 SpiderScript_ReferenceValue(ret = Left);
1176 ret = SpiderScript_CreateInteger(0);
1179 case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
1180 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
1181 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
1182 case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
1183 case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
1184 case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
1185 case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
1186 case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
1187 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
1188 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
1189 case NODETYPE_BITROTATELEFT:
1190 ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
1193 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
1194 SpiderScript_DereferenceValue(ret);
1201 case SS_DATATYPE_REAL:
1202 if( Left->ReferenceCount == 1 )
1203 SpiderScript_ReferenceValue(ret = Left);
1205 ret = SpiderScript_CreateReal(0);
1208 case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
1209 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
1210 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
1211 case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
1213 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1214 SpiderScript_DereferenceValue(ret);
1221 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1226 if(Right && Right != preCastValue) free(Right);
1232 * \brief Define a variable
1233 * \param Block Current block state
1234 * \param Type Type of the variable
1235 * \param Name Name of the variable
1236 * \return Boolean Failure
1238 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1240 tAST_Variable *var, *prev = NULL;
1242 for( var = Block->FirstVar; var; prev = var, var = var->Next )
1244 if( strcmp(var->Name, Name) == 0 ) {
1245 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1250 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1253 var->Object = Value;
1254 if(Value) SpiderScript_ReferenceValue(Value);
1255 strcpy(var->Name, Name);
1257 if(prev) prev->Next = var;
1258 else Block->FirstVar = var;
1260 //printf("Defined variable %s (%i)\n", Name, Type);
1265 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1267 tAST_Variable *var = NULL;
1270 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1271 var = VarNode->ValueCache;
1272 #if TRACE_VAR_LOOKUPS
1273 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1274 VarNode->Variable.Name, var,
1275 VarNode->BlockState, VarNode->BlockIdent
1281 tAST_BlockState *bs;
1282 for( bs = Block; bs; bs = bs->Parent )
1284 for( var = bs->FirstVar; var; var = var->Next )
1286 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1294 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1296 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1300 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1305 #if TRACE_VAR_LOOKUPS
1306 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1307 VarNode->Variable.Name, var,
1308 Block, Block->Ident);
1311 VarNode->ValueCache = var;
1312 VarNode->BlockState = Block;
1313 VarNode->BlockIdent = Block->Ident;
1320 * \brief Set the value of a variable
1321 * \return Boolean Failure
1323 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1327 var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1329 if( !var ) return -1;
1331 if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1333 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1334 VarNode->Variable.Name);
1338 // printf("Assign %p to '%s'\n", Value, var->Name);
1339 SpiderScript_ReferenceValue(Value);
1340 SpiderScript_DereferenceValue(var->Object);
1341 var->Object = Value;
1346 * \brief Get the value of a variable
1348 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1350 tAST_Variable *var = Variable_Lookup(Block, VarNode, 0);
1352 if( !var ) return ERRPTR;
1354 SpiderScript_ReferenceValue(var->Object);
1359 * \brief Destorys a variable
1361 void Variable_Destroy(tAST_Variable *Variable)
1363 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1364 SpiderScript_DereferenceValue(Variable->Object);
1368 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
1373 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1375 fprintf(stderr, "%s: ", Type);
1376 va_start(args, Format);
1377 vfprintf(stderr, Format, args);
1379 fprintf(stderr, "\n");
1381 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1386 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1388 fprintf(stderr, "error: ");
1389 va_start(args, Format);
1390 vfprintf(stderr, Format, args);
1392 fprintf(stderr, "\n");