9 void Object_Dereference(tSpiderObject *Object);
10 void Object_Reference(tSpiderObject *Object);
11 tSpiderObject *Object_CreateInteger(uint64_t Value);
12 tSpiderObject *Object_CreateReal(double Value);
13 tSpiderObject *Object_CreateString(int Length, const char *Data);
14 tSpiderObject *Object_CastTo(int Type, tSpiderObject *Source);
15 int Object_IsTrue(tSpiderObject *Value);
17 tSpiderObject *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
19 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
20 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value);
21 tSpiderObject *Variable_GetValue(tAST_BlockState *Block, const char *Name);
22 void Variable_Destroy(tAST_Variable *Variable);
26 * \brief Dereference a created object
28 void Object_Dereference(tSpiderObject *Object)
31 Object->ReferenceCount --;
32 if( Object->ReferenceCount == 0 ) free(Object);
35 void Object_Reference(tSpiderObject *Object)
38 Object->ReferenceCount ++;
42 * \brief Create an integer object
44 tSpiderObject *Object_CreateInteger(uint64_t Value)
46 tSpiderObject *ret = malloc( sizeof(tSpiderObject) );
47 ret->Type = SS_DATATYPE_INTEGER;
48 ret->ReferenceCount = 1;
54 * \brief Create an real number object
56 tSpiderObject *Object_CreateReal(double Value)
58 tSpiderObject *ret = malloc( sizeof(tSpiderObject) );
59 ret->Type = SS_DATATYPE_REAL;
60 ret->ReferenceCount = 1;
66 * \brief Create an string object
68 tSpiderObject *Object_CreateString(int Length, const char *Data)
70 tSpiderObject *ret = malloc( sizeof(tSpiderObject) + Length + 1 );
71 ret->Type = SS_DATATYPE_STRING;
72 ret->ReferenceCount = 1;
73 ret->String.Length = Length;
74 memcpy(ret->String.Data, Data, Length);
75 ret->String.Data[Length] = '\0';
80 * \brief Concatenate two strings
82 tSpiderObject *Object_StringConcat(tSpiderObject *Str1, tSpiderObject *Str2)
86 if(Str1) newLen += Str1->String.Length;
87 if(Str2) newLen += Str2->String.Length;
88 ret = malloc( sizeof(tSpiderObject) + newLen + 1 );
89 ret->Type = SS_DATATYPE_STRING;
90 ret->ReferenceCount = 1;
91 ret->String.Length = newLen;
93 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
96 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
98 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
100 ret->String.Data[ newLen ] = '\0';
105 * \brief Cast one object to another
107 tSpiderObject *Object_CastTo(int Type, tSpiderObject *Source)
109 tSpiderObject *ret = ERRPTR;
110 // Check if anything needs to be done
111 if( Source->Type == Type ) {
112 Object_Reference(Source);
118 case SS_DATATYPE_UNDEF:
119 case SS_DATATYPE_NULL:
120 case SS_DATATYPE_ARRAY:
121 fprintf(stderr, "Object_CastTo - Invalid cast to %i\n", Type);
124 case SS_DATATYPE_INTEGER:
125 ret = malloc(sizeof(tSpiderObject));
126 ret->Type = SS_DATATYPE_INTEGER;
127 ret->ReferenceCount = 1;
130 case SS_DATATYPE_INTEGER: break; // Handled above
131 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
132 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
134 fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
141 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
149 * \brief Condenses a value down to a boolean
151 int Object_IsTrue(tSpiderObject *Value)
155 case SS_DATATYPE_UNDEF:
156 case SS_DATATYPE_NULL:
159 case SS_DATATYPE_INTEGER:
160 return !!Value->Integer;
162 case SS_DATATYPE_REAL:
163 return (-.5f < Value->Real && Value->Real < 0.5f);
165 case SS_DATATYPE_STRING:
166 return Value->String.Length > 0;
168 case SS_DATATYPE_OBJECT:
169 return Value->Object != NULL;
171 case SS_DATATYPE_ARRAY:
172 return Value->Array.Length > 0;
178 * \brief Execute an AST node and return its value
180 tSpiderObject *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
183 tSpiderObject *ret, *tmpobj;
184 tSpiderObject *op1, *op2; // Binary operations
185 int cmp; // Used in comparisons
190 case NODETYPE_NOP: ret = NULL; break;
195 tAST_BlockState blockInfo;
196 blockInfo.FirstVar = NULL;
197 blockInfo.Parent = Block;
198 blockInfo.Script = Block->Script;
200 for(node = Node->Block.FirstChild; node; node = node->NextSibling )
202 if(node->Type == NODETYPE_RETURN) {
203 ret = AST_ExecuteNode(&blockInfo, node);
207 tmpobj = AST_ExecuteNode(&blockInfo, node);
208 if(tmpobj == ERRPTR) { // Error check
212 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
215 // Clean up variables
216 while(blockInfo.FirstVar)
218 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
219 Variable_Destroy( blockInfo.FirstVar );
220 blockInfo.FirstVar = nextVar;
227 case NODETYPE_ASSIGN:
228 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
229 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
232 ret = AST_ExecuteNode(Block, Node->Assign.Value);
234 Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
238 case NODETYPE_FUNCTIONCALL:
241 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
244 // Logical block (used to allocate `params`)
246 tSpiderObject *params[nParams];
248 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
249 params[i] = AST_ExecuteNode(Block, node);
250 if( params[i] == ERRPTR ) {
251 while(i--) Object_Dereference(params[i]);
258 // Call the function (SpiderScript_ExecuteMethod does the
259 // required namespace handling)
260 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
262 // Dereference parameters
263 while(i--) Object_Dereference(params[i]);
270 // Return's special handling happens elsewhere
271 case NODETYPE_RETURN:
272 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
276 case NODETYPE_DEFVAR:
278 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
283 case NODETYPE_VARIABLE:
284 ret = Variable_GetValue( Block, Node->Variable.Name );
287 // Cast a value to another
291 AST_ExecuteNode(Block, Node->Cast.Value)
295 // Index into an array
297 fprintf(stderr, "TODO: Array indexing\n");
301 // TODO: Implement runtime constants
302 case NODETYPE_CONSTANT:
303 fprintf(stderr, "TODO: Runtime Constants\n");
307 case NODETYPE_STRING: ret = Object_CreateString( Node->String.Length, Node->String.Data ); break;
308 case NODETYPE_INTEGER: ret = Object_CreateInteger( Node->Integer ); break;
309 case NODETYPE_REAL: ret = Object_CreateReal( Node->Real ); break;
311 // --- Operations ---
312 // Boolean Operations
313 case NODETYPE_LOGICALAND: // Logical AND (&&)
314 case NODETYPE_LOGICALOR: // Logical OR (||)
315 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
316 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
317 if(op1 == ERRPTR) return ERRPTR;
318 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
320 Object_Dereference(op1);
326 case NODETYPE_LOGICALAND:
327 ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
329 case NODETYPE_LOGICALOR:
330 ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
332 case NODETYPE_LOGICALXOR:
333 ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
338 // Free intermediate objects
339 Object_Dereference(op1);
340 Object_Dereference(op2);
344 case NODETYPE_EQUALS:
345 case NODETYPE_LESSTHAN:
346 case NODETYPE_GREATERTHAN:
347 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
348 if(op1 == ERRPTR) return ERRPTR;
349 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
351 Object_Dereference(op1);
355 // No conversion done for NULL
356 // TODO: Determine if this will ever be needed
357 if( op1->Type == SS_DATATYPE_NULL )
359 // NULLs always typecheck
360 ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
365 if( op1->Type != op2->Type ) {
366 // If dynamically typed, convert op2 to op1's type
367 if(Block->Script->Variant->bDyamicTyped)
370 op2 = Object_CastTo(op1->Type, op2);
371 Object_Dereference(tmpobj);
373 Object_Dereference(op1);
377 // If statically typed, this should never happen, but catch it anyway
379 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
388 case SS_DATATYPE_NULL: break;
389 // - String Compare (does a strcmp, well memcmp)
390 case SS_DATATYPE_STRING:
391 // Call memcmp to do most of the work
393 op1->String.Data, op2->String.Data,
394 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
396 // Handle reaching the end of the string
398 if( op1->String.Length == op2->String.Length )
400 else if( op1->String.Length < op2->String.Length )
408 // Free intermediate objects
409 Object_Dereference(op1);
410 Object_Dereference(op2);
415 case NODETYPE_EQUALS: ret = Object_CreateInteger(cmp == 0); break;
416 case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0); break;
417 case NODETYPE_GREATERTHAN: ret = Object_CreateInteger(cmp > 0); break;
419 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
425 // General Binary Operations
427 case NODETYPE_SUBTRACT:
428 case NODETYPE_MULTIPLY:
429 case NODETYPE_DIVIDE:
430 case NODETYPE_MODULO:
434 case NODETYPE_BITSHIFTLEFT:
435 case NODETYPE_BITSHIFTRIGHT:
436 case NODETYPE_BITROTATELEFT:
438 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
439 if(op1 == ERRPTR) return ERRPTR;
440 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
442 Object_Dereference(op1);
447 if( op1 && op2 && op1->Type != op2->Type ) {
448 // If dynamically typed, convert op2 to op1's type
449 if(Block->Script->Variant->bDyamicTyped)
452 op2 = Object_CastTo(op1->Type, op2);
453 Object_Dereference(tmpobj);
455 Object_Dereference(op1);
459 // If statically typed, this should never happen, but catch it anyway
461 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
470 case SS_DATATYPE_NULL: break;
471 // String Concatenation
472 case SS_DATATYPE_STRING:
475 case NODETYPE_ADD: // Concatenate
476 ret = Object_StringConcat(op1, op2);
479 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
484 case SS_DATATYPE_INTEGER:
487 case NODETYPE_ADD: ret = Object_CreateInteger( op1->Integer + op2->Integer ); break;
488 case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer ); break;
489 case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer ); break;
490 case NODETYPE_DIVIDE: ret = Object_CreateInteger( op1->Integer / op2->Integer ); break;
491 case NODETYPE_MODULO: ret = Object_CreateInteger( op1->Integer % op2->Integer ); break;
492 case NODETYPE_BWAND: ret = Object_CreateInteger( op1->Integer & op2->Integer ); break;
493 case NODETYPE_BWOR: ret = Object_CreateInteger( op1->Integer | op2->Integer ); break;
494 case NODETYPE_BWXOR: ret = Object_CreateInteger( op1->Integer ^ op2->Integer ); break;
495 case NODETYPE_BITSHIFTLEFT: ret = Object_CreateInteger( op1->Integer << op2->Integer ); break;
496 case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
497 case NODETYPE_BITROTATELEFT:
498 ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
501 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Node->Type);
508 // Free intermediate objects
509 Object_Dereference(op1);
510 Object_Dereference(op2);
515 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
523 * \brief Define a variable
524 * \param Block Current block state
525 * \param Type Type of the variable
526 * \param Name Name of the variable
527 * \return Boolean Failure
529 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
531 tAST_Variable *var, *prev = NULL;
533 for( var = Block->FirstVar; var; prev = var, var = var->Next )
535 if( strcmp(var->Name, Name) == 0 ) {
536 fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
541 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
545 strcpy(var->Name, Name);
547 if(prev) prev->Next = var;
548 else Block->FirstVar = var;
550 //printf("Defined variable %s (%i)\n", Name, Type);
556 * \brief Set the value of a variable
558 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value)
563 for( bs = Block; bs; bs = bs->Parent )
565 for( var = bs->FirstVar; var; var = var->Next )
567 if( strcmp(var->Name, Name) == 0 ) {
568 if( !Block->Script->Variant->bDyamicTyped
569 && (Value && var->Type != Value->Type) ) {
570 fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
573 Object_Reference(Value);
574 Object_Dereference(var->Object);
581 if( Block->Script->Variant->bDyamicTyped )
584 var = Variable_Define(Block, Value->Type, Name);
585 Object_Reference(Value);
590 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
595 * \brief Get the value of a variable
597 tSpiderObject *Variable_GetValue(tAST_BlockState *Block, const char *Name)
602 for( bs = Block; bs; bs = bs->Parent )
604 for( var = bs->FirstVar; var; var = var->Next )
606 if( strcmp(var->Name, Name) == 0 ) {
607 Object_Reference(var->Object);
613 fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
619 * \brief Destorys a variable
621 void Variable_Destroy(tAST_Variable *Variable)
623 Object_Dereference(Variable->Object);