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 switch( (enum eSpiderScript_DataTypes)Value->Type )
171 case SS_DATATYPE_UNDEF:
172 case SS_DATATYPE_NULL:
175 case SS_DATATYPE_INTEGER:
176 return !!Value->Integer;
178 case SS_DATATYPE_REAL:
179 return (-.5f < Value->Real && Value->Real < 0.5f);
181 case SS_DATATYPE_STRING:
182 return Value->String.Length > 0;
184 case SS_DATATYPE_OBJECT:
185 return Value->Object != NULL;
187 case SS_DATATYPE_OPAQUE:
188 return Value->Opaque.Data != NULL;
190 case SS_DATATYPE_ARRAY:
191 return Value->Array.Length > 0;
193 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_IsTrue\n", Value->Type);
200 * \brief Execute an AST node and return its value
202 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
205 tSpiderValue *ret = NULL, *tmpobj;
206 tSpiderValue *op1, *op2; // Binary operations
207 int cmp; // Used in comparisons
212 case NODETYPE_NOP: ret = NULL; break;
217 tAST_BlockState blockInfo;
218 blockInfo.FirstVar = NULL;
219 blockInfo.Parent = Block;
220 blockInfo.Script = Block->Script;
222 for(node = Node->Block.FirstChild; node; node = node->NextSibling )
224 if(node->Type == NODETYPE_RETURN) {
225 ret = AST_ExecuteNode(&blockInfo, node);
229 tmpobj = AST_ExecuteNode(&blockInfo, node);
230 if(tmpobj == ERRPTR) { // Error check
234 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
237 // Clean up variables
238 while(blockInfo.FirstVar)
240 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
241 Variable_Destroy( blockInfo.FirstVar );
242 blockInfo.FirstVar = nextVar;
249 case NODETYPE_ASSIGN:
250 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
251 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
254 ret = AST_ExecuteNode(Block, Node->Assign.Value);
256 Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
260 case NODETYPE_FUNCTIONCALL:
263 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
266 // Logical block (used to allocate `params`)
268 tSpiderValue *params[nParams];
270 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
271 params[i] = AST_ExecuteNode(Block, node);
272 if( params[i] == ERRPTR ) {
273 while(i--) Object_Dereference(params[i]);
280 // Call the function (SpiderScript_ExecuteMethod does the
281 // required namespace handling)
282 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
284 // Dereference parameters
285 while(i--) Object_Dereference(params[i]);
292 // Return's special handling happens elsewhere
293 case NODETYPE_RETURN:
294 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
298 case NODETYPE_DEFVAR:
300 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
305 case NODETYPE_VARIABLE:
306 ret = Variable_GetValue( Block, Node->Variable.Name );
309 // Cast a value to another
313 AST_ExecuteNode(Block, Node->Cast.Value)
317 // Index into an array
319 fprintf(stderr, "TODO: Array indexing\n");
323 // TODO: Implement runtime constants
324 case NODETYPE_CONSTANT:
325 fprintf(stderr, "TODO: Runtime Constants\n");
329 case NODETYPE_STRING: ret = Object_CreateString( Node->String.Length, Node->String.Data ); break;
330 case NODETYPE_INTEGER: ret = Object_CreateInteger( Node->Integer ); break;
331 case NODETYPE_REAL: ret = Object_CreateReal( Node->Real ); break;
333 // --- Operations ---
334 // Boolean Operations
335 case NODETYPE_LOGICALAND: // Logical AND (&&)
336 case NODETYPE_LOGICALOR: // Logical OR (||)
337 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
338 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
339 if(op1 == ERRPTR) return ERRPTR;
340 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
342 Object_Dereference(op1);
348 case NODETYPE_LOGICALAND:
349 ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
351 case NODETYPE_LOGICALOR:
352 ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
354 case NODETYPE_LOGICALXOR:
355 ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
360 // Free intermediate objects
361 Object_Dereference(op1);
362 Object_Dereference(op2);
366 case NODETYPE_EQUALS:
367 case NODETYPE_LESSTHAN:
368 case NODETYPE_GREATERTHAN:
369 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
370 if(op1 == ERRPTR) return ERRPTR;
371 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
373 Object_Dereference(op1);
377 // No conversion done for NULL
378 // TODO: Determine if this will ever be needed
379 if( op1->Type == SS_DATATYPE_NULL )
381 // NULLs always typecheck
382 ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
387 if( op1->Type != op2->Type ) {
388 // If dynamically typed, convert op2 to op1's type
389 if(Block->Script->Variant->bDyamicTyped)
392 op2 = Object_CastTo(op1->Type, op2);
393 Object_Dereference(tmpobj);
395 Object_Dereference(op1);
399 // If statically typed, this should never happen, but catch it anyway
401 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
410 case SS_DATATYPE_NULL: break;
411 // - String Compare (does a strcmp, well memcmp)
412 case SS_DATATYPE_STRING:
413 // Call memcmp to do most of the work
415 op1->String.Data, op2->String.Data,
416 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
418 // Handle reaching the end of the string
420 if( op1->String.Length == op2->String.Length )
422 else if( op1->String.Length < op2->String.Length )
429 fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
434 // Free intermediate objects
435 Object_Dereference(op1);
436 Object_Dereference(op2);
445 case NODETYPE_EQUALS: ret = Object_CreateInteger(cmp == 0); break;
446 case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0); break;
447 case NODETYPE_GREATERTHAN: ret = Object_CreateInteger(cmp > 0); break;
449 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
455 // General Binary Operations
457 case NODETYPE_SUBTRACT:
458 case NODETYPE_MULTIPLY:
459 case NODETYPE_DIVIDE:
460 case NODETYPE_MODULO:
464 case NODETYPE_BITSHIFTLEFT:
465 case NODETYPE_BITSHIFTRIGHT:
466 case NODETYPE_BITROTATELEFT:
468 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
469 if(op1 == ERRPTR) return ERRPTR;
470 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
472 Object_Dereference(op1);
477 if( op1 && op2 && op1->Type != op2->Type ) {
478 // If dynamically typed, convert op2 to op1's type
479 if(Block->Script->Variant->bDyamicTyped)
482 op2 = Object_CastTo(op1->Type, op2);
483 Object_Dereference(tmpobj);
485 Object_Dereference(op1);
489 // If statically typed, this should never happen, but catch it anyway
491 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
500 case SS_DATATYPE_NULL: break;
501 // String Concatenation
502 case SS_DATATYPE_STRING:
505 case NODETYPE_ADD: // Concatenate
506 ret = Object_StringConcat(op1, op2);
509 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
514 // Integer Operations
515 case SS_DATATYPE_INTEGER:
518 case NODETYPE_ADD: ret = Object_CreateInteger( op1->Integer + op2->Integer ); break;
519 case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer ); break;
520 case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer ); break;
521 case NODETYPE_DIVIDE: ret = Object_CreateInteger( op1->Integer / op2->Integer ); break;
522 case NODETYPE_MODULO: ret = Object_CreateInteger( op1->Integer % op2->Integer ); break;
523 case NODETYPE_BWAND: ret = Object_CreateInteger( op1->Integer & op2->Integer ); break;
524 case NODETYPE_BWOR: ret = Object_CreateInteger( op1->Integer | op2->Integer ); break;
525 case NODETYPE_BWXOR: ret = Object_CreateInteger( op1->Integer ^ op2->Integer ); break;
526 case NODETYPE_BITSHIFTLEFT: ret = Object_CreateInteger( op1->Integer << op2->Integer ); break;
527 case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
528 case NODETYPE_BITROTATELEFT:
529 ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
532 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
539 case SS_DATATYPE_REAL:
543 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
550 fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
555 // Free intermediate objects
556 Object_Dereference(op1);
557 Object_Dereference(op2);
562 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
570 * \brief Define a variable
571 * \param Block Current block state
572 * \param Type Type of the variable
573 * \param Name Name of the variable
574 * \return Boolean Failure
576 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
578 tAST_Variable *var, *prev = NULL;
580 for( var = Block->FirstVar; var; prev = var, var = var->Next )
582 if( strcmp(var->Name, Name) == 0 ) {
583 fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
588 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
592 strcpy(var->Name, Name);
594 if(prev) prev->Next = var;
595 else Block->FirstVar = var;
597 //printf("Defined variable %s (%i)\n", Name, Type);
603 * \brief Set the value of a variable
605 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
610 for( bs = Block; bs; bs = bs->Parent )
612 for( var = bs->FirstVar; var; var = var->Next )
614 if( strcmp(var->Name, Name) == 0 ) {
615 if( !Block->Script->Variant->bDyamicTyped
616 && (Value && var->Type != Value->Type) ) {
617 fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
620 Object_Reference(Value);
621 Object_Dereference(var->Object);
628 if( Block->Script->Variant->bDyamicTyped )
631 var = Variable_Define(Block, Value->Type, Name);
632 Object_Reference(Value);
637 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
642 * \brief Get the value of a variable
644 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
649 for( bs = Block; bs; bs = bs->Parent )
651 for( var = bs->FirstVar; var; var = var->Next )
653 if( strcmp(var->Name, Name) == 0 ) {
654 Object_Reference(var->Object);
660 fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
666 * \brief Destorys a variable
668 void Variable_Destroy(tAST_Variable *Variable)
670 Object_Dereference(Variable->Object);