8 #define ERRPTR ((void*)((intptr_t)0-1))
11 void Object_Dereference(tSpiderVariable *Object);
12 void Object_Reference(tSpiderVariable *Object);
13 tSpiderVariable *Object_CreateInteger(uint64_t Value);
14 tSpiderVariable *Object_CreateReal(double Value);
15 tSpiderVariable *Object_CreateString(int Length, const char *Data);
16 tSpiderVariable *Object_CastTo(int Type, tSpiderVariable *Source);
17 int Object_IsTrue(tSpiderVariable *Value);
19 void Variable_SetValue(tSpiderScript *Script, const char *Name, tSpiderVariable *Value);
20 tSpiderVariable *Variable_GetValue(tSpiderScript *Script, const char *Name);
24 * \brief Dereference a created object
26 void Object_Dereference(tSpiderVariable *Object)
28 Object->ReferenceCount --;
29 if( Object->ReferenceCount == 0 ) free(Object);
32 void Object_Reference(tSpiderVariable *Object)
34 Object->ReferenceCount ++;
38 * \brief Create an integer object
40 tSpiderVariable *Object_CreateInteger(uint64_t Value)
42 tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
43 ret->Type = SS_DATATYPE_INTEGER;
44 ret->ReferenceCount = 1;
50 * \brief Create an real number object
52 tSpiderVariable *Object_CreateReal(double Value)
54 tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
55 ret->Type = SS_DATATYPE_REAL;
56 ret->ReferenceCount = 1;
62 * \brief Create an string object
64 tSpiderVariable *Object_CreateString(int Length, const char *Data)
66 tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) + Length + 1 );
67 ret->Type = SS_DATATYPE_STRING;
68 ret->ReferenceCount = 1;
69 ret->String.Length = Length;
70 memcpy(ret->String.Data, Data, Length);
71 ret->String.Data[Length] = '\0';
77 tSpiderVariable *Object_CastTo(int Type, tSpiderVariable *Source)
80 // Check if anything needs to be done
81 if( Source->Type == Type ) {
82 Object_Reference(Source);
88 case SS_DATATYPE_UNDEF:
89 case SS_DATATYPE_NULL:
90 case SS_DATATYPE_ARRAY:
91 fprintf(stderr, "Object_CastTo - Invalid cast to %i\n", Type);
94 case SS_DATATYPE_INTEGER:
95 ret = malloc(sizeof(tSpiderVariable));
96 ret->Type = SS_DATATYPE_INTEGER;
97 ret->ReferenceCount = 1;
100 case SS_DATATYPE_INTEGER: break; // Handled above
101 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
102 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
104 fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
114 * \brief Condenses a value down to a boolean
116 int Object_IsTrue(tSpiderVariable *Value)
120 case SS_DATATYPE_UNDEF:
121 case SS_DATATYPE_NULL:
124 case SS_DATATYPE_INTEGER:
125 return !!Value->Integer;
127 case SS_DATATYPE_REAL:
128 return (-.5f < Value->Real && Value->Real < 0.5f);
130 case SS_DATATYPE_STRING:
131 return Value->String.Length > 0;
133 case SS_DATATYPE_OBJECT:
134 return Value->Object != NULL;
136 case SS_DATATYPE_ARRAY:
137 return Value->Array.Length > 0;
142 tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
145 tSpiderVariable *ret, *tmpvar;
146 tSpiderVariable *op1, *op2; // Binary operations
147 int cmp; // Used in comparisons
152 case NODETYPE_NOP: ret = NULL; break ;
157 for(node = Node->Block.FirstChild; node; node = node->NextSibling )
159 if(node->Type == NODETYPE_RETURN) {
160 ret = AST_ExecuteNode(Script, node);
164 tmpvar = AST_ExecuteNode(Script, node);
165 if(tmpvar == ERRPTR) return ERRPTR; // Error check
166 if(tmpvar) Object_Dereference(tmpvar); // Free unused value
172 case NODETYPE_ASSIGN:
173 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
174 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
177 ret = AST_ExecuteNode(Script, Node->Assign.Value);
178 // TODO: Apply operation
179 Variable_SetValue( Script, Node->Assign.Dest->Variable.Name, ret );
182 case NODETYPE_FUNCTIONCALL:
183 // TODO: Find a function from the export list in variant
184 //SpiderScript_ExecuteMethod(Script, Node->FunctionCall.Name
186 fprintf(stderr, "TODO: Implement function calls\n");
189 // Return's special handling happens elsewhere
190 case NODETYPE_RETURN:
191 ret = AST_ExecuteNode(Script, Node->UniOp.Value);
195 case NODETYPE_VARIABLE: ret = Variable_GetValue( Script, Node->Variable.Name ); break;
197 // TODO: Implement runtime constants
198 case NODETYPE_CONSTANT: ret = ERRPTR; break;
200 case NODETYPE_STRING: ret = Object_CreateString( Node->String.Length, Node->String.Data ); break;
201 case NODETYPE_INTEGER: ret = Object_CreateInteger( Node->Integer ); break;
202 case NODETYPE_REAL: ret = Object_CreateReal( Node->Real ); break;
204 // --- Operations ---
205 // Boolean Operations
206 case NODETYPE_LOGICALAND: // Logical AND (&&)
207 case NODETYPE_LOGICALOR: // Logical OR (||)
208 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
209 op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
210 op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
213 case NODETYPE_LOGICALAND:
214 ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
216 case NODETYPE_LOGICALOR:
217 ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
219 case NODETYPE_LOGICALXOR:
220 ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
227 case NODETYPE_EQUALS:
228 case NODETYPE_LESSTHAN:
229 case NODETYPE_GREATERTHAN:
230 op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
231 op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
233 // No conversion done for NULL
234 // TODO: Determine if this will ever be needed
235 if( op1->Type == SS_DATATYPE_NULL )
237 // NULLs always typecheck
238 ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
243 if( op1->Type != op2->Type ) {
244 // If dynamically typed, convert op2 to op1's type
245 if(Script->Variant->bDyamicTyped)
248 op2 = Object_CastTo(op1->Type, op2);
249 Object_Dereference(tmpvar);
251 // If statically typed, this should never happen, but catch it anyway
261 case SS_DATATYPE_NULL: break;
262 // - String Compare (does a strcmp, well memcmp)
263 case SS_DATATYPE_STRING:
264 // Call memcmp to do most of the work
266 op1->String.Data, op2->String.Data,
267 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
269 // Handle reaching the end of the string
271 if( op1->String.Length == op2->String.Length )
273 else if( op1->String.Length < op2->String.Length )
281 // Free intermediate objects
282 Object_Dereference(op1);
283 Object_Dereference(op2);
288 case NODETYPE_EQUALS: ret = Object_CreateInteger(cmp == 0); break;
289 case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0); break;
290 case NODETYPE_GREATERTHAN: ret = Object_CreateInteger(cmp > 0); break;
292 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
298 // General Binary Operations
300 case NODETYPE_SUBTRACT:
301 case NODETYPE_MULTIPLY:
302 case NODETYPE_DIVIDE:
303 case NODETYPE_MODULO:
307 case NODETYPE_BITSHIFTLEFT:
308 case NODETYPE_BITSHIFTRIGHT:
309 case NODETYPE_BITROTATELEFT:
311 op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
312 op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
315 if( op1->Type != op2->Type ) {
316 // If dynamically typed, convert op2 to op1's type
317 if(Script->Variant->bDyamicTyped)
320 op2 = Object_CastTo(op1->Type, op2);
321 Object_Dereference(tmpvar);
323 // If statically typed, this should never happen, but catch it anyway
333 case SS_DATATYPE_NULL: break;
334 // String Concatenation
335 case SS_DATATYPE_STRING:
339 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Node->Type);
344 case SS_DATATYPE_INTEGER:
347 case NODETYPE_ADD: ret = Object_CreateInteger( op1->Integer + op2->Integer ); break;
348 case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer ); break;
349 case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer ); break;
350 case NODETYPE_DIVIDE: ret = Object_CreateInteger( op1->Integer / op2->Integer ); break;
351 case NODETYPE_MODULO: ret = Object_CreateInteger( op1->Integer % op2->Integer ); break;
352 case NODETYPE_BWAND: ret = Object_CreateInteger( op1->Integer & op2->Integer ); break;
353 case NODETYPE_BWOR: ret = Object_CreateInteger( op1->Integer | op2->Integer ); break;
354 case NODETYPE_BWXOR: ret = Object_CreateInteger( op1->Integer ^ op2->Integer ); break;
355 case NODETYPE_BITSHIFTLEFT: ret = Object_CreateInteger( op1->Integer << op2->Integer ); break;
356 case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
357 case NODETYPE_BITROTATELEFT:
358 ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
361 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Node->Type);
368 // Free intermediate objects
369 Object_Dereference(op1);
370 Object_Dereference(op2);
375 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);