10 extern tSpiderFunction *gpExports_First;
13 void Object_Dereference(tSpiderValue *Object);
14 void Object_Reference(tSpiderValue *Object);
15 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
16 tSpiderValue *SpiderScript_CreateReal(double Value);
17 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
18 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
19 int SpiderScript_IsValueTrue(tSpiderValue *Value);
20 void SpiderScript_FreeValue(tSpiderValue *Value);
21 char *SpiderScript_DumpValue(tSpiderValue *Value);
23 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
24 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right);
25 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, int Operation, tSpiderValue *Value);
27 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
28 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
29 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name);
30 void Variable_Destroy(tAST_Variable *Variable);
32 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
36 * \brief Dereference a created object
38 void Object_Dereference(tSpiderValue *Object)
41 if(Object == ERRPTR) return ;
42 Object->ReferenceCount --;
43 // printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount);
44 if( Object->ReferenceCount == 0 ) {
45 switch( (enum eSpiderScript_DataTypes) Object->Type )
47 case SS_DATATYPE_OBJECT:
48 Object->Object->Type->Destructor( Object->Object );
50 case SS_DATATYPE_OPAQUE:
51 Object->Opaque.Destroy( Object->Opaque.Data );
60 void Object_Reference(tSpiderValue *Object)
63 Object->ReferenceCount ++;
64 // printf("%p Referenced (%i)\n", Object, Object->ReferenceCount);
68 * \brief Allocate and initialise a SpiderScript object
70 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
72 int size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
73 tSpiderObject *ret = malloc(size);
76 ret->ReferenceCount = 1;
77 ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
78 memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
84 * \brief Create an integer object
86 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
88 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
89 ret->Type = SS_DATATYPE_INTEGER;
90 ret->ReferenceCount = 1;
96 * \brief Create an real number object
98 tSpiderValue *SpiderScript_CreateReal(double Value)
100 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
101 ret->Type = SS_DATATYPE_REAL;
102 ret->ReferenceCount = 1;
108 * \brief Create an string object
110 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
112 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
113 ret->Type = SS_DATATYPE_STRING;
114 ret->ReferenceCount = 1;
115 ret->String.Length = Length;
117 memcpy(ret->String.Data, Data, Length);
119 memset(ret->String.Data, 0, Length);
120 ret->String.Data[Length] = '\0';
125 * \brief Concatenate two strings
127 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
131 if(Str1) newLen += Str1->String.Length;
132 if(Str2) newLen += Str2->String.Length;
133 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
134 ret->Type = SS_DATATYPE_STRING;
135 ret->ReferenceCount = 1;
136 ret->String.Length = newLen;
138 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
141 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
143 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
145 ret->String.Data[ newLen ] = '\0';
150 * \brief Cast one object to another
151 * \brief Type Destination type
152 * \brief Source Input data
154 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
156 tSpiderValue *ret = ERRPTR;
163 case SS_DATATYPE_INTEGER: return SpiderScript_CreateInteger(0);
164 case SS_DATATYPE_REAL: return SpiderScript_CreateReal(0);
165 case SS_DATATYPE_STRING: return SpiderScript_CreateString(4, "null");
170 // Check if anything needs to be done
171 if( Source->Type == Type ) {
172 Object_Reference(Source);
178 printf("Casting %i ", Source->Type);
181 case SS_DATATYPE_INTEGER: printf("0x%lx", Source->Integer); break;
182 case SS_DATATYPE_STRING: printf("\"%s\"", Source->String.Data); break;
183 case SS_DATATYPE_REAL: printf("%f", Source->Real); break;
186 printf(" to %i\n", Type);
191 if( Source->Type == SS_DATATYPE_OBJECT )
193 const char *name = NULL;
196 case SS_DATATYPE_INTEGER: name = "cast Integer"; break;
197 case SS_DATATYPE_REAL: name = "cast Real"; break;
198 case SS_DATATYPE_STRING: name = "cast String"; break;
199 case SS_DATATYPE_ARRAY: name = "cast Array"; break;
201 AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
206 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
209 // Fall through and try casting (which will usually fail)
214 switch( (enum eSpiderScript_DataTypes)Type )
216 case SS_DATATYPE_UNDEF:
217 case SS_DATATYPE_ARRAY:
218 case SS_DATATYPE_OPAQUE:
219 case SS_DATATYPE_OBJECT:
220 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
223 case SS_DATATYPE_INTEGER:
224 ret = malloc(sizeof(tSpiderValue));
225 ret->Type = SS_DATATYPE_INTEGER;
226 ret->ReferenceCount = 1;
229 case SS_DATATYPE_INTEGER: break; // Handled above
230 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
231 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
233 AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
240 case SS_DATATYPE_REAL:
241 ret = malloc(sizeof(tSpiderValue));
242 ret->Type = SS_DATATYPE_REAL;
243 ret->ReferenceCount = 1;
246 case SS_DATATYPE_STRING: ret->Real = atof(Source->String.Data); break;
247 case SS_DATATYPE_INTEGER: ret->Real = Source->Integer; break;
249 AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
256 case SS_DATATYPE_STRING:
259 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
260 case SS_DATATYPE_REAL: len = snprintf(NULL, 0, "%g", Source->Real); break;
263 ret = malloc(sizeof(tSpiderValue) + len + 1);
264 ret->Type = SS_DATATYPE_STRING;
265 ret->ReferenceCount = 1;
266 ret->String.Length = len;
269 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
270 case SS_DATATYPE_REAL:
271 sprintf(ret->String.Data, "%g", Source->Real); break;
273 AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
281 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
290 * \brief Condenses a value down to a boolean
292 int SpiderScript_IsValueTrue(tSpiderValue *Value)
294 if( Value == ERRPTR ) return 0;
295 if( Value == NULL ) return 0;
297 switch( (enum eSpiderScript_DataTypes)Value->Type )
299 case SS_DATATYPE_UNDEF:
302 case SS_DATATYPE_INTEGER:
303 return !!Value->Integer;
305 case SS_DATATYPE_REAL:
306 return (-.5f < Value->Real && Value->Real < 0.5f);
308 case SS_DATATYPE_STRING:
309 return Value->String.Length > 0;
311 case SS_DATATYPE_OBJECT:
312 return Value->Object != NULL;
314 case SS_DATATYPE_OPAQUE:
315 return Value->Opaque.Data != NULL;
317 case SS_DATATYPE_ARRAY:
318 return Value->Array.Length > 0;
320 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
327 * \brief Free a value
328 * \note Just calls Object_Dereference
330 void SpiderScript_FreeValue(tSpiderValue *Value)
332 Object_Dereference(Value);
336 * \brief Dump a value into a string
337 * \return Heap string
339 char *SpiderScript_DumpValue(tSpiderValue *Value)
342 if( Value == ERRPTR )
343 return strdup("ERRPTR");
345 return strdup("null");
347 switch( (enum eSpiderScript_DataTypes)Value->Type )
349 case SS_DATATYPE_UNDEF: return strdup("undefined");
351 case SS_DATATYPE_INTEGER:
352 ret = malloc( sizeof(Value->Integer)*2 + 3 );
353 sprintf(ret, "0x%lx", Value->Integer);
356 case SS_DATATYPE_REAL:
357 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
358 sprintf(ret, "%f", Value->Real);
361 case SS_DATATYPE_STRING:
362 ret = malloc( Value->String.Length + 3 );
364 strcpy(ret+1, Value->String.Data);
365 ret[Value->String.Length+1] = '"';
366 ret[Value->String.Length+2] = '\0';
369 case SS_DATATYPE_OBJECT:
370 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
371 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
374 case SS_DATATYPE_OPAQUE:
375 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
376 sprintf(ret, "*%p", Value->Opaque.Data);
379 case SS_DATATYPE_ARRAY:
380 return strdup("Array");
383 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
390 * \brief Execute a script function
391 * \param Script Script context to execute in
392 * \param Function Function name to execute
393 * \param NArguments Number of arguments to pass
394 * \param Arguments Arguments passed
396 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
397 tSpiderNamespace *Namespace, const char *Function,
398 int NArguments, tSpiderValue **Arguments)
400 char *trueName = NULL;
401 int bFound = 0; // Used to keep nesting levels down
402 tSpiderValue *ret = ERRPTR;
403 tSpiderFunction *fcn;
405 // First: Find the function in the script
407 tAST_Function *astFcn;
408 for( astFcn = Script->Script->Functions; astFcn; astFcn = astFcn->Next )
410 if( strcmp(astFcn->Name, Function) == 0 )
420 // Build a block State
424 bs.BaseNamespace = &Script->Variant->RootNamespace;
425 bs.CurNamespace = NULL;
429 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
432 Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
433 if( i >= NArguments ) break; // TODO: Return gracefully
434 Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
438 ret = AST_ExecuteNode(&bs, astFcn->Code);
439 Object_Dereference(ret); // Dereference output of last block statement
440 ret = bs.RetVal; // Set to return value of block
445 tAST_Variable *nextVar = bs.FirstVar->Next;
446 Variable_Destroy( bs.FirstVar );
447 bs.FirstVar = nextVar;
452 // Didn't find it in script?
455 fcn = NULL; // Just to allow the below code to be neat
457 // Second: Scan current namespace
458 if( !fcn && Namespace )
460 for( fcn = Namespace->Functions; fcn; fcn = fcn->Next )
462 if( strcmp( fcn->Name, Function ) == 0 )
467 // Third: Search the variant's global exports
470 for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
472 if( strcmp( fcn->Name, Function ) == 0 )
477 // Fourth: Search language exports
480 for( fcn = gpExports_First; fcn; fcn = fcn->Next )
482 if( strcmp( fcn->Name, Function ) == 0 )
490 // TODO: Type Checking
491 ret = fcn->Handler( Script, NArguments, Arguments );
499 fprintf(stderr, "Undefined reference to '%s'\n", trueName);
507 * \brief Execute an object method function
508 * \param Script Script context to execute in
509 * \param Function Function name to execute
510 * \param NArguments Number of arguments to pass
511 * \param Arguments Arguments passed
513 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script, tSpiderObject *Object,
514 const char *MethodName,
515 int NArguments, tSpiderValue **Arguments)
517 tSpiderFunction *fcn;
519 tSpiderValue *newargs[NArguments+1];
522 for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
524 if( strcmp(fcn->Name, MethodName) == 0 )
530 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
531 Object->Type->Name, MethodName);
535 this.Type = SS_DATATYPE_OBJECT;
536 this.ReferenceCount = 1;
537 this.Object = Object;
540 memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
542 // TODO: Type Checking
543 for( i = 0; fcn->ArgTypes[i]; i ++ )
545 if( i >= NArguments ) {
546 AST_RuntimeError(NULL, "Argument count mismatch (%i passed)",
550 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
552 AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
553 Arguments[i]->Type, fcn->ArgTypes[i]);
558 return fcn->Handler(Script, NArguments+1, newargs);
562 * \brief Execute a script function
563 * \param Script Script context to execute in
564 * \param Function Function name to execute
565 * \param NArguments Number of arguments to pass
566 * \param Arguments Arguments passed
568 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
569 tSpiderNamespace *Namespace, const char *ClassName,
570 int NArguments, tSpiderValue **Arguments)
572 int bFound = 0; // Used to keep nesting levels down
573 tSpiderValue *ret = ERRPTR;
574 tSpiderObjectDef *class;
576 // First: Find the function in the script
577 // TODO: Implement scripted classes
580 tAST_Function *astClass;
581 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
583 if( strcmp(astClass->Name, ClassName) == 0 )
593 // Build a block State
597 bs.BaseNamespace = &Script->Variant->RootNamespace;
598 bs.CurNamespace = NULL;
602 for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
605 Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
606 if( i >= NArguments ) break; // TODO: Return gracefully
607 Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
611 ret = AST_ExecuteNode(&bs, astFcn->Code);
612 Object_Dereference(ret); // Dereference output of last block statement
613 ret = bs.RetVal; // Set to return value of block
618 tAST_Variable *nextVar = bs.FirstVar->Next;
619 Variable_Destroy( bs.FirstVar );
620 bs.FirstVar = nextVar;
626 // Didn't find it in script?
629 class = NULL; // Just to allow the below code to be neat
631 // Second: Scan current namespace
632 if( !class && Namespace )
634 for( class = Namespace->Classes; class; class = class->Next )
636 if( strcmp( class->Name, ClassName ) == 0 )
642 // Third: Search the variant's global exports
645 for( class = Script->Variant->Classes; class; class = fcn->Next )
647 if( strcmp( class->Name, Function ) == 0 )
654 // Fourth: Search language exports
657 for( class = gpExports_First; class; class = fcn->Next )
659 if( strcmp( class->Name, ClassName ) == 0 )
669 // TODO: Type Checking
670 obj = class->Constructor( NArguments, Arguments );
671 if( obj == NULL || obj == ERRPTR )
674 ret = malloc( sizeof(tSpiderValue) );
675 ret->Type = SS_DATATYPE_OBJECT;
676 ret->ReferenceCount = 1;
685 fprintf(stderr, "Undefined reference to '%s'\n", ClassName);
694 * \brief Execute an AST node and return its value
696 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
699 tSpiderValue *ret = NULL, *tmpobj;
700 tSpiderValue *op1, *op2; // Binary operations
701 int cmp; // Used in comparisons
707 case NODETYPE_NOP: ret = NULL; break;
712 tAST_BlockState blockInfo;
713 blockInfo.Parent = Block;
714 blockInfo.Script = Block->Script;
715 blockInfo.FirstVar = NULL;
716 blockInfo.RetVal = NULL;
717 blockInfo.BaseNamespace = Block->BaseNamespace;
718 blockInfo.CurNamespace = NULL;
720 for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
722 ret = AST_ExecuteNode(&blockInfo, node);
723 if(ret == ERRPTR) { // Error check
726 if(ret) Object_Dereference(ret); // Free unused value
728 // Clean up variables
729 while(blockInfo.FirstVar)
731 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
732 Variable_Destroy( blockInfo.FirstVar );
733 blockInfo.FirstVar = nextVar;
737 if( blockInfo.RetVal )
738 Block->RetVal = blockInfo.RetVal;
744 case NODETYPE_ASSIGN:
745 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
746 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
749 ret = AST_ExecuteNode(Block, Node->Assign.Value);
753 if( Node->Assign.Operation != NODETYPE_NOP )
755 tSpiderValue *varVal = Variable_GetValue(Block, Node->Assign.Dest->Variable.Name);
757 value = AST_ExecuteNode_BinOp(Block, Node->Assign.Operation, varVal, ret);
758 if( value == ERRPTR )
760 if(ret) Object_Dereference(ret);
761 if(varVal) Object_Dereference(varVal);
765 if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) {
766 Object_Dereference( ret );
771 case NODETYPE_POSTINC:
772 case NODETYPE_POSTDEC:
774 tSpiderValue *varVal, *value, *one;
775 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
776 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
780 varVal = Variable_GetValue(Block, Node->Assign.Dest->Variable.Name);
781 one = SpiderScript_CreateInteger(1);
783 if( Node->Type == NODETYPE_POSTDEC )
784 value = AST_ExecuteNode_BinOp(Block, NODETYPE_SUBTRACT, varVal, one);
786 value = AST_ExecuteNode_BinOp(Block, NODETYPE_ADD, varVal, one);
787 if( value == ERRPTR )
789 Object_Dereference(one); // Free constant one
793 if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, value ) ) {
794 Object_Dereference( ret );
797 Object_Dereference( value );
802 case NODETYPE_METHODCALL:
803 case NODETYPE_FUNCTIONCALL:
804 case NODETYPE_CREATEOBJECT:
805 // Logical block (used to allocate `params`)
807 tSpiderValue *params[Node->FunctionCall.NumArgs];
809 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
811 params[i] = AST_ExecuteNode(Block, node);
812 if( params[i] == ERRPTR ) {
813 while(i--) Object_Dereference(params[i]);
820 if( !Block->CurNamespace )
821 Block->CurNamespace = Block->BaseNamespace;
824 if( Node->Type == NODETYPE_CREATEOBJECT )
826 ret = SpiderScript_CreateObject(Block->Script,
828 Node->FunctionCall.Name,
829 Node->FunctionCall.NumArgs, params
832 else if( Node->Type == NODETYPE_METHODCALL )
834 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
835 if( !obj || obj->Type != SS_DATATYPE_OBJECT ) {
836 AST_RuntimeError(Node->FunctionCall.Object,
837 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
838 while(i--) Object_Dereference(params[i]);
842 ret = SpiderScript_ExecuteMethod(Block->Script,
843 obj->Object, Node->FunctionCall.Name,
844 Node->FunctionCall.NumArgs, params
846 Object_Dereference(obj);
850 ret = SpiderScript_ExecuteFunction(Block->Script,
851 Block->CurNamespace, Node->FunctionCall.Name,
852 Node->FunctionCall.NumArgs, params
857 // Dereference parameters
858 while(i--) Object_Dereference(params[i]);
866 ret = AST_ExecuteNode(Block, Node->If.Condition);
867 if( SpiderScript_IsValueTrue(ret) ) {
868 Object_Dereference(AST_ExecuteNode(Block, Node->If.True));
871 Object_Dereference(AST_ExecuteNode(Block, Node->If.False));
873 Object_Dereference(ret);
879 ret = AST_ExecuteNode(Block, Node->For.Init);
880 if( Node->For.bCheckAfter )
883 Object_Dereference(ret);
884 ret = AST_ExecuteNode(Block, Node->For.Code);
885 Object_Dereference(ret);
886 ret = AST_ExecuteNode(Block, Node->For.Increment);
887 Object_Dereference(ret);
888 ret = AST_ExecuteNode(Block, Node->For.Condition);
889 } while( SpiderScript_IsValueTrue(ret) );
893 Object_Dereference(ret);
894 ret = AST_ExecuteNode(Block, Node->For.Condition);
895 while( SpiderScript_IsValueTrue(ret) ) {
896 Object_Dereference(ret);
897 ret = AST_ExecuteNode(Block, Node->For.Code);
898 Object_Dereference(ret);
899 ret = AST_ExecuteNode(Block, Node->For.Increment);
900 Object_Dereference(ret);
901 ret = AST_ExecuteNode(Block, Node->For.Condition);
904 Object_Dereference(ret);
909 case NODETYPE_RETURN:
910 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
911 Block->RetVal = ret; // Return value set
912 ret = NULL; // the `return` statement does not return a value
916 case NODETYPE_DEFVAR:
918 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
925 tSpiderNamespace *ns;
927 // Set current namespace if unset
928 if( !Block->CurNamespace )
929 Block->CurNamespace = Block->BaseNamespace;
931 // Empty string means use the root namespace
932 if( Node->Scope.Name[0] == '\0' )
934 ns = &Block->Script->Variant->RootNamespace;
938 // Otherwise scan the current namespace for the element
939 for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
941 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
946 AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
950 Block->CurNamespace = ns;
952 ret = AST_ExecuteNode(Block, Node->Scope.Element);
957 case NODETYPE_VARIABLE:
958 ret = Variable_GetValue( Block, Node->Variable.Name );
961 // Element of an Object
962 case NODETYPE_ELEMENT:
963 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
964 if( tmpobj->Type != SS_DATATYPE_OBJECT )
966 AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
971 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
973 if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
975 ret = tmpobj->Object->Attributes[i];
976 Object_Reference(ret);
980 if( i == tmpobj->Object->Type->NAttributes )
982 AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
983 Node->Scope.Name, tmpobj->Object->Type->Name);
988 // Cast a value to another
991 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
992 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
993 Object_Dereference(tmpobj);
997 // Index into an array
999 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
1000 op2 = AST_ExecuteNode(Block, Node->BinOp.Right); // Offset
1002 if( op1->Type != SS_DATATYPE_ARRAY )
1004 // TODO: Implement "operator []" on objects
1005 AST_RuntimeError(Node, "Indexing non-array");
1010 if( op2->Type != SS_DATATYPE_INTEGER && !Block->Script->Variant->bImplicitCasts ) {
1011 AST_RuntimeError(Node, "Array index is not an integer");
1016 if( op2->Type != SS_DATATYPE_INTEGER )
1018 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
1019 Object_Dereference(op2);
1023 if( op2->Integer >= op1->Array.Length ) {
1024 AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
1025 op2->Integer, op1->Array.Length);
1030 ret = op1->Array.Items[ op2->Integer ];
1031 Object_Reference(ret);
1033 Object_Dereference(op1);
1034 Object_Dereference(op2);
1037 // TODO: Implement runtime constants
1038 case NODETYPE_CONSTANT:
1039 // TODO: Scan namespace for function
1040 AST_RuntimeError(Node, "TODO - Runtime Constants");
1045 case NODETYPE_STRING: ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data ); break;
1046 case NODETYPE_INTEGER: ret = SpiderScript_CreateInteger( Node->Integer ); break;
1047 case NODETYPE_REAL: ret = SpiderScript_CreateReal( Node->Real ); break;
1049 // --- Operations ---
1050 // Boolean Operations
1051 case NODETYPE_LOGICALNOT: // Logical NOT (!)
1052 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1053 if(op1 == ERRPTR) return ERRPTR;
1054 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
1055 Object_Dereference(op1);
1057 case NODETYPE_LOGICALAND: // Logical AND (&&)
1058 case NODETYPE_LOGICALOR: // Logical OR (||)
1059 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
1060 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1061 if(op1 == ERRPTR) return ERRPTR;
1062 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1064 Object_Dereference(op1);
1068 switch( Node->Type )
1070 case NODETYPE_LOGICALAND:
1071 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
1073 case NODETYPE_LOGICALOR:
1074 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
1076 case NODETYPE_LOGICALXOR:
1077 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
1082 // Free intermediate objects
1083 Object_Dereference(op1);
1084 Object_Dereference(op2);
1088 case NODETYPE_EQUALS:
1089 case NODETYPE_LESSTHAN:
1090 case NODETYPE_GREATERTHAN:
1091 case NODETYPE_LESSTHANEQUAL:
1092 case NODETYPE_GREATERTHANEQUAL:
1093 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1094 if(op1 == ERRPTR) return ERRPTR;
1095 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1097 Object_Dereference(op1);
1102 if( !op1 || !op2 ) {
1103 AST_RuntimeError(Node, "NULL Comparison (%p and %p)\n", op1, op2);
1104 if(op1) Object_Dereference(op1);
1105 if(op2) Object_Dereference(op2);
1106 ret = SpiderScript_CreateInteger( !op1 && !op2 );
1111 if( op1->Type != op2->Type ) {
1112 // If dynamically typed, convert op2 to op1's type
1113 if(Block->Script->Variant->bDyamicTyped)
1116 op2 = SpiderScript_CastValueTo(op1->Type, op2);
1117 Object_Dereference(tmpobj);
1119 Object_Dereference(op1);
1123 // If statically typed, this should never happen, but catch it anyway
1125 AST_RuntimeError(Node, "Statically typed implicit cast");
1133 // - String Compare (does a strcmp, well memcmp)
1134 case SS_DATATYPE_STRING:
1135 // Call memcmp to do most of the work
1137 op1->String.Data, op2->String.Data,
1138 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
1140 // Handle reaching the end of the string
1142 if( op1->String.Length == op2->String.Length )
1144 else if( op1->String.Length < op2->String.Length )
1151 // - Integer Comparisons
1152 case SS_DATATYPE_INTEGER:
1153 if( op1->Integer == op2->Integer )
1155 else if( op1->Integer < op2->Integer )
1160 // - Real Number Comparisons
1161 case SS_DATATYPE_REAL:
1162 cmp = (op1->Real - op2->Real) / op2->Real * 10000; // < 0.1% difference is equality
1165 AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
1170 // Free intermediate objects
1171 Object_Dereference(op1);
1172 Object_Dereference(op2);
1181 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
1182 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
1183 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
1184 case NODETYPE_LESSTHANEQUAL: ret = SpiderScript_CreateInteger(cmp <= 0); break;
1185 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0); break;
1187 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
1193 // General Unary Operations
1194 case NODETYPE_BWNOT: // Bitwise NOT (~)
1195 case NODETYPE_NEGATE: // Negation (-)
1196 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1197 if(op1 == ERRPTR) return ERRPTR;
1198 ret = AST_ExecuteNode_UniOp(Block, Node->Type, op1);
1199 Object_Dereference(op1);
1202 // General Binary Operations
1204 case NODETYPE_SUBTRACT:
1205 case NODETYPE_MULTIPLY:
1206 case NODETYPE_DIVIDE:
1207 case NODETYPE_MODULO:
1208 case NODETYPE_BWAND:
1210 case NODETYPE_BWXOR:
1211 case NODETYPE_BITSHIFTLEFT:
1212 case NODETYPE_BITSHIFTRIGHT:
1213 case NODETYPE_BITROTATELEFT:
1215 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1216 if(op1 == ERRPTR) return ERRPTR;
1217 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1219 Object_Dereference(op1);
1223 ret = AST_ExecuteNode_BinOp(Block, Node->Type, op1, op2);
1225 // Free intermediate objects
1226 Object_Dereference(op1);
1227 Object_Dereference(op2);
1232 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
1239 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, int Operation, tSpiderValue *Value)
1243 if( Value->Type == SS_DATATYPE_OBJECT )
1245 const char *fcnname;
1248 case NODETYPE_NEGATE: fcnname = "-ve"; break;
1249 case NODETYPE_BWNOT: fcnname = "~"; break;
1250 default: fcnname = NULL; break;
1255 ret = Object_ExecuteMethod(Value->Object, fcnname, );
1258 // Fall through and try casting (which will usually fail)
1264 // Integer Operations
1265 case SS_DATATYPE_INTEGER:
1268 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Integer ); break;
1269 case NODETYPE_BWNOT: ret = SpiderScript_CreateInteger( ~Value->Integer ); break;
1271 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1276 // Real number Operations
1277 case SS_DATATYPE_REAL:
1280 case NODETYPE_NEGATE: ret = SpiderScript_CreateInteger( -Value->Real ); break;
1282 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1289 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1297 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1299 tSpiderValue *preCastValue = Right;
1303 if( Left && Right && Left->Type != Right->Type )
1307 // - Operator overload functions
1308 if( Left->Type == SS_DATATYPE_OBJECT )
1310 const char *fcnname;
1313 case NODETYPE_ADD: fcnname = "+"; break;
1314 case NODETYPE_SUBTRACT: fcnname = "-"; break;
1315 case NODETYPE_MULTIPLY: fcnname = "*"; break;
1316 case NODETYPE_DIVIDE: fcnname = "/"; break;
1317 case NODETYPE_MODULO: fcnname = "%"; break;
1318 case NODETYPE_BWAND: fcnname = "&"; break;
1319 case NODETYPE_BWOR: fcnname = "|"; break;
1320 case NODETYPE_BWXOR: fcnname = "^"; break;
1321 case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break;
1322 case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break;
1323 case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break;
1324 default: fcnname = NULL; break;
1329 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1332 // Fall through and try casting (which will usually fail)
1337 // If implicit casts are allowed, convert Right to Left's type
1338 if(Block->Script->Variant->bImplicitCasts)
1340 Right = SpiderScript_CastValueTo(Left->Type, Right);
1344 // If statically typed, this should never happen, but catch it anyway
1346 AST_RuntimeError(NULL, "Implicit cast not allowed (from %i to %i)\n", Right->Type, Left->Type);
1352 if( Left == NULL || Right == NULL ) {
1353 if(Right && Right != preCastValue) free(Right);
1360 // String Concatenation
1361 case SS_DATATYPE_STRING:
1364 case NODETYPE_ADD: // Concatenate
1365 ret = Object_StringConcat(Left, Right);
1368 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1373 // Integer Operations
1374 case SS_DATATYPE_INTEGER:
1377 case NODETYPE_ADD: ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer ); break;
1378 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer ); break;
1379 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer ); break;
1380 case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer ); break;
1381 case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer ); break;
1382 case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer ); break;
1383 case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer ); break;
1384 case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer ); break;
1385 case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer ); break;
1386 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer ); break;
1387 case NODETYPE_BITROTATELEFT:
1388 ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) );
1391 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Operation);
1398 case SS_DATATYPE_REAL:
1401 case NODETYPE_ADD: ret = SpiderScript_CreateReal( Left->Real + Right->Real ); break;
1402 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateReal( Left->Real - Right->Real ); break;
1403 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateReal( Left->Real * Right->Real ); break;
1404 case NODETYPE_DIVIDE: ret = SpiderScript_CreateReal( Left->Real / Right->Real ); break;
1406 AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1413 AST_RuntimeError(NULL, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1418 if(Right && Right != preCastValue) free(Right);
1424 * \brief Define a variable
1425 * \param Block Current block state
1426 * \param Type Type of the variable
1427 * \param Name Name of the variable
1428 * \return Boolean Failure
1430 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
1432 tAST_Variable *var, *prev = NULL;
1434 for( var = Block->FirstVar; var; prev = var, var = var->Next )
1436 if( strcmp(var->Name, Name) == 0 ) {
1437 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1442 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1446 strcpy(var->Name, Name);
1448 if(prev) prev->Next = var;
1449 else Block->FirstVar = var;
1451 //printf("Defined variable %s (%i)\n", Name, Type);
1457 * \brief Set the value of a variable
1458 * \return Boolean Failure
1460 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
1463 tAST_BlockState *bs;
1465 for( bs = Block; bs; bs = bs->Parent )
1467 for( var = bs->FirstVar; var; var = var->Next )
1469 if( strcmp(var->Name, Name) == 0 )
1471 if( !Block->Script->Variant->bDyamicTyped
1472 && (Value && var->Type != Value->Type) )
1474 AST_RuntimeError(NULL, "Type mismatch assigning to '%s'", Name);
1477 // printf("Assign %p to '%s'\n", Value, var->Name);
1478 Object_Reference(Value);
1479 Object_Dereference(var->Object);
1480 var->Object = Value;
1486 if( Block->Script->Variant->bDyamicTyped )
1489 var = Variable_Define(Block, Value->Type, Name);
1490 Object_Reference(Value);
1491 var->Object = Value;
1496 AST_RuntimeError(NULL, "Variable '%s' set while undefined", Name);
1502 * \brief Get the value of a variable
1504 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
1507 tAST_BlockState *bs;
1509 for( bs = Block; bs; bs = bs->Parent )
1511 for( var = bs->FirstVar; var; var = var->Next )
1513 if( strcmp(var->Name, Name) == 0 ) {
1514 Object_Reference(var->Object);
1521 AST_RuntimeError(NULL, "Variable '%s' used undefined", Name);
1527 * \brief Destorys a variable
1529 void Variable_Destroy(tAST_Variable *Variable)
1531 // printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1532 Object_Dereference(Variable->Object);
1536 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1540 fprintf(stderr, "ERROR: ");
1541 va_start(args, Format);
1542 vfprintf(stderr, Format, args);
1544 fprintf(stderr, "\n");
1548 fprintf(stderr, " at %s:%i\n", Node->File, Node->Line);