12 #define TRACE_VAR_LOOKUPS 0
13 #define TRACE_NODE_RETURNS 0
16 extern tSpiderFunction *gpExports_First;
19 void Object_Dereference(tSpiderValue *Object);
20 void Object_Reference(tSpiderValue *Object);
21 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
22 tSpiderValue *SpiderScript_CreateReal(double Value);
23 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
24 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
25 int SpiderScript_IsValueTrue(tSpiderValue *Value);
26 void SpiderScript_FreeValue(tSpiderValue *Value);
27 char *SpiderScript_DumpValue(tSpiderValue *Value);
29 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
30 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
31 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value);
33 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
34 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
35 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
36 void Variable_Destroy(tAST_Variable *Variable);
38 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
39 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
42 int giNextBlockIdent = 1;
46 * \brief Dereference a created object
48 void Object_Dereference(tSpiderValue *Object)
51 if(Object == ERRPTR) return ;
52 Object->ReferenceCount --;
53 // printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount);
54 if( Object->ReferenceCount == 0 ) {
55 switch( (enum eSpiderScript_DataTypes) Object->Type )
57 case SS_DATATYPE_OBJECT:
58 Object->Object->Type->Destructor( Object->Object );
60 case SS_DATATYPE_OPAQUE:
61 Object->Opaque.Destroy( Object->Opaque.Data );
70 void Object_Reference(tSpiderValue *Object)
73 Object->ReferenceCount ++;
74 // printf("%p Referenced (%i)\n", Object, Object->ReferenceCount);
78 * \brief Allocate and initialise a SpiderScript object
80 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
82 int size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
83 tSpiderObject *ret = malloc(size);
86 ret->ReferenceCount = 1;
87 ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
88 memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
94 * \brief Create an integer object
96 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
98 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
99 ret->Type = SS_DATATYPE_INTEGER;
100 ret->ReferenceCount = 1;
101 ret->Integer = Value;
106 * \brief Create an real number object
108 tSpiderValue *SpiderScript_CreateReal(double Value)
110 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
111 ret->Type = SS_DATATYPE_REAL;
112 ret->ReferenceCount = 1;
118 * \brief Create an string object
120 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
122 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
123 ret->Type = SS_DATATYPE_STRING;
124 ret->ReferenceCount = 1;
125 ret->String.Length = Length;
127 memcpy(ret->String.Data, Data, Length);
129 memset(ret->String.Data, 0, Length);
130 ret->String.Data[Length] = '\0';
135 * \brief Concatenate two strings
137 tSpiderValue *Object_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
141 if(Str1) newLen += Str1->String.Length;
142 if(Str2) newLen += Str2->String.Length;
143 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
144 ret->Type = SS_DATATYPE_STRING;
145 ret->ReferenceCount = 1;
146 ret->String.Length = newLen;
148 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
151 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
153 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
155 ret->String.Data[ newLen ] = '\0';
160 * \brief Cast one object to another
161 * \brief Type Destination type
162 * \brief Source Input data
164 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
166 tSpiderValue *ret = ERRPTR;
173 case SS_DATATYPE_INTEGER: return SpiderScript_CreateInteger(0);
174 case SS_DATATYPE_REAL: return SpiderScript_CreateReal(0);
175 case SS_DATATYPE_STRING: return SpiderScript_CreateString(4, "null");
180 // Check if anything needs to be done
181 if( Source->Type == Type ) {
182 Object_Reference(Source);
188 printf("Casting %i ", Source->Type);
191 case SS_DATATYPE_INTEGER: printf("0x%lx", Source->Integer); break;
192 case SS_DATATYPE_STRING: printf("\"%s\"", Source->String.Data); break;
193 case SS_DATATYPE_REAL: printf("%f", Source->Real); break;
196 printf(" to %i\n", Type);
201 if( Source->Type == SS_DATATYPE_OBJECT )
203 const char *name = NULL;
206 case SS_DATATYPE_INTEGER: name = "cast Integer"; break;
207 case SS_DATATYPE_REAL: name = "cast Real"; break;
208 case SS_DATATYPE_STRING: name = "cast String"; break;
209 case SS_DATATYPE_ARRAY: name = "cast Array"; break;
211 AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
216 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
219 // Fall through and try casting (which will usually fail)
224 switch( (enum eSpiderScript_DataTypes)Type )
226 case SS_DATATYPE_UNDEF:
227 case SS_DATATYPE_ARRAY:
228 case SS_DATATYPE_OPAQUE:
229 case SS_DATATYPE_OBJECT:
230 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
233 case SS_DATATYPE_INTEGER:
234 ret = malloc(sizeof(tSpiderValue));
235 ret->Type = SS_DATATYPE_INTEGER;
236 ret->ReferenceCount = 1;
239 case SS_DATATYPE_INTEGER: break; // Handled above
240 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
241 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
243 AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
250 case SS_DATATYPE_REAL:
251 ret = malloc(sizeof(tSpiderValue));
252 ret->Type = SS_DATATYPE_REAL;
253 ret->ReferenceCount = 1;
256 case SS_DATATYPE_STRING: ret->Real = atof(Source->String.Data); break;
257 case SS_DATATYPE_INTEGER: ret->Real = Source->Integer; break;
259 AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
266 case SS_DATATYPE_STRING:
269 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
270 case SS_DATATYPE_REAL: len = snprintf(NULL, 0, "%g", Source->Real); break;
273 ret = malloc(sizeof(tSpiderValue) + len + 1);
274 ret->Type = SS_DATATYPE_STRING;
275 ret->ReferenceCount = 1;
276 ret->String.Length = len;
279 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
280 case SS_DATATYPE_REAL:
281 sprintf(ret->String.Data, "%g", Source->Real); break;
283 AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
291 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
300 * \brief Condenses a value down to a boolean
302 int SpiderScript_IsValueTrue(tSpiderValue *Value)
304 if( Value == ERRPTR ) return 0;
305 if( Value == NULL ) return 0;
307 switch( (enum eSpiderScript_DataTypes)Value->Type )
309 case SS_DATATYPE_UNDEF:
312 case SS_DATATYPE_INTEGER:
313 return !!Value->Integer;
315 case SS_DATATYPE_REAL:
316 return (-.5f < Value->Real && Value->Real < 0.5f);
318 case SS_DATATYPE_STRING:
319 return Value->String.Length > 0;
321 case SS_DATATYPE_OBJECT:
322 return Value->Object != NULL;
324 case SS_DATATYPE_OPAQUE:
325 return Value->Opaque.Data != NULL;
327 case SS_DATATYPE_ARRAY:
328 return Value->Array.Length > 0;
330 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
337 * \brief Free a value
338 * \note Just calls Object_Dereference
340 void SpiderScript_FreeValue(tSpiderValue *Value)
342 Object_Dereference(Value);
346 * \brief Dump a value into a string
347 * \return Heap string
349 char *SpiderScript_DumpValue(tSpiderValue *Value)
352 if( Value == ERRPTR )
353 return strdup("ERRPTR");
355 return strdup("null");
357 switch( (enum eSpiderScript_DataTypes)Value->Type )
359 case SS_DATATYPE_UNDEF: return strdup("undefined");
361 case SS_DATATYPE_INTEGER:
362 ret = malloc( sizeof(Value->Integer)*2 + 3 );
363 sprintf(ret, "0x%lx", Value->Integer);
366 case SS_DATATYPE_REAL:
367 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
368 sprintf(ret, "%f", Value->Real);
371 case SS_DATATYPE_STRING:
372 ret = malloc( Value->String.Length + 3 );
374 strcpy(ret+1, Value->String.Data);
375 ret[Value->String.Length+1] = '"';
376 ret[Value->String.Length+2] = '\0';
379 case SS_DATATYPE_OBJECT:
380 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
381 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
384 case SS_DATATYPE_OPAQUE:
385 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
386 sprintf(ret, "*%p", Value->Opaque.Data);
389 case SS_DATATYPE_ARRAY:
390 return strdup("Array");
393 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
400 * \brief Execute a script function
401 * \param Script Script context to execute in
402 * \param Namespace Namespace to search for the function
403 * \param Function Function name to execute
404 * \param NArguments Number of arguments to pass
405 * \param Arguments Arguments passed
407 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
408 tSpiderNamespace *Namespace, const char *Function,
409 int NArguments, tSpiderValue **Arguments)
411 int bFound = 0; // Used to keep nesting levels down
412 tSpiderValue *ret = ERRPTR;
413 tSpiderFunction *fcn;
415 // First: Find the function in the script
417 tAST_Function *astFcn;
418 for( astFcn = Script->Script->Functions; astFcn; astFcn = astFcn->Next )
420 if( strcmp(astFcn->Name, Function) == 0 )
430 // Build a block State
434 bs.BaseNamespace = &Script->Variant->RootNamespace;
435 bs.CurNamespace = NULL;
437 bs.Ident = giNextBlockIdent ++;
440 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
442 if( i >= NArguments ) break; // TODO: Return gracefully
445 arg->DefVar.DataType, arg->DefVar.Name,
450 ret = AST_ExecuteNode(&bs, astFcn->Code);
453 Object_Dereference(ret); // Dereference output of last block statement
454 ret = bs.RetVal; // Set to return value of block
460 tAST_Variable *nextVar = bs.FirstVar->Next;
461 Variable_Destroy( bs.FirstVar );
462 bs.FirstVar = nextVar;
467 // Didn't find it in script?
470 fcn = NULL; // Just to allow the below code to be neat
472 // Second: Scan current namespace
473 if( !fcn && Namespace )
475 for( fcn = Namespace->Functions; fcn; fcn = fcn->Next )
477 if( strcmp( fcn->Name, Function ) == 0 )
482 // Third: Search the variant's global exports
485 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
487 if( strcmp( fcn->Name, Function ) == 0 )
492 // Fourth: Search language exports
495 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
497 if( strcmp( fcn->Name, Function ) == 0 )
505 // TODO: Type Checking
506 ret = fcn->Handler( Script, NArguments, Arguments );
514 fprintf(stderr, "Undefined reference to function '%s' (ns='%s')\n",
515 Function, Namespace->Name);
523 * \brief Execute an object method function
524 * \param Script Script context to execute in
525 * \param Object Object in which to find the method
526 * \param MethodName Name of method to call
527 * \param NArguments Number of arguments to pass
528 * \param Arguments Arguments passed
530 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
531 tSpiderObject *Object, const char *MethodName,
532 int NArguments, tSpiderValue **Arguments)
534 tSpiderFunction *fcn;
536 tSpiderValue *newargs[NArguments+1];
539 // TODO: Support program defined objects
541 // Search for the function
542 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
544 if( strcmp(fcn->Name, MethodName) == 0 )
550 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
551 Object->Type->Name, MethodName);
555 // Create the "this" argument
556 this.Type = SS_DATATYPE_OBJECT;
557 this.ReferenceCount = 1;
558 this.Object = Object;
560 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
562 // Check the type of the arguments
563 for( i = 0; fcn->ArgTypes[i]; i ++ )
565 if( i >= NArguments ) {
566 for( ; fcn->ArgTypes[i]; i ++ ) ;
567 AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
571 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
573 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
574 Arguments[i]->Type, fcn->ArgTypes[i]);
580 return fcn->Handler(Script, NArguments+1, newargs);
584 * \brief Execute a script function
585 * \param Script Script context to execute in
586 * \param Function Function name to execute
587 * \param NArguments Number of arguments to pass
588 * \param Arguments Arguments passed
590 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
591 tSpiderNamespace *Namespace, const char *ClassName,
592 int NArguments, tSpiderValue **Arguments)
594 int bFound = 0; // Used to keep nesting levels down
595 tSpiderValue *ret = ERRPTR;
596 tSpiderObjectDef *class;
598 // First: Find the function in the script
599 // TODO: Implement script-defined classes
602 tAST_Function *astClass;
603 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
605 if( strcmp(astClass->Name, ClassName) == 0 )
615 // Build a block State
619 bs.BaseNamespace = &Script->Variant->RootNamespace;
620 bs.CurNamespace = NULL;
622 bs.Ident = giNextBlockIdent ++;
624 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
626 if( i >= NArguments ) break; // TODO: Return gracefully
629 arg->DefVar.DataType, arg->DefVar.Name,
634 ret = AST_ExecuteNode(&bs, astFcn->Code);
637 Object_Dereference(ret); // Dereference output of last block statement
638 ret = bs.RetVal; // Set to return value of block
644 tAST_Variable *nextVar = bs.FirstVar->Next;
645 Variable_Destroy( bs.FirstVar );
646 bs.FirstVar = nextVar;
652 // Didn't find it in script?
655 class = NULL; // Just to allow the below code to be neat
658 // Namespace = &Script->Variant->RootNamespace;
660 // Second: Scan current namespace
661 if( !class && Namespace )
663 for( class = Namespace->Classes; class; class = class->Next )
665 if( strcmp( class->Name, ClassName ) == 0 )
671 // Third: Search the variant's global exports
674 for( class = Script->Variant->Classes; class; class = fcn->Next )
676 if( strcmp( class->Name, Function ) == 0 )
683 // Fourth: Search language exports
686 for( class = gpExports_First; class; class = fcn->Next )
688 if( strcmp( class->Name, ClassName ) == 0 )
698 // TODO: Type Checking
701 obj = class->Constructor( NArguments, Arguments );
702 if( obj == NULL || obj == ERRPTR )
705 // Creatue return object
706 ret = malloc( sizeof(tSpiderValue) );
707 ret->Type = SS_DATATYPE_OBJECT;
708 ret->ReferenceCount = 1;
717 fprintf(stderr, "Undefined reference to class '%s'\n", ClassName);
726 * \brief Execute an AST node and return its value
727 * \param Block Execution context
728 * \param Node Node to execute
730 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
733 tSpiderValue *ret = NULL, *tmpobj;
734 tSpiderValue *op1, *op2; // Binary operations
735 int cmp; // Used in comparisons
748 tAST_BlockState blockInfo;
749 blockInfo.Parent = Block;
750 blockInfo.Script = Block->Script;
751 blockInfo.FirstVar = NULL;
752 blockInfo.RetVal = NULL;
753 blockInfo.BaseNamespace = Block->BaseNamespace;
754 blockInfo.CurNamespace = NULL;
755 blockInfo.BreakTarget = NULL;
756 blockInfo.Ident = giNextBlockIdent ++;
758 // Loop over all nodes, or until the return value is set
759 for(node = Node->Block.FirstChild;
760 node && !blockInfo.RetVal && !blockInfo.BreakTarget;
761 node = node->NextSibling )
763 ret = AST_ExecuteNode(&blockInfo, node);
764 if(ret == ERRPTR) break; // Error check
765 if(ret != NULL) Object_Dereference(ret); // Free unused value
767 // Clean up variables
768 while(blockInfo.FirstVar)
770 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
771 Variable_Destroy( blockInfo.FirstVar );
772 blockInfo.FirstVar = nextVar;
774 // Clear ret if not an error
775 if(ret != ERRPTR) ret = NULL;
777 // Set parent's return value if needed
778 if( blockInfo.RetVal )
779 Block->RetVal = blockInfo.RetVal;
780 if( blockInfo.BreakTarget ) {
781 Block->BreakTarget = blockInfo.BreakTarget;
782 Block->BreakType = blockInfo.BreakType;
785 // TODO: Unset break if break type deontes a block break
791 case NODETYPE_ASSIGN:
792 // TODO: Support assigning to object attributes
793 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
794 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
797 ret = AST_ExecuteNode(Block, Node->Assign.Value);
798 if(ret == ERRPTR) return ERRPTR;
800 // Perform assignment operation
801 if( Node->Assign.Operation != NODETYPE_NOP )
803 tSpiderValue *varVal, *value;
805 varVal = Variable_GetValue(Block, Node->Assign.Dest);
806 if(varVal == ERRPTR) return ERRPTR;
809 if(varVal && varVal->ReferenceCount == 2) {
810 Object_Dereference(varVal);
811 // printf("pre: (%s) varVal->ReferenceCount = %i\n",
812 // Node->Assign.Dest->Variable.Name,
813 // varVal->ReferenceCount);
816 value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
817 if(value == ERRPTR) return ERRPTR;
819 if(ret) Object_Dereference(ret);
821 if(varVal) Object_Dereference(varVal);
823 if(varVal && varVal->ReferenceCount == 1) {
824 Object_Reference(varVal);
825 // printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
826 break; // If varVal was non-null, it has been updated by _BinOp
829 // Else, it was NULL, so has to be assigned
833 // Set the variable value
834 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
835 Object_Dereference( ret );
840 // Post increment/decrement
841 case NODETYPE_POSTINC:
842 case NODETYPE_POSTDEC:
844 tSpiderValue *varVal, *value;
845 static tSpiderValue one = {
846 .Type = SS_DATATYPE_INTEGER,
851 // TODO: Support assigning to object attributes
852 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
853 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
857 // Get values (current variable contents and a static one)
858 varVal = Variable_GetValue(Block, Node->UniOp.Value);
860 if( Node->Type == NODETYPE_POSTDEC )
861 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_SUBTRACT, varVal, &one);
863 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_ADD, varVal, &one);
864 if( value == ERRPTR )
869 if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
870 Object_Dereference( ret );
873 Object_Dereference( value );
878 case NODETYPE_METHODCALL:
879 case NODETYPE_FUNCTIONCALL:
880 case NODETYPE_CREATEOBJECT:
881 // Logical block (used to allocate `params`)
883 tSpiderNamespace *ns = Block->CurNamespace;
884 tSpiderValue *params[Node->FunctionCall.NumArgs];
886 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
888 params[i] = AST_ExecuteNode(Block, node);
889 if( params[i] == ERRPTR ) {
890 while(i--) Object_Dereference(params[i]);
897 if( !ns ) ns = Block->BaseNamespace;
900 if( Node->Type == NODETYPE_CREATEOBJECT )
902 ret = SpiderScript_CreateObject(Block->Script,
904 Node->FunctionCall.Name,
905 Node->FunctionCall.NumArgs, params
908 else if( Node->Type == NODETYPE_METHODCALL )
910 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
911 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
912 AST_RuntimeError(Node->FunctionCall.Object,
913 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
914 while(i--) Object_Dereference(params[i]);
918 ret = SpiderScript_ExecuteMethod(Block->Script,
919 obj->Object, Node->FunctionCall.Name,
920 Node->FunctionCall.NumArgs, params
922 Object_Dereference(obj);
926 ret = SpiderScript_ExecuteFunction(Block->Script,
927 ns, Node->FunctionCall.Name,
928 Node->FunctionCall.NumArgs, params
933 // Dereference parameters
934 while(i--) Object_Dereference(params[i]);
942 ret = AST_ExecuteNode(Block, Node->If.Condition);
943 if( ret == ERRPTR ) break;
944 if( SpiderScript_IsValueTrue(ret) ) {
945 tmpobj = AST_ExecuteNode(Block, Node->If.True);
948 tmpobj = AST_ExecuteNode(Block, Node->If.False);
950 Object_Dereference(ret);
951 if( tmpobj == ERRPTR ) return ERRPTR;
952 Object_Dereference(tmpobj);
959 ret = AST_ExecuteNode(Block, Node->For.Init);
960 if(ret == ERRPTR) break;
962 // Check initial condition
963 if( !Node->For.bCheckAfter )
965 Object_Dereference(ret);
967 ret = AST_ExecuteNode(Block, Node->For.Condition);
968 if(ret == ERRPTR) return ERRPTR;
969 if(!SpiderScript_IsValueTrue(ret)) {
970 Object_Dereference(ret);
979 Object_Dereference(ret);
982 ret = AST_ExecuteNode(Block, Node->For.Code);
983 if(ret == ERRPTR) return ERRPTR;
984 Object_Dereference(ret);
986 if(Block->BreakTarget)
988 if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
991 free((void*)Block->BreakTarget); Block->BreakTarget = NULL;
992 if( Block->BreakType == NODETYPE_CONTINUE ) {
993 // Continue, just keep going
999 break; // Break out of this loop
1003 ret = AST_ExecuteNode(Block, Node->For.Increment);
1004 if(ret == ERRPTR) return ERRPTR;
1005 Object_Dereference(ret);
1008 ret = AST_ExecuteNode(Block, Node->For.Condition);
1009 if(ret == ERRPTR) return ERRPTR;
1010 if(!SpiderScript_IsValueTrue(ret)) break;
1012 Object_Dereference(ret);
1017 case NODETYPE_RETURN:
1018 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
1019 if(ret == ERRPTR) break;
1020 Block->RetVal = ret; // Return value set
1021 ret = NULL; // the `return` statement does not return a value
1024 case NODETYPE_BREAK:
1025 case NODETYPE_CONTINUE:
1026 Block->BreakTarget = strdup(Node->Variable.Name);
1027 Block->BreakType = Node->Type;
1030 // Define a variable
1031 case NODETYPE_DEFVAR:
1032 if( Node->DefVar.InitialValue ) {
1033 tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
1034 if(tmpobj == ERRPTR) return ERRPTR;
1040 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
1042 Object_Dereference(tmpobj);
1046 case NODETYPE_SCOPE:
1048 tSpiderNamespace *ns;
1050 // Set current namespace if unset
1051 if( !Block->CurNamespace )
1052 Block->CurNamespace = Block->BaseNamespace;
1054 // Empty string means use the root namespace
1055 if( Node->Scope.Name[0] == '\0' )
1057 ns = &Block->Script->Variant->RootNamespace;
1061 // Otherwise scan the current namespace for the element
1062 for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
1064 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
1069 AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
1073 Block->CurNamespace = ns;
1075 ret = AST_ExecuteNode(Block, Node->Scope.Element);
1080 case NODETYPE_VARIABLE:
1081 ret = Variable_GetValue( Block, Node );
1084 // Element of an Object
1085 case NODETYPE_ELEMENT:
1086 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
1087 if(tmpobj == ERRPTR) return ERRPTR;
1088 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
1090 AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
1095 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
1097 if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
1099 ret = tmpobj->Object->Attributes[i];
1100 Object_Reference(ret);
1104 if( i == tmpobj->Object->Type->NAttributes )
1106 AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
1107 Node->Scope.Name, tmpobj->Object->Type->Name);
1112 // Cast a value to another
1115 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
1116 if(tmpobj == ERRPTR) return ERRPTR;
1117 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
1118 Object_Dereference(tmpobj);
1122 // Index into an array
1123 case NODETYPE_INDEX:
1124 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
1125 if(op1 == ERRPTR) return ERRPTR;
1126 op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
1128 Object_Dereference(op1);
1132 if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
1134 // TODO: Implement "operator []" on objects
1135 AST_RuntimeError(Node, "Indexing non-array");
1140 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
1141 AST_RuntimeError(Node, "Array index is not an integer");
1146 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
1148 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
1149 Object_Dereference(op2);
1153 if( op2->Integer >= op1->Array.Length ) {
1154 AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
1155 op2->Integer, op1->Array.Length);
1160 ret = op1->Array.Items[ op2->Integer ];
1161 Object_Reference(ret);
1163 Object_Dereference(op1);
1164 Object_Dereference(op2);
1167 // TODO: Implement runtime constants
1168 case NODETYPE_CONSTANT:
1169 // TODO: Scan namespace for function
1170 AST_RuntimeError(Node, "TODO - Runtime Constants");
1175 case NODETYPE_STRING:
1176 case NODETYPE_INTEGER:
1178 ret = &Node->Constant;
1179 Object_Reference(ret);
1182 // --- Operations ---
1183 // Boolean Operations
1184 case NODETYPE_LOGICALNOT: // Logical NOT (!)
1185 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1186 if(op1 == ERRPTR) return ERRPTR;
1187 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
1188 Object_Dereference(op1);
1190 case NODETYPE_LOGICALAND: // Logical AND (&&)
1191 case NODETYPE_LOGICALOR: // Logical OR (||)
1192 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
1193 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1194 if(op1 == ERRPTR) return ERRPTR;
1195 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1197 Object_Dereference(op1);
1201 switch( Node->Type )
1203 case NODETYPE_LOGICALAND:
1204 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
1206 case NODETYPE_LOGICALOR:
1207 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
1209 case NODETYPE_LOGICALXOR:
1210 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
1215 // Free intermediate objects
1216 Object_Dereference(op1);
1217 Object_Dereference(op2);
1221 case NODETYPE_EQUALS:
1222 case NODETYPE_LESSTHAN:
1223 case NODETYPE_GREATERTHAN:
1224 case NODETYPE_LESSTHANEQUAL:
1225 case NODETYPE_GREATERTHANEQUAL:
1226 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1227 if(op1 == ERRPTR) return ERRPTR;
1228 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1230 Object_Dereference(op1);
1235 if( !op1 || !op2 ) {
1236 AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
1237 if(op1) Object_Dereference(op1);
1238 if(op2) Object_Dereference(op2);
1239 ret = SpiderScript_CreateInteger( !op1 && !op2 );
1244 if( op1->Type != op2->Type ) {
1245 // If dynamically typed, convert op2 to op1's type
1246 if(Block->Script->Variant->bImplicitCasts)
1249 op2 = SpiderScript_CastValueTo(op1->Type, op2);
1250 Object_Dereference(tmpobj);
1252 Object_Dereference(op1);
1256 // If statically typed, this should never happen, but catch it anyway
1258 AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
1259 op1->Type, op2->Type);
1267 // - String Compare (does a strcmp, well memcmp)
1268 case SS_DATATYPE_STRING:
1269 // Call memcmp to do most of the work
1271 op1->String.Data, op2->String.Data,
1272 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
1274 // Handle reaching the end of the string
1276 if( op1->String.Length == op2->String.Length )
1278 else if( op1->String.Length < op2->String.Length )
1285 // - Integer Comparisons
1286 case SS_DATATYPE_INTEGER:
1287 if( op1->Integer == op2->Integer )
1289 else if( op1->Integer < op2->Integer )
1294 // - Real Number Comparisons
1295 case SS_DATATYPE_REAL:
1296 cmp = (op1->Real - op2->Real) / op2->Real * 10000; // < 0.1% difference is equality
1299 AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
1304 // Free intermediate objects
1305 Object_Dereference(op1);
1306 Object_Dereference(op2);
1315 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
1316 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
1317 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
1318 case NODETYPE_LESSTHANEQUAL: ret = SpiderScript_CreateInteger(cmp <= 0); break;
1319 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0); break;
1321 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
1327 // General Unary Operations
1328 case NODETYPE_BWNOT: // Bitwise NOT (~)
1329 case NODETYPE_NEGATE: // Negation (-)
1330 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1331 if(op1 == ERRPTR) return ERRPTR;
1332 ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
1333 Object_Dereference(op1);
1336 // General Binary Operations
1338 case NODETYPE_SUBTRACT:
1339 case NODETYPE_MULTIPLY:
1340 case NODETYPE_DIVIDE:
1341 case NODETYPE_MODULO:
1342 case NODETYPE_BWAND:
1344 case NODETYPE_BWXOR:
1345 case NODETYPE_BITSHIFTLEFT:
1346 case NODETYPE_BITSHIFTRIGHT:
1347 case NODETYPE_BITROTATELEFT:
1349 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1350 if(op1 == ERRPTR) return ERRPTR;
1351 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1353 Object_Dereference(op1);
1357 ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
1359 // Free intermediate objects
1360 Object_Dereference(op1);
1361 Object_Dereference(op2);
1366 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
1370 // Reset namespace when no longer needed
1371 if( Node->Type != NODETYPE_SCOPE )
1372 Block->CurNamespace = NULL;
1374 #if TRACE_NODE_RETURNS
1375 if(ret && ret != ERRPTR) {
1376 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
1379 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
1386 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value)
1390 if( Value->Type == SS_DATATYPE_OBJECT )
1392 const char *fcnname;
1395 case NODETYPE_NEGATE: fcnname = "-ve"; break;
1396 case NODETYPE_BWNOT: fcnname = "~"; break;
1397 default: fcnname = NULL; break;
1402 ret = Object_ExecuteMethod(Value->Object, fcnname, );
1405 // Fall through and try casting (which will usually fail)
1411 // Integer Operations
1412 case SS_DATATYPE_INTEGER:
1413 if( Value->ReferenceCount == 1 )
1414 Object_Reference(ret = Value);
1416 ret = SpiderScript_CreateInteger(0);
1419 case NODETYPE_NEGATE: ret->Integer = -Value->Integer; break;
1420 case NODETYPE_BWNOT: ret->Integer = ~Value->Integer; break;
1422 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1423 Object_Dereference(ret);
1428 // Real number Operations
1429 case SS_DATATYPE_REAL:
1432 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
1434 AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1441 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1449 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1451 tSpiderValue *preCastValue = Right;
1455 if( Left && Right && Left->Type != Right->Type )
1459 // - Operator overload functions
1460 if( Left->Type == SS_DATATYPE_OBJECT )
1462 const char *fcnname;
1465 case NODETYPE_ADD: fcnname = "+"; break;
1466 case NODETYPE_SUBTRACT: fcnname = "-"; break;
1467 case NODETYPE_MULTIPLY: fcnname = "*"; break;
1468 case NODETYPE_DIVIDE: fcnname = "/"; break;
1469 case NODETYPE_MODULO: fcnname = "%"; break;
1470 case NODETYPE_BWAND: fcnname = "&"; break;
1471 case NODETYPE_BWOR: fcnname = "|"; break;
1472 case NODETYPE_BWXOR: fcnname = "^"; break;
1473 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
1474 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
1475 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
1476 default: fcnname = NULL; break;
1481 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1484 // Fall through and try casting (which will usually fail)
1489 // If implicit casts are allowed, convert Right to Left's type
1490 if(Block->Script->Variant->bImplicitCasts)
1492 Right = SpiderScript_CastValueTo(Left->Type, Right);
1496 // If statically typed, this should never happen, but catch it anyway
1498 AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
1504 if( Left == NULL || Right == NULL ) {
1505 if(Right && Right != preCastValue) free(Right);
1512 // String Concatenation
1513 case SS_DATATYPE_STRING:
1516 case NODETYPE_ADD: // Concatenate
1517 ret = Object_StringConcat(Left, Right);
1519 // TODO: Support python style 'i = %i' % i ?
1520 // Might do it via a function call
1521 // case NODETYPE_MODULUS:
1525 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1530 // Integer Operations
1531 case SS_DATATYPE_INTEGER:
1532 if( Left->ReferenceCount == 1 )
1533 Object_Reference(ret = Left);
1535 ret = SpiderScript_CreateInteger(0);
1538 case NODETYPE_ADD: ret->Integer = Left->Integer + Right->Integer; break;
1539 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer; break;
1540 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer; break;
1541 case NODETYPE_DIVIDE: ret->Integer = Left->Integer / Right->Integer; break;
1542 case NODETYPE_MODULO: ret->Integer = Left->Integer % Right->Integer; break;
1543 case NODETYPE_BWAND: ret->Integer = Left->Integer & Right->Integer; break;
1544 case NODETYPE_BWOR: ret->Integer = Left->Integer | Right->Integer; break;
1545 case NODETYPE_BWXOR: ret->Integer = Left->Integer ^ Right->Integer; break;
1546 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer; break;
1547 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer; break;
1548 case NODETYPE_BITROTATELEFT:
1549 ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
1552 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
1553 Object_Dereference(ret);
1560 case SS_DATATYPE_REAL:
1561 if( Left->ReferenceCount == 1 )
1562 Object_Reference(ret = Left);
1564 ret = SpiderScript_CreateReal(0);
1567 case NODETYPE_ADD: ret->Real = Left->Real + Right->Real; break;
1568 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real; break;
1569 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real; break;
1570 case NODETYPE_DIVIDE: ret->Real = Left->Real / Right->Real; break;
1572 AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1573 Object_Dereference(ret);
1580 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1585 if(Right && Right != preCastValue) free(Right);
1591 * \brief Define a variable
1592 * \param Block Current block state
1593 * \param Type Type of the variable
1594 * \param Name Name of the variable
1595 * \return Boolean Failure
1597 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1599 tAST_Variable *var, *prev = NULL;
1601 for( var = Block->FirstVar; var; prev = var, var = var->Next )
1603 if( strcmp(var->Name, Name) == 0 ) {
1604 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1609 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1612 var->Object = Value;
1613 if(Value) Object_Reference(Value);
1614 strcpy(var->Name, Name);
1616 if(prev) prev->Next = var;
1617 else Block->FirstVar = var;
1619 //printf("Defined variable %s (%i)\n", Name, Type);
1624 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1626 tAST_Variable *var = NULL;
1629 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1630 var = VarNode->ValueCache;
1631 #if TRACE_VAR_LOOKUPS
1632 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1633 VarNode->Variable.Name, var,
1634 VarNode->BlockState, VarNode->BlockIdent
1640 tAST_BlockState *bs;
1641 for( bs = Block; bs; bs = bs->Parent )
1643 for( var = bs->FirstVar; var; var = var->Next )
1645 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1653 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1655 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1659 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1664 #if TRACE_VAR_LOOKUPS
1665 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1666 VarNode->Variable.Name, var,
1667 Block, Block->Ident);
1670 VarNode->ValueCache = var;
1671 VarNode->BlockState = Block;
1672 VarNode->BlockIdent = Block->Ident;
1679 * \brief Set the value of a variable
1680 * \return Boolean Failure
1682 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1686 var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1688 if( !var ) return -1;
1690 if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1692 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1693 VarNode->Variable.Name);
1697 // printf("Assign %p to '%s'\n", Value, var->Name);
1698 Object_Reference(Value);
1699 Object_Dereference(var->Object);
1700 var->Object = Value;
1705 * \brief Get the value of a variable
1707 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1709 tAST_Variable *var = Variable_Lookup(Block, VarNode, 0);
1711 if( !var ) return ERRPTR;
1713 Object_Reference(var->Object);
1718 * \brief Destorys a variable
1720 void Variable_Destroy(tAST_Variable *Variable)
1722 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1723 Object_Dereference(Variable->Object);
1727 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
1732 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1734 fprintf(stderr, "%s: ", Type);
1735 va_start(args, Format);
1736 vfprintf(stderr, Format, args);
1738 fprintf(stderr, "\n");
1740 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1745 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1747 fprintf(stderr, "error: ");
1748 va_start(args, Format);
1749 vfprintf(stderr, Format, args);
1751 fprintf(stderr, "\n");