9 void Object_Dereference(tSpiderValue *Object);
10 void Object_Reference(tSpiderValue *Object);
11 tSpiderValue *Object_CreateInteger(uint64_t Value);
12 tSpiderValue *Object_CreateReal(double Value);
13 tSpiderValue *Object_CreateString(int Length, const char *Data);
14 tSpiderValue *Object_CastTo(int Type, tSpiderValue *Source);
15 int Object_IsTrue(tSpiderValue *Value);
17 tSpiderValue *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, tSpiderValue *Value);
21 tSpiderValue *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(tSpiderValue *Object)
31 Object->ReferenceCount --;
32 if( Object->ReferenceCount == 0 ) {
33 switch( (enum eSpiderScript_DataTypes) Object->Type )
35 case SS_DATATYPE_OBJECT:
36 Object->Object->Type->Destructor( Object->Object );
38 case SS_DATATYPE_OPAQUE:
39 Object->Opaque.Destroy( Object->Opaque.Data );
48 void Object_Reference(tSpiderValue *Object)
51 Object->ReferenceCount ++;
55 * \brief Create an integer object
57 tSpiderValue *Object_CreateInteger(uint64_t Value)
59 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
60 ret->Type = SS_DATATYPE_INTEGER;
61 ret->ReferenceCount = 1;
67 * \brief Create an real number object
69 tSpiderValue *Object_CreateReal(double Value)
71 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
72 ret->Type = SS_DATATYPE_REAL;
73 ret->ReferenceCount = 1;
79 * \brief Create an string object
81 tSpiderValue *Object_CreateString(int Length, const char *Data)
83 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
84 ret->Type = SS_DATATYPE_STRING;
85 ret->ReferenceCount = 1;
86 ret->String.Length = Length;
87 memcpy(ret->String.Data, Data, Length);
88 ret->String.Data[Length] = '\0';
93 * \brief Concatenate two strings
95 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
99 if(Str1) newLen += Str1->String.Length;
100 if(Str2) newLen += Str2->String.Length;
101 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
102 ret->Type = SS_DATATYPE_STRING;
103 ret->ReferenceCount = 1;
104 ret->String.Length = newLen;
106 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
109 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
111 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
113 ret->String.Data[ newLen ] = '\0';
118 * \brief Cast one object to another
119 * \brief Type Destination type
120 * \brief Source Input data
122 tSpiderValue *Object_CastTo(int Type, tSpiderValue *Source)
124 tSpiderValue *ret = ERRPTR;
125 // Check if anything needs to be done
126 if( Source->Type == Type ) {
127 Object_Reference(Source);
131 switch( (enum eSpiderScript_DataTypes)Type )
133 case SS_DATATYPE_UNDEF:
134 case SS_DATATYPE_NULL:
135 case SS_DATATYPE_ARRAY:
136 case SS_DATATYPE_OPAQUE:
137 fprintf(stderr, "Object_CastTo - Invalid cast to %i\n", Type);
140 case SS_DATATYPE_INTEGER:
141 ret = malloc(sizeof(tSpiderValue));
142 ret->Type = SS_DATATYPE_INTEGER;
143 ret->ReferenceCount = 1;
146 case SS_DATATYPE_INTEGER: break; // Handled above
147 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
148 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
150 fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
157 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
165 * \brief Condenses a value down to a boolean
167 int Object_IsTrue(tSpiderValue *Value)
169 if( Value == ERRPTR ) return 0;
170 if( Value == NULL ) return 0;
172 switch( (enum eSpiderScript_DataTypes)Value->Type )
174 case SS_DATATYPE_UNDEF:
175 case SS_DATATYPE_NULL:
178 case SS_DATATYPE_INTEGER:
179 return !!Value->Integer;
181 case SS_DATATYPE_REAL:
182 return (-.5f < Value->Real && Value->Real < 0.5f);
184 case SS_DATATYPE_STRING:
185 return Value->String.Length > 0;
187 case SS_DATATYPE_OBJECT:
188 return Value->Object != NULL;
190 case SS_DATATYPE_OPAQUE:
191 return Value->Opaque.Data != NULL;
193 case SS_DATATYPE_ARRAY:
194 return Value->Array.Length > 0;
196 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_IsTrue\n", Value->Type);
203 * \brief Execute an AST node and return its value
205 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
208 tSpiderValue *ret = NULL, *tmpobj;
209 tSpiderValue *op1, *op2; // Binary operations
210 int cmp; // Used in comparisons
215 case NODETYPE_NOP: ret = NULL; break;
220 tAST_BlockState blockInfo;
221 blockInfo.FirstVar = NULL;
222 blockInfo.RetVal = NULL;
223 blockInfo.Parent = Block;
224 blockInfo.Script = Block->Script;
226 for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
228 tmpobj = AST_ExecuteNode(&blockInfo, node);
229 if(tmpobj == ERRPTR) { // Error check
233 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
235 // Clean up variables
236 while(blockInfo.FirstVar)
238 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
239 Variable_Destroy( blockInfo.FirstVar );
240 blockInfo.FirstVar = nextVar;
243 if( blockInfo.RetVal )
244 Block->RetVal = blockInfo.RetVal;
250 case NODETYPE_ASSIGN:
251 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
252 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
255 ret = AST_ExecuteNode(Block, Node->Assign.Value);
257 Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
261 case NODETYPE_FUNCTIONCALL:
264 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
267 // Logical block (used to allocate `params`)
269 tSpiderValue *params[nParams];
271 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
272 params[i] = AST_ExecuteNode(Block, node);
273 if( params[i] == ERRPTR ) {
274 while(i--) Object_Dereference(params[i]);
281 // Call the function (SpiderScript_ExecuteMethod does the
282 // required namespace handling)
283 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
285 // Dereference parameters
286 while(i--) Object_Dereference(params[i]);
295 ret = AST_ExecuteNode(Block, Node->If.Condition);
296 if( Object_IsTrue(ret) ) {
297 AST_ExecuteNode(Block, Node->If.True);
300 AST_ExecuteNode(Block, Node->If.False);
302 Object_Dereference(ret);
307 ret = AST_ExecuteNode(Block, Node->For.Init);
308 if( Node->For.bCheckAfter ) {
310 Object_Dereference(ret);
311 ret = AST_ExecuteNode(Block, Node->For.Code);
312 Object_Dereference(ret);
313 ret = AST_ExecuteNode(Block, Node->For.Condition);
314 } while( Object_IsTrue(ret) );
317 Object_Dereference(ret);
318 ret = AST_ExecuteNode(Block, Node->For.Condition);
319 while( Object_IsTrue(ret) ) {
320 Object_Dereference(ret);
321 ret = AST_ExecuteNode(Block, Node->For.Code);
322 Object_Dereference(ret);
323 ret = AST_ExecuteNode(Block, Node->For.Condition);
325 Object_Dereference(ret);
330 case NODETYPE_RETURN:
331 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
332 Block->RetVal = ret; // Return value set
336 case NODETYPE_DEFVAR:
338 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
343 case NODETYPE_VARIABLE:
344 ret = Variable_GetValue( Block, Node->Variable.Name );
347 // Cast a value to another
351 AST_ExecuteNode(Block, Node->Cast.Value)
355 // Index into an array
357 fprintf(stderr, "TODO: Array indexing\n");
361 // TODO: Implement runtime constants
362 case NODETYPE_CONSTANT:
363 fprintf(stderr, "TODO: Runtime Constants\n");
367 case NODETYPE_STRING: ret = Object_CreateString( Node->String.Length, Node->String.Data ); break;
368 case NODETYPE_INTEGER: ret = Object_CreateInteger( Node->Integer ); break;
369 case NODETYPE_REAL: ret = Object_CreateReal( Node->Real ); break;
371 // --- Operations ---
372 // Boolean Operations
373 case NODETYPE_LOGICALAND: // Logical AND (&&)
374 case NODETYPE_LOGICALOR: // Logical OR (||)
375 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
376 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
377 if(op1 == ERRPTR) return ERRPTR;
378 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
380 Object_Dereference(op1);
386 case NODETYPE_LOGICALAND:
387 ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
389 case NODETYPE_LOGICALOR:
390 ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
392 case NODETYPE_LOGICALXOR:
393 ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
398 // Free intermediate objects
399 Object_Dereference(op1);
400 Object_Dereference(op2);
404 case NODETYPE_EQUALS:
405 case NODETYPE_LESSTHAN:
406 case NODETYPE_GREATERTHAN:
407 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
408 if(op1 == ERRPTR) return ERRPTR;
409 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
411 Object_Dereference(op1);
415 // No conversion done for NULL
416 // TODO: Determine if this will ever be needed
417 if( op1->Type == SS_DATATYPE_NULL )
419 // NULLs always typecheck
420 ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
425 if( op1->Type != op2->Type ) {
426 // If dynamically typed, convert op2 to op1's type
427 if(Block->Script->Variant->bDyamicTyped)
430 op2 = Object_CastTo(op1->Type, op2);
431 Object_Dereference(tmpobj);
433 Object_Dereference(op1);
437 // If statically typed, this should never happen, but catch it anyway
439 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
448 case SS_DATATYPE_NULL: break;
449 // - String Compare (does a strcmp, well memcmp)
450 case SS_DATATYPE_STRING:
451 // Call memcmp to do most of the work
453 op1->String.Data, op2->String.Data,
454 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
456 // Handle reaching the end of the string
458 if( op1->String.Length == op2->String.Length )
460 else if( op1->String.Length < op2->String.Length )
467 fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
472 // Free intermediate objects
473 Object_Dereference(op1);
474 Object_Dereference(op2);
483 case NODETYPE_EQUALS: ret = Object_CreateInteger(cmp == 0); break;
484 case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0); break;
485 case NODETYPE_GREATERTHAN: ret = Object_CreateInteger(cmp > 0); break;
487 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
493 // General Binary Operations
495 case NODETYPE_SUBTRACT:
496 case NODETYPE_MULTIPLY:
497 case NODETYPE_DIVIDE:
498 case NODETYPE_MODULO:
502 case NODETYPE_BITSHIFTLEFT:
503 case NODETYPE_BITSHIFTRIGHT:
504 case NODETYPE_BITROTATELEFT:
506 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
507 if(op1 == ERRPTR) return ERRPTR;
508 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
510 Object_Dereference(op1);
515 if( op1 && op2 && op1->Type != op2->Type ) {
516 // If dynamically typed, convert op2 to op1's type
517 if(Block->Script->Variant->bDyamicTyped)
520 op2 = Object_CastTo(op1->Type, op2);
521 Object_Dereference(tmpobj);
523 Object_Dereference(op1);
527 // If statically typed, this should never happen, but catch it anyway
529 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
538 case SS_DATATYPE_NULL: break;
539 // String Concatenation
540 case SS_DATATYPE_STRING:
543 case NODETYPE_ADD: // Concatenate
544 ret = Object_StringConcat(op1, op2);
547 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
552 // Integer Operations
553 case SS_DATATYPE_INTEGER:
556 case NODETYPE_ADD: ret = Object_CreateInteger( op1->Integer + op2->Integer ); break;
557 case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer ); break;
558 case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer ); break;
559 case NODETYPE_DIVIDE: ret = Object_CreateInteger( op1->Integer / op2->Integer ); break;
560 case NODETYPE_MODULO: ret = Object_CreateInteger( op1->Integer % op2->Integer ); break;
561 case NODETYPE_BWAND: ret = Object_CreateInteger( op1->Integer & op2->Integer ); break;
562 case NODETYPE_BWOR: ret = Object_CreateInteger( op1->Integer | op2->Integer ); break;
563 case NODETYPE_BWXOR: ret = Object_CreateInteger( op1->Integer ^ op2->Integer ); break;
564 case NODETYPE_BITSHIFTLEFT: ret = Object_CreateInteger( op1->Integer << op2->Integer ); break;
565 case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
566 case NODETYPE_BITROTATELEFT:
567 ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
570 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
577 case SS_DATATYPE_REAL:
581 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
588 fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
593 // Free intermediate objects
594 Object_Dereference(op1);
595 Object_Dereference(op2);
600 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
608 * \brief Define a variable
609 * \param Block Current block state
610 * \param Type Type of the variable
611 * \param Name Name of the variable
612 * \return Boolean Failure
614 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
616 tAST_Variable *var, *prev = NULL;
618 for( var = Block->FirstVar; var; prev = var, var = var->Next )
620 if( strcmp(var->Name, Name) == 0 ) {
621 fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
626 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
630 strcpy(var->Name, Name);
632 if(prev) prev->Next = var;
633 else Block->FirstVar = var;
635 //printf("Defined variable %s (%i)\n", Name, Type);
641 * \brief Set the value of a variable
643 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
648 for( bs = Block; bs; bs = bs->Parent )
650 for( var = bs->FirstVar; var; var = var->Next )
652 if( strcmp(var->Name, Name) == 0 ) {
653 if( !Block->Script->Variant->bDyamicTyped
654 && (Value && var->Type != Value->Type) ) {
655 fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
658 Object_Reference(Value);
659 Object_Dereference(var->Object);
666 if( Block->Script->Variant->bDyamicTyped )
669 var = Variable_Define(Block, Value->Type, Name);
670 Object_Reference(Value);
675 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
680 * \brief Get the value of a variable
682 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
687 for( bs = Block; bs; bs = bs->Parent )
689 for( var = bs->FirstVar; var; var = var->Next )
691 if( strcmp(var->Name, Name) == 0 ) {
692 Object_Reference(var->Object);
698 fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
704 * \brief Destorys a variable
706 void Variable_Destroy(tAST_Variable *Variable)
708 Object_Dereference(Variable->Object);