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;
451 ret = AST_ExecuteNode_Element(Block->Script, Node, tmpobj, Node->Scope.Name, ERRPTR);
454 // Cast a value to another
457 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
458 if(tmpobj == ERRPTR) return ERRPTR;
459 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
460 SpiderScript_DereferenceValue(tmpobj);
464 // Index into an array
466 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
467 if(op1 == ERRPTR) return ERRPTR;
468 op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
470 SpiderScript_DereferenceValue(op1);
474 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
476 if( !Block->Script->Variant->bImplicitCasts ) {
477 AST_RuntimeError(Node, "Array index is not an integer");
482 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
483 SpiderScript_DereferenceValue(op2);
490 SpiderScript_DereferenceValue(op2);
491 AST_RuntimeError(Node, "Indexing NULL value");
496 ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, ERRPTR);
498 SpiderScript_DereferenceValue(op1);
499 SpiderScript_DereferenceValue(op2);
502 // TODO: Implement runtime constants
503 case NODETYPE_CONSTANT:
504 // TODO: Scan namespace for constant name
505 AST_RuntimeError(Node, "TODO - Runtime Constants");
510 case NODETYPE_STRING:
511 case NODETYPE_INTEGER:
513 ret = &Node->Constant;
514 SpiderScript_ReferenceValue(ret);
520 // --- Operations ---
521 // Boolean Operations
522 case NODETYPE_LOGICALNOT: // Logical NOT (!)
523 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
524 if(op1 == ERRPTR) return ERRPTR;
525 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
526 SpiderScript_DereferenceValue(op1);
528 case NODETYPE_LOGICALAND: // Logical AND (&&)
529 case NODETYPE_LOGICALOR: // Logical OR (||)
530 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
531 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
532 if(op1 == ERRPTR) return ERRPTR;
533 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
535 SpiderScript_DereferenceValue(op1);
541 case NODETYPE_LOGICALAND:
542 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
544 case NODETYPE_LOGICALOR:
545 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
547 case NODETYPE_LOGICALXOR:
548 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
553 // Free intermediate objects
554 SpiderScript_DereferenceValue(op1);
555 SpiderScript_DereferenceValue(op2);
558 // General Unary Operations
559 case NODETYPE_BWNOT: // Bitwise NOT (~)
560 case NODETYPE_NEGATE: // Negation (-)
561 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
562 if(op1 == ERRPTR) return ERRPTR;
563 ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
564 SpiderScript_DereferenceValue(op1);
567 // General Binary Operations
569 case NODETYPE_SUBTRACT:
570 case NODETYPE_MULTIPLY:
571 case NODETYPE_DIVIDE:
572 case NODETYPE_MODULO:
576 case NODETYPE_BITSHIFTLEFT:
577 case NODETYPE_BITSHIFTRIGHT:
578 case NODETYPE_BITROTATELEFT:
579 case NODETYPE_EQUALS:
580 case NODETYPE_NOTEQUALS:
581 case NODETYPE_LESSTHAN:
582 case NODETYPE_GREATERTHAN:
583 case NODETYPE_LESSTHANEQUAL:
584 case NODETYPE_GREATERTHANEQUAL:
586 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
587 if(op1 == ERRPTR) return ERRPTR;
588 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
590 SpiderScript_DereferenceValue(op1);
594 ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
596 // Free intermediate objects
597 SpiderScript_DereferenceValue(op1);
598 SpiderScript_DereferenceValue(op2);
603 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
607 // Reset namespace when no longer needed
608 if( Node->Type != NODETYPE_SCOPE )
609 Block->CurNamespace = NULL;
611 #if TRACE_NODE_RETURNS
612 if(ret && ret != ERRPTR) {
613 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
616 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
624 tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
628 if( Value->Type == SS_DATATYPE_OBJECT )
633 case NODETYPE_NEGATE: fcnname = "-ve"; break;
634 case NODETYPE_BWNOT: fcnname = "~"; break;
635 default: fcnname = NULL; break;
640 ret = Object_ExecuteMethod(Value->Object, fcnname, );
648 // Integer Operations
649 case SS_DATATYPE_INTEGER:
650 if( Value->ReferenceCount == 1 )
651 SpiderScript_ReferenceValue(ret = Value);
653 ret = SpiderScript_CreateInteger(0);
656 case NODETYPE_NEGATE: ret->Integer = -Value->Integer; break;
657 case NODETYPE_BWNOT: ret->Integer = ~Value->Integer; break;
659 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
660 SpiderScript_DereferenceValue(ret);
665 // Real number Operations
666 case SS_DATATYPE_REAL:
669 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
671 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
678 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
686 tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
688 tSpiderValue *preCastValue = Right;
692 if( Left && Right && Left->Type != Right->Type )
696 // - Operator overload functions
697 if( Left->Type == SS_DATATYPE_OBJECT )
702 case NODETYPE_ADD: fcnname = "+"; break;
703 case NODETYPE_SUBTRACT: fcnname = "-"; break;
704 case NODETYPE_MULTIPLY: fcnname = "*"; break;
705 case NODETYPE_DIVIDE: fcnname = "/"; break;
706 case NODETYPE_MODULO: fcnname = "%"; break;
707 case NODETYPE_BWAND: fcnname = "&"; break;
708 case NODETYPE_BWOR: fcnname = "|"; break;
709 case NODETYPE_BWXOR: fcnname = "^"; break;
710 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
711 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
712 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
713 default: fcnname = NULL; break;
718 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
721 // Fall through and try casting (which will usually fail)
726 // If implicit casts are allowed, convert Right to Left's type
727 if(Script->Variant->bImplicitCasts)
729 Right = SpiderScript_CastValueTo(Left->Type, Right);
733 // If statically typed, this should never happen, but catch it anyway
735 AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
741 if( Left == NULL || Right == NULL ) {
742 if(Right && Right != preCastValue) free(Right);
749 case NODETYPE_EQUALS:
750 case NODETYPE_NOTEQUALS:
751 case NODETYPE_LESSTHAN:
752 case NODETYPE_GREATERTHAN:
753 case NODETYPE_LESSTHANEQUAL:
754 case NODETYPE_GREATERTHANEQUAL: {
760 // - String Compare (does a strcmp, well memcmp)
761 case SS_DATATYPE_STRING:
762 // Call memcmp to do most of the work
764 Left->String.Data, Right->String.Data,
765 (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length
767 // Handle reaching the end of the string
769 if( Left->String.Length == Right->String.Length )
771 else if( Left->String.Length < Right->String.Length )
778 // - Integer Comparisons
779 case SS_DATATYPE_INTEGER:
780 if( Left->Integer == Right->Integer )
782 else if( Left->Integer < Right->Integer )
787 // - Real Number Comparisons
788 case SS_DATATYPE_REAL:
789 cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality
792 AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type);
800 if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING)
801 SpiderScript_ReferenceValue(ret = Left);
803 ret = SpiderScript_CreateInteger(0);
808 case NODETYPE_EQUALS: ret->Integer = (cmp == 0); break;
809 case NODETYPE_NOTEQUALS: ret->Integer = (cmp != 0); break;
810 case NODETYPE_LESSTHAN: ret->Integer = (cmp < 0); break;
811 case NODETYPE_GREATERTHAN: ret->Integer = (cmp > 0); break;
812 case NODETYPE_LESSTHANEQUAL: ret->Integer = (cmp <= 0); break;
813 case NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0); break;
815 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation);
816 SpiderScript_DereferenceValue(ret);
821 if(Right && Right != preCastValue) free(Right);
825 // Fall through and sort by type instead
833 // String Concatenation
834 case SS_DATATYPE_STRING:
837 case NODETYPE_ADD: // Concatenate
838 ret = SpiderScript_StringConcat(Left, Right);
840 // TODO: Support python style 'i = %i' % i ?
841 // Might do it via a function call
842 // Implement it via % with an array, but getting past the cast will be fun
843 // case NODETYPE_MODULUS:
845 // TODO: Support string repititions
846 // case NODETYPE_MULTIPLY:
850 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
855 // Integer Operations
856 case SS_DATATYPE_INTEGER:
857 if( Left->ReferenceCount == 1 )
858 SpiderScript_ReferenceValue(ret = Left);
860 ret = SpiderScript_CreateInteger(0);
863 case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
864 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
865 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
866 case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
867 case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
868 case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
869 case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
870 case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
871 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
872 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
873 case NODETYPE_BITROTATELEFT:
874 ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
877 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
878 SpiderScript_DereferenceValue(ret);
885 case SS_DATATYPE_REAL:
886 if( Left->ReferenceCount == 1 )
887 SpiderScript_ReferenceValue(ret = Left);
889 ret = SpiderScript_CreateReal(0);
892 case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
893 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
894 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
895 case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
897 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
898 SpiderScript_DereferenceValue(ret);
905 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
910 if(Right && Right != preCastValue) free(Right);
915 tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node,
916 tSpiderValue *Array, int Index, tSpiderValue *SaveValue)
918 // Quick sanity check
921 AST_RuntimeError(Node, "Indexing NULL, not a good idea");
926 if( SS_GETARRAYDEPTH(Array->Type) )
928 if( Index < 0 || Index >= Array->Array.Length ) {
929 AST_RuntimeError(Node, "Array index out of bounds %i not in (0, %i]",
930 Index, Array->Array.Length);
934 if( SaveValue != ERRPTR )
936 if( SaveValue && SaveValue->Type != SS_DOWNARRAY(Array->Type) ) {
937 // TODO: Implicit casting
938 AST_RuntimeError(Node, "Type mismatch assiging to array element");
941 SpiderScript_DereferenceValue( Array->Array.Items[Index] );
942 Array->Array.Items[Index] = SaveValue;
943 SpiderScript_ReferenceValue( Array->Array.Items[Index] );
948 SpiderScript_ReferenceValue( Array->Array.Items[Index] );
949 return Array->Array.Items[Index];
954 AST_RuntimeError(Node, "TODO - Implement indexing on non-arrays (type = %x)",
961 * \brief Get/Set the value of an element/attribute of a class
962 * \param Script Executing script
963 * \param Node Current execution node (only used for AST_RuntimeError)
964 * \param Object Object value
965 * \param ElementName Name of the attribute to be accessed
966 * \param SaveValue Value to set the element to (if ERRPTR, element value is returned)
968 tSpiderValue *AST_ExecuteNode_Element(tSpiderScript *Script, tAST_Node *Node,
969 tSpiderValue *Object, const char *ElementName, tSpiderValue *SaveValue)
975 AST_RuntimeError(Node, "Tried to access an element of NULL");
979 switch( Object->Type )
981 case SS_DATATYPE_OBJECT: {
982 tSpiderObjectDef *class = Object->Object->Type;
983 for( i = 0; i < class->NAttributes; i ++ )
985 if( strcmp(ElementName, class->AttributeDefs[i].Name) == 0 )
987 if( SaveValue != ERRPTR ) {
988 Object->Object->Attributes[i] = SaveValue;
989 SpiderScript_ReferenceValue(SaveValue);
993 ret = Object->Object->Attributes[i];
994 SpiderScript_ReferenceValue(ret);
999 AST_RuntimeError(Node, "Unknown attribute '%s' of class '%s'",
1000 ElementName, class->Name);
1003 AST_RuntimeError(Node, "Unable to get element of type %i", Object->Type);
1010 * \brief Define a variable
1011 * \param Block Current block state
1012 * \param Type Type of the variable
1013 * \param Name Name of the variable
1014 * \return Boolean Failure
1016 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1018 tAST_Variable *var, *prev = NULL;
1020 for( var = Block->FirstVar; var; prev = var, var = var->Next )
1022 if( strcmp(var->Name, Name) == 0 ) {
1023 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1028 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1031 var->Object = Value;
1032 if(Value) SpiderScript_ReferenceValue(Value);
1033 strcpy(var->Name, Name);
1035 if(prev) prev->Next = var;
1036 else Block->FirstVar = var;
1038 //printf("Defined variable %s (%i)\n", Name, Type);
1043 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1045 tAST_Variable *var = NULL;
1048 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1049 var = VarNode->ValueCache;
1050 #if TRACE_VAR_LOOKUPS
1051 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1052 VarNode->Variable.Name, var,
1053 VarNode->BlockState, VarNode->BlockIdent
1059 tAST_BlockState *bs;
1060 for( bs = Block; bs; bs = bs->Parent )
1062 for( var = bs->FirstVar; var; var = var->Next )
1064 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1072 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1074 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1078 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1083 #if TRACE_VAR_LOOKUPS
1084 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1085 VarNode->Variable.Name, var,
1086 Block, Block->Ident);
1089 VarNode->ValueCache = var;
1090 VarNode->BlockState = Block;
1091 VarNode->BlockIdent = Block->Ident;
1098 * \brief Set the value of a variable
1099 * \return Boolean Failure
1101 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1105 var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1107 if( !var ) return -1;
1109 if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1111 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1112 VarNode->Variable.Name);
1116 // printf("Assign %p to '%s'\n", Value, var->Name);
1117 SpiderScript_ReferenceValue(Value);
1118 SpiderScript_DereferenceValue(var->Object);
1119 var->Object = Value;
1124 * \brief Get the value of a variable
1126 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1128 tAST_Variable *var = Variable_Lookup(Block, VarNode, 0);
1130 if( !var ) return ERRPTR;
1132 SpiderScript_ReferenceValue(var->Object);
1137 * \brief Destorys a variable
1139 void Variable_Destroy(tAST_Variable *Variable)
1141 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1142 SpiderScript_DereferenceValue(Variable->Object);