13 #define USE_AST_EXEC 1
14 #define TRACE_VAR_LOOKUPS 0
15 #define TRACE_NODE_RETURNS 0
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);
24 tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Array, int Index, tSpiderValue *SaveValue);
26 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
27 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
28 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
29 void Variable_Destroy(tAST_Variable *Variable);
31 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
32 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
35 int giNextBlockIdent = 1;
39 tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments)
45 // Build a block State
49 bs.BaseNamespace = &Script->Variant->RootNamespace;
50 bs.CurNamespace = NULL;
52 bs.Ident = giNextBlockIdent ++;
55 for( i = 0; i < Fcn->ArgumentCount; i ++ )
57 if( i >= NArguments ) break; // TODO: Return gracefully
60 Fcn->Arguments[i].Type, Fcn->Arguments[i].Name,
65 ret = AST_ExecuteNode(&bs, Fcn->ASTFcn);
68 SpiderScript_DereferenceValue(ret); // Dereference output of last block statement
69 ret = bs.RetVal; // Set to return value of block
74 tAST_Variable *nextVar = bs.FirstVar->Next;
75 Variable_Destroy( bs.FirstVar );
76 bs.FirstVar = nextVar;
82 * \brief Execute an AST node and return its value
83 * \param Block Execution context
84 * \param Node Node to execute
86 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
89 tSpiderValue *ret = NULL, *tmpobj;
90 tSpiderValue *op1, *op2; // Binary operations
103 tAST_BlockState blockInfo;
104 blockInfo.Parent = Block;
105 blockInfo.Script = Block->Script;
106 blockInfo.FirstVar = NULL;
107 blockInfo.RetVal = NULL;
108 blockInfo.BaseNamespace = Block->BaseNamespace;
109 blockInfo.CurNamespace = NULL;
110 blockInfo.BreakTarget = NULL;
111 blockInfo.Ident = giNextBlockIdent ++;
113 // Loop over all nodes, or until the return value is set
114 for(node = Node->Block.FirstChild;
115 node && !blockInfo.RetVal && !blockInfo.BreakTarget;
116 node = node->NextSibling )
118 ret = AST_ExecuteNode(&blockInfo, node);
119 if(ret == ERRPTR) break; // Error check
120 if(ret != NULL) SpiderScript_DereferenceValue(ret); // Free unused value
122 // Clean up variables
123 while(blockInfo.FirstVar)
125 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
126 Variable_Destroy( blockInfo.FirstVar );
127 blockInfo.FirstVar = nextVar;
129 // Clear ret if not an error
130 if(ret != ERRPTR) ret = NULL;
132 // Set parent's return value if needed
133 if( blockInfo.RetVal )
134 Block->RetVal = blockInfo.RetVal;
135 if( blockInfo.BreakTarget ) {
136 Block->BreakTarget = blockInfo.BreakTarget;
137 Block->BreakType = blockInfo.BreakType;
140 // TODO: Unset break if break type deontes a block break
146 case NODETYPE_ASSIGN:
147 // TODO: Support assigning to object attributes
148 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
149 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
152 ret = AST_ExecuteNode(Block, Node->Assign.Value);
153 if(ret == ERRPTR) return ERRPTR;
155 // Perform assignment operation
156 if( Node->Assign.Operation != NODETYPE_NOP )
158 tSpiderValue *varVal, *value;
160 varVal = Variable_GetValue(Block, Node->Assign.Dest);
161 if(varVal == ERRPTR) return ERRPTR;
164 if(varVal && varVal->ReferenceCount == 2) {
165 SpiderScript_DereferenceValue(varVal);
166 // printf("pre: (%s) varVal->ReferenceCount = %i\n",
167 // Node->Assign.Dest->Variable.Name,
168 // varVal->ReferenceCount);
171 value = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Assign.Operation, varVal, ret);
172 if(value == ERRPTR) return ERRPTR;
174 if(ret) SpiderScript_DereferenceValue(ret);
176 if(varVal) SpiderScript_DereferenceValue(varVal);
178 if(varVal && varVal->ReferenceCount == 1) {
179 SpiderScript_ReferenceValue(varVal);
180 // printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
181 break; // If varVal was non-null, it has been updated by _BinOp
184 // Else, it was NULL, so has to be assigned
188 // Set the variable value
189 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
190 SpiderScript_DereferenceValue( ret );
195 // Post increment/decrement
196 case NODETYPE_POSTINC:
197 case NODETYPE_POSTDEC:
199 tSpiderValue *varVal, *value;
200 static tSpiderValue one = {
201 .Type = SS_DATATYPE_INTEGER,
206 // TODO: Support assigning to object attributes
207 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
208 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
212 // Get values (current variable contents and a static one)
213 varVal = Variable_GetValue(Block, Node->UniOp.Value);
215 if( Node->Type == NODETYPE_POSTDEC )
216 value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_SUBTRACT, varVal, &one);
218 value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_ADD, varVal, &one);
219 if( value == ERRPTR )
224 if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
225 SpiderScript_DereferenceValue( ret );
228 SpiderScript_DereferenceValue( value );
233 case NODETYPE_METHODCALL:
234 case NODETYPE_FUNCTIONCALL:
235 case NODETYPE_CREATEOBJECT:
236 // Logical block (used to allocate `params`)
238 const char *namespaces[] = {NULL}; // TODO: Default namespaces?
239 tSpiderValue *params[Node->FunctionCall.NumArgs];
243 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
245 params[i] = AST_ExecuteNode(Block, node);
246 if( params[i] == ERRPTR ) {
247 while(i--) SpiderScript_DereferenceValue(params[i]);
254 // TODO: Check for cached function reference
257 if( Node->Type == NODETYPE_CREATEOBJECT )
259 ret = SpiderScript_CreateObject(Block->Script,
260 Node->FunctionCall.Name,
262 Node->FunctionCall.NumArgs, params
265 else if( Node->Type == NODETYPE_METHODCALL )
267 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
268 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
269 AST_RuntimeError(Node->FunctionCall.Object,
270 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
271 while(i--) SpiderScript_DereferenceValue(params[i]);
275 ret = SpiderScript_ExecuteMethod(Block->Script,
276 obj->Object, Node->FunctionCall.Name,
277 Node->FunctionCall.NumArgs, params
279 SpiderScript_DereferenceValue(obj);
283 ret = SpiderScript_ExecuteFunction(Block->Script,
284 Node->FunctionCall.Name,
286 Node->FunctionCall.NumArgs, params,
292 // Dereference parameters
293 while(i--) SpiderScript_DereferenceValue(params[i]);
301 ret = AST_ExecuteNode(Block, Node->If.Condition);
302 if( ret == ERRPTR ) break;
303 if( SpiderScript_IsValueTrue(ret) ) {
304 tmpobj = AST_ExecuteNode(Block, Node->If.True);
307 tmpobj = AST_ExecuteNode(Block, Node->If.False);
309 SpiderScript_DereferenceValue(ret);
310 if( tmpobj == ERRPTR ) return ERRPTR;
311 SpiderScript_DereferenceValue(tmpobj);
318 ret = AST_ExecuteNode(Block, Node->For.Init);
319 if(ret == ERRPTR) break;
321 // Check initial condition
322 if( !Node->For.bCheckAfter )
324 SpiderScript_DereferenceValue(ret);
326 ret = AST_ExecuteNode(Block, Node->For.Condition);
327 if(ret == ERRPTR) return ERRPTR;
328 if(!SpiderScript_IsValueTrue(ret)) {
329 SpiderScript_DereferenceValue(ret);
338 SpiderScript_DereferenceValue(ret);
341 ret = AST_ExecuteNode(Block, Node->For.Code);
342 if(ret == ERRPTR) return ERRPTR;
343 SpiderScript_DereferenceValue(ret);
345 if(Block->BreakTarget)
347 if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
350 free((void*)Block->BreakTarget); Block->BreakTarget = NULL;
351 if( Block->BreakType == NODETYPE_CONTINUE ) {
352 // Continue, just keep going
358 break; // Break out of this loop
362 ret = AST_ExecuteNode(Block, Node->For.Increment);
363 if(ret == ERRPTR) return ERRPTR;
364 SpiderScript_DereferenceValue(ret);
367 ret = AST_ExecuteNode(Block, Node->For.Condition);
368 if(ret == ERRPTR) return ERRPTR;
369 if(!SpiderScript_IsValueTrue(ret)) break;
371 SpiderScript_DereferenceValue(ret);
376 case NODETYPE_RETURN:
377 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
378 if(ret == ERRPTR) break;
379 Block->RetVal = ret; // Return value set
380 ret = NULL; // the `return` statement does not return a value
384 case NODETYPE_CONTINUE:
385 Block->BreakTarget = strdup(Node->Variable.Name);
386 Block->BreakType = Node->Type;
390 case NODETYPE_DEFVAR:
391 if( Node->DefVar.InitialValue ) {
392 tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
393 if(tmpobj == ERRPTR) return ERRPTR;
398 // TODO: Handle arrays
400 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
402 SpiderScript_DereferenceValue(tmpobj);
408 tSpiderNamespace *ns;
410 // Set current namespace if unset
411 if( !Block->CurNamespace )
412 Block->CurNamespace = Block->BaseNamespace;
414 // Empty string means use the root namespace
415 if( Node->Scope.Name[0] == '\0' )
417 ns = &Block->Script->Variant->RootNamespace;
421 // Otherwise scan the current namespace for the element
422 for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
424 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
429 AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
433 Block->CurNamespace = ns;
435 // TODO: Check type of child node (Scope, Constant or Function)
437 ret = AST_ExecuteNode(Block, Node->Scope.Element);
442 case NODETYPE_VARIABLE:
443 ret = Variable_GetValue( Block, Node );
446 // Element of an Object
447 case NODETYPE_ELEMENT:
448 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
449 if(tmpobj == ERRPTR) return ERRPTR;
450 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
452 AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
457 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
459 if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
461 ret = tmpobj->Object->Attributes[i];
462 SpiderScript_ReferenceValue(ret);
466 if( i == tmpobj->Object->Type->NAttributes )
468 AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
469 Node->Scope.Name, tmpobj->Object->Type->Name);
474 // Cast a value to another
477 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
478 if(tmpobj == ERRPTR) return ERRPTR;
479 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
480 SpiderScript_DereferenceValue(tmpobj);
484 // Index into an array
486 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
487 if(op1 == ERRPTR) return ERRPTR;
488 op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
490 SpiderScript_DereferenceValue(op1);
494 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
496 if( !Block->Script->Variant->bImplicitCasts ) {
497 AST_RuntimeError(Node, "Array index is not an integer");
502 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
503 SpiderScript_DereferenceValue(op2);
510 SpiderScript_DereferenceValue(op2);
511 AST_RuntimeError(Node, "Indexing NULL value");
516 ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, NULL);
518 SpiderScript_DereferenceValue(op1);
519 SpiderScript_DereferenceValue(op2);
522 // TODO: Implement runtime constants
523 case NODETYPE_CONSTANT:
524 // TODO: Scan namespace for constant name
525 AST_RuntimeError(Node, "TODO - Runtime Constants");
530 case NODETYPE_STRING:
531 case NODETYPE_INTEGER:
533 ret = &Node->Constant;
534 SpiderScript_ReferenceValue(ret);
540 // --- Operations ---
541 // Boolean Operations
542 case NODETYPE_LOGICALNOT: // Logical NOT (!)
543 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
544 if(op1 == ERRPTR) return ERRPTR;
545 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
546 SpiderScript_DereferenceValue(op1);
548 case NODETYPE_LOGICALAND: // Logical AND (&&)
549 case NODETYPE_LOGICALOR: // Logical OR (||)
550 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
551 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
552 if(op1 == ERRPTR) return ERRPTR;
553 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
555 SpiderScript_DereferenceValue(op1);
561 case NODETYPE_LOGICALAND:
562 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
564 case NODETYPE_LOGICALOR:
565 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
567 case NODETYPE_LOGICALXOR:
568 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
573 // Free intermediate objects
574 SpiderScript_DereferenceValue(op1);
575 SpiderScript_DereferenceValue(op2);
578 // General Unary Operations
579 case NODETYPE_BWNOT: // Bitwise NOT (~)
580 case NODETYPE_NEGATE: // Negation (-)
581 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
582 if(op1 == ERRPTR) return ERRPTR;
583 ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
584 SpiderScript_DereferenceValue(op1);
587 // General Binary Operations
589 case NODETYPE_SUBTRACT:
590 case NODETYPE_MULTIPLY:
591 case NODETYPE_DIVIDE:
592 case NODETYPE_MODULO:
596 case NODETYPE_BITSHIFTLEFT:
597 case NODETYPE_BITSHIFTRIGHT:
598 case NODETYPE_BITROTATELEFT:
599 case NODETYPE_EQUALS:
600 case NODETYPE_NOTEQUALS:
601 case NODETYPE_LESSTHAN:
602 case NODETYPE_GREATERTHAN:
603 case NODETYPE_LESSTHANEQUAL:
604 case NODETYPE_GREATERTHANEQUAL:
606 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
607 if(op1 == ERRPTR) return ERRPTR;
608 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
610 SpiderScript_DereferenceValue(op1);
614 ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
616 // Free intermediate objects
617 SpiderScript_DereferenceValue(op1);
618 SpiderScript_DereferenceValue(op2);
623 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
627 // Reset namespace when no longer needed
628 if( Node->Type != NODETYPE_SCOPE )
629 Block->CurNamespace = NULL;
631 #if TRACE_NODE_RETURNS
632 if(ret && ret != ERRPTR) {
633 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
636 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
644 tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
648 if( Value->Type == SS_DATATYPE_OBJECT )
653 case NODETYPE_NEGATE: fcnname = "-ve"; break;
654 case NODETYPE_BWNOT: fcnname = "~"; break;
655 default: fcnname = NULL; break;
660 ret = Object_ExecuteMethod(Value->Object, fcnname, );
668 // Integer Operations
669 case SS_DATATYPE_INTEGER:
670 if( Value->ReferenceCount == 1 )
671 SpiderScript_ReferenceValue(ret = Value);
673 ret = SpiderScript_CreateInteger(0);
676 case NODETYPE_NEGATE: ret->Integer = -Value->Integer; break;
677 case NODETYPE_BWNOT: ret->Integer = ~Value->Integer; break;
679 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
680 SpiderScript_DereferenceValue(ret);
685 // Real number Operations
686 case SS_DATATYPE_REAL:
689 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
691 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
698 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
706 tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
708 tSpiderValue *preCastValue = Right;
712 if( Left && Right && Left->Type != Right->Type )
716 // - Operator overload functions
717 if( Left->Type == SS_DATATYPE_OBJECT )
722 case NODETYPE_ADD: fcnname = "+"; break;
723 case NODETYPE_SUBTRACT: fcnname = "-"; break;
724 case NODETYPE_MULTIPLY: fcnname = "*"; break;
725 case NODETYPE_DIVIDE: fcnname = "/"; break;
726 case NODETYPE_MODULO: fcnname = "%"; break;
727 case NODETYPE_BWAND: fcnname = "&"; break;
728 case NODETYPE_BWOR: fcnname = "|"; break;
729 case NODETYPE_BWXOR: fcnname = "^"; break;
730 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
731 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
732 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
733 default: fcnname = NULL; break;
738 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
741 // Fall through and try casting (which will usually fail)
746 // If implicit casts are allowed, convert Right to Left's type
747 if(Script->Variant->bImplicitCasts)
749 Right = SpiderScript_CastValueTo(Left->Type, Right);
753 // If statically typed, this should never happen, but catch it anyway
755 AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
761 if( Left == NULL || Right == NULL ) {
762 if(Right && Right != preCastValue) free(Right);
769 case NODETYPE_EQUALS:
770 case NODETYPE_NOTEQUALS:
771 case NODETYPE_LESSTHAN:
772 case NODETYPE_GREATERTHAN:
773 case NODETYPE_LESSTHANEQUAL:
774 case NODETYPE_GREATERTHANEQUAL: {
780 // - String Compare (does a strcmp, well memcmp)
781 case SS_DATATYPE_STRING:
782 // Call memcmp to do most of the work
784 Left->String.Data, Right->String.Data,
785 (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length
787 // Handle reaching the end of the string
789 if( Left->String.Length == Right->String.Length )
791 else if( Left->String.Length < Right->String.Length )
798 // - Integer Comparisons
799 case SS_DATATYPE_INTEGER:
800 if( Left->Integer == Right->Integer )
802 else if( Left->Integer < Right->Integer )
807 // - Real Number Comparisons
808 case SS_DATATYPE_REAL:
809 cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality
812 AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type);
820 if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING)
821 SpiderScript_ReferenceValue(ret = Left);
823 ret = SpiderScript_CreateInteger(0);
828 case NODETYPE_EQUALS: ret->Integer = (cmp == 0); break;
829 case NODETYPE_NOTEQUALS: ret->Integer = (cmp != 0); break;
830 case NODETYPE_LESSTHAN: ret->Integer = (cmp < 0); break;
831 case NODETYPE_GREATERTHAN: ret->Integer = (cmp > 0); break;
832 case NODETYPE_LESSTHANEQUAL: ret->Integer = (cmp <= 0); break;
833 case NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0); break;
835 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation);
836 SpiderScript_DereferenceValue(ret);
841 if(Right && Right != preCastValue) free(Right);
845 // Fall through and sort by type instead
853 // String Concatenation
854 case SS_DATATYPE_STRING:
857 case NODETYPE_ADD: // Concatenate
858 ret = SpiderScript_StringConcat(Left, Right);
860 // TODO: Support python style 'i = %i' % i ?
861 // Might do it via a function call
862 // Implement it via % with an array, but getting past the cast will be fun
863 // case NODETYPE_MODULUS:
865 // TODO: Support string repititions
866 // case NODETYPE_MULTIPLY:
870 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
875 // Integer Operations
876 case SS_DATATYPE_INTEGER:
877 if( Left->ReferenceCount == 1 )
878 SpiderScript_ReferenceValue(ret = Left);
880 ret = SpiderScript_CreateInteger(0);
883 case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
884 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
885 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
886 case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
887 case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
888 case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
889 case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
890 case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
891 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
892 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
893 case NODETYPE_BITROTATELEFT:
894 ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
897 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
898 SpiderScript_DereferenceValue(ret);
905 case SS_DATATYPE_REAL:
906 if( Left->ReferenceCount == 1 )
907 SpiderScript_ReferenceValue(ret = Left);
909 ret = SpiderScript_CreateReal(0);
912 case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
913 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
914 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
915 case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
917 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
918 SpiderScript_DereferenceValue(ret);
925 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
930 if(Right && Right != preCastValue) free(Right);
935 tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node,
936 tSpiderValue *Array, int Index, tSpiderValue *SaveValue)
938 // Quick sanity check
941 AST_RuntimeError(Node, "Indexing NULL, not a good idea");
946 if( SS_GETARRAYDEPTH(Array->Type) )
948 if( Index < 0 || Index >= Array->Array.Length ) {
949 AST_RuntimeError(Node, "Array index out of bounds %i not in (0, %i]",
950 Index, Array->Array.Length);
956 if( SaveValue->Type != SS_DOWNARRAY(Array->Type) ) {
957 // TODO: Implicit casting
958 AST_RuntimeError(Node, "Type mismatch assiging to array element");
961 SpiderScript_DereferenceValue( Array->Array.Items[Index] );
962 Array->Array.Items[Index] = SaveValue;
963 SpiderScript_ReferenceValue( Array->Array.Items[Index] );
968 SpiderScript_ReferenceValue( Array->Array.Items[Index] );
969 return Array->Array.Items[Index];
974 AST_RuntimeError(Node, "TODO - Implement indexing on non-arrays (type = %x)",
982 * \brief Define a variable
983 * \param Block Current block state
984 * \param Type Type of the variable
985 * \param Name Name of the variable
986 * \return Boolean Failure
988 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
990 tAST_Variable *var, *prev = NULL;
992 for( var = Block->FirstVar; var; prev = var, var = var->Next )
994 if( strcmp(var->Name, Name) == 0 ) {
995 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1000 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1003 var->Object = Value;
1004 if(Value) SpiderScript_ReferenceValue(Value);
1005 strcpy(var->Name, Name);
1007 if(prev) prev->Next = var;
1008 else Block->FirstVar = var;
1010 //printf("Defined variable %s (%i)\n", Name, Type);
1015 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1017 tAST_Variable *var = NULL;
1020 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1021 var = VarNode->ValueCache;
1022 #if TRACE_VAR_LOOKUPS
1023 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1024 VarNode->Variable.Name, var,
1025 VarNode->BlockState, VarNode->BlockIdent
1031 tAST_BlockState *bs;
1032 for( bs = Block; bs; bs = bs->Parent )
1034 for( var = bs->FirstVar; var; var = var->Next )
1036 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1044 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1046 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1050 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1055 #if TRACE_VAR_LOOKUPS
1056 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1057 VarNode->Variable.Name, var,
1058 Block, Block->Ident);
1061 VarNode->ValueCache = var;
1062 VarNode->BlockState = Block;
1063 VarNode->BlockIdent = Block->Ident;
1070 * \brief Set the value of a variable
1071 * \return Boolean Failure
1073 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1077 var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1079 if( !var ) return -1;
1081 if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1083 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1084 VarNode->Variable.Name);
1088 // printf("Assign %p to '%s'\n", Value, var->Name);
1089 SpiderScript_ReferenceValue(Value);
1090 SpiderScript_DereferenceValue(var->Object);
1091 var->Object = Value;
1096 * \brief Get the value of a variable
1098 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1100 tAST_Variable *var = Variable_Lookup(Block, VarNode, 0);
1102 if( !var ) return ERRPTR;
1104 SpiderScript_ReferenceValue(var->Object);
1109 * \brief Destorys a variable
1111 void Variable_Destroy(tAST_Variable *Variable)
1113 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1114 SpiderScript_DereferenceValue(Variable->Object);