9 void Object_Dereference(tSpiderValue *Object);
10 void Object_Reference(tSpiderValue *Object);
11 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value);
12 tSpiderValue *SpiderScript_CreateReal(double Value);
13 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data);
14 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
15 int SpiderScript_IsValueTrue(tSpiderValue *Value);
16 char *SpiderScript_DumpValue(tSpiderValue *Value);
18 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
20 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
21 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
22 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name);
23 void Variable_Destroy(tAST_Variable *Variable);
27 * \brief Dereference a created object
29 void Object_Dereference(tSpiderValue *Object)
32 Object->ReferenceCount --;
33 if( Object->ReferenceCount == 0 ) {
34 switch( (enum eSpiderScript_DataTypes) Object->Type )
36 case SS_DATATYPE_OBJECT:
37 Object->Object->Type->Destructor( Object->Object );
39 case SS_DATATYPE_OPAQUE:
40 Object->Opaque.Destroy( Object->Opaque.Data );
49 void Object_Reference(tSpiderValue *Object)
52 Object->ReferenceCount ++;
56 * \brief Create an integer object
58 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
60 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
61 ret->Type = SS_DATATYPE_INTEGER;
62 ret->ReferenceCount = 1;
68 * \brief Create an real number object
70 tSpiderValue *SpiderScript_CreateReal(double Value)
72 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
73 ret->Type = SS_DATATYPE_REAL;
74 ret->ReferenceCount = 1;
80 * \brief Create an string object
82 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
84 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
85 ret->Type = SS_DATATYPE_STRING;
86 ret->ReferenceCount = 1;
87 ret->String.Length = Length;
88 memcpy(ret->String.Data, Data, Length);
89 ret->String.Data[Length] = '\0';
94 * \brief Concatenate two strings
96 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
100 if(Str1) newLen += Str1->String.Length;
101 if(Str2) newLen += Str2->String.Length;
102 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
103 ret->Type = SS_DATATYPE_STRING;
104 ret->ReferenceCount = 1;
105 ret->String.Length = newLen;
107 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
110 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
112 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
114 ret->String.Data[ newLen ] = '\0';
119 * \brief Cast one object to another
120 * \brief Type Destination type
121 * \brief Source Input data
123 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
125 tSpiderValue *ret = ERRPTR;
126 // Check if anything needs to be done
127 if( Source->Type == Type ) {
128 Object_Reference(Source);
132 switch( (enum eSpiderScript_DataTypes)Type )
134 case SS_DATATYPE_UNDEF:
135 case SS_DATATYPE_NULL:
136 case SS_DATATYPE_ARRAY:
137 case SS_DATATYPE_OPAQUE:
138 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast to %i\n", Type);
141 case SS_DATATYPE_INTEGER:
142 ret = malloc(sizeof(tSpiderValue));
143 ret->Type = SS_DATATYPE_INTEGER;
144 ret->ReferenceCount = 1;
147 case SS_DATATYPE_INTEGER: break; // Handled above
148 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
149 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
151 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
158 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
166 * \brief Condenses a value down to a boolean
168 int SpiderScript_IsValueTrue(tSpiderValue *Value)
170 if( Value == ERRPTR ) return 0;
171 if( Value == NULL ) return 0;
173 switch( (enum eSpiderScript_DataTypes)Value->Type )
175 case SS_DATATYPE_UNDEF:
176 case SS_DATATYPE_NULL:
179 case SS_DATATYPE_INTEGER:
180 return !!Value->Integer;
182 case SS_DATATYPE_REAL:
183 return (-.5f < Value->Real && Value->Real < 0.5f);
185 case SS_DATATYPE_STRING:
186 return Value->String.Length > 0;
188 case SS_DATATYPE_OBJECT:
189 return Value->Object != NULL;
191 case SS_DATATYPE_OPAQUE:
192 return Value->Opaque.Data != NULL;
194 case SS_DATATYPE_ARRAY:
195 return Value->Array.Length > 0;
197 fprintf(stderr, "Spiderscript internal error: Unknown type %i in SpiderScript_IsValueTrue\n", Value->Type);
204 * \brief Dump a value into a string
205 * \return Heap string
207 char *SpiderScript_DumpValue(tSpiderValue *Value)
210 if( Value == ERRPTR )
211 return strdup("ERRPTR");
213 return strdup("null");
215 switch( (enum eSpiderScript_DataTypes)Value->Type )
217 case SS_DATATYPE_UNDEF: return strdup("undefined");
218 case SS_DATATYPE_NULL: return strdup("null type");
220 case SS_DATATYPE_INTEGER:
221 ret = malloc( sizeof(Value->Integer)*2 + 3 );
222 sprintf(ret, "0x%lx", Value->Integer);
225 case SS_DATATYPE_REAL:
226 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
227 sprintf(ret, "%f", Value->Real);
230 case SS_DATATYPE_STRING:
231 ret = malloc( Value->String.Length + 3 );
233 strcpy(ret+1, Value->String.Data);
234 ret[Value->String.Length+1] = '"';
235 ret[Value->String.Length+2] = '\0';
238 case SS_DATATYPE_OBJECT:
239 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
240 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
243 case SS_DATATYPE_OPAQUE:
244 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
245 sprintf(ret, "*%p", Value->Opaque.Data);
248 case SS_DATATYPE_ARRAY:
249 return strdup("Array");
252 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_Dump\n", Value->Type);
259 * \brief Execute an AST node and return its value
261 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
264 tSpiderValue *ret = NULL, *tmpobj;
265 tSpiderValue *op1, *op2; // Binary operations
266 int cmp; // Used in comparisons
271 case NODETYPE_NOP: ret = NULL; break;
276 tAST_BlockState blockInfo;
277 blockInfo.FirstVar = NULL;
278 blockInfo.RetVal = NULL;
279 blockInfo.Parent = Block;
280 blockInfo.Script = Block->Script;
282 for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
284 tmpobj = AST_ExecuteNode(&blockInfo, node);
285 if(tmpobj == ERRPTR) { // Error check
289 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
291 // Clean up variables
292 while(blockInfo.FirstVar)
294 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
295 Variable_Destroy( blockInfo.FirstVar );
296 blockInfo.FirstVar = nextVar;
299 if( blockInfo.RetVal )
300 Block->RetVal = blockInfo.RetVal;
306 case NODETYPE_ASSIGN:
307 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
308 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
311 ret = AST_ExecuteNode(Block, Node->Assign.Value);
313 Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
317 case NODETYPE_FUNCTIONCALL:
320 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
323 // Logical block (used to allocate `params`)
325 tSpiderValue *params[nParams];
327 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
328 params[i] = AST_ExecuteNode(Block, node);
329 if( params[i] == ERRPTR ) {
330 while(i--) Object_Dereference(params[i]);
337 // Call the function (SpiderScript_ExecuteMethod does the
338 // required namespace handling)
339 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
341 // Dereference parameters
342 while(i--) Object_Dereference(params[i]);
351 ret = AST_ExecuteNode(Block, Node->If.Condition);
352 if( SpiderScript_IsValueTrue(ret) ) {
353 AST_ExecuteNode(Block, Node->If.True);
356 AST_ExecuteNode(Block, Node->If.False);
358 Object_Dereference(ret);
363 ret = AST_ExecuteNode(Block, Node->For.Init);
364 if( Node->For.bCheckAfter ) {
366 Object_Dereference(ret);
367 ret = AST_ExecuteNode(Block, Node->For.Code);
368 Object_Dereference(ret);
369 ret = AST_ExecuteNode(Block, Node->For.Condition);
370 } while( SpiderScript_IsValueTrue(ret) );
373 Object_Dereference(ret);
374 ret = AST_ExecuteNode(Block, Node->For.Condition);
375 while( SpiderScript_IsValueTrue(ret) ) {
376 Object_Dereference(ret);
377 ret = AST_ExecuteNode(Block, Node->For.Code);
378 Object_Dereference(ret);
379 ret = AST_ExecuteNode(Block, Node->For.Condition);
381 Object_Dereference(ret);
386 case NODETYPE_RETURN:
387 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
388 Block->RetVal = ret; // Return value set
392 case NODETYPE_DEFVAR:
394 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
399 case NODETYPE_VARIABLE:
400 ret = Variable_GetValue( Block, Node->Variable.Name );
403 // Cast a value to another
405 ret = SpiderScript_CastValueTo(
407 AST_ExecuteNode(Block, Node->Cast.Value)
411 // Index into an array
413 fprintf(stderr, "TODO: Array indexing\n");
417 // TODO: Implement runtime constants
418 case NODETYPE_CONSTANT:
419 fprintf(stderr, "TODO: Runtime Constants\n");
423 case NODETYPE_STRING: ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data ); break;
424 case NODETYPE_INTEGER: ret = SpiderScript_CreateInteger( Node->Integer ); break;
425 case NODETYPE_REAL: ret = SpiderScript_CreateReal( Node->Real ); break;
427 // --- Operations ---
428 // Boolean Operations
429 case NODETYPE_LOGICALAND: // Logical AND (&&)
430 case NODETYPE_LOGICALOR: // Logical OR (||)
431 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
432 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
433 if(op1 == ERRPTR) return ERRPTR;
434 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
436 Object_Dereference(op1);
442 case NODETYPE_LOGICALAND:
443 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
445 case NODETYPE_LOGICALOR:
446 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
448 case NODETYPE_LOGICALXOR:
449 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
454 // Free intermediate objects
455 Object_Dereference(op1);
456 Object_Dereference(op2);
460 case NODETYPE_EQUALS:
461 case NODETYPE_LESSTHAN:
462 case NODETYPE_GREATERTHAN:
463 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
464 if(op1 == ERRPTR) return ERRPTR;
465 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
467 Object_Dereference(op1);
471 // No conversion done for NULL
472 // TODO: Determine if this will ever be needed
473 if( op1->Type == SS_DATATYPE_NULL )
475 // NULLs always typecheck
476 ret = SpiderScript_CreateInteger(op2->Type == SS_DATATYPE_NULL);
481 if( op1->Type != op2->Type ) {
482 // If dynamically typed, convert op2 to op1's type
483 if(Block->Script->Variant->bDyamicTyped)
486 op2 = SpiderScript_CastValueTo(op1->Type, op2);
487 Object_Dereference(tmpobj);
489 Object_Dereference(op1);
493 // If statically typed, this should never happen, but catch it anyway
495 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
504 case SS_DATATYPE_NULL: break;
505 // - String Compare (does a strcmp, well memcmp)
506 case SS_DATATYPE_STRING:
507 // Call memcmp to do most of the work
509 op1->String.Data, op2->String.Data,
510 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
512 // Handle reaching the end of the string
514 if( op1->String.Length == op2->String.Length )
516 else if( op1->String.Length < op2->String.Length )
523 fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
528 // Free intermediate objects
529 Object_Dereference(op1);
530 Object_Dereference(op2);
539 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
540 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
541 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
543 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
549 // General Binary Operations
551 case NODETYPE_SUBTRACT:
552 case NODETYPE_MULTIPLY:
553 case NODETYPE_DIVIDE:
554 case NODETYPE_MODULO:
558 case NODETYPE_BITSHIFTLEFT:
559 case NODETYPE_BITSHIFTRIGHT:
560 case NODETYPE_BITROTATELEFT:
562 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
563 if(op1 == ERRPTR) return ERRPTR;
564 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
566 Object_Dereference(op1);
571 if( op1 && op2 && op1->Type != op2->Type ) {
572 // If dynamically typed, convert op2 to op1's type
573 if(Block->Script->Variant->bDyamicTyped)
576 op2 = SpiderScript_CastValueTo(op1->Type, op2);
577 Object_Dereference(tmpobj);
579 Object_Dereference(op1);
583 // If statically typed, this should never happen, but catch it anyway
585 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
594 case SS_DATATYPE_NULL: break;
595 // String Concatenation
596 case SS_DATATYPE_STRING:
599 case NODETYPE_ADD: // Concatenate
600 ret = Object_StringConcat(op1, op2);
603 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
608 // Integer Operations
609 case SS_DATATYPE_INTEGER:
612 case NODETYPE_ADD: ret = SpiderScript_CreateInteger( op1->Integer + op2->Integer ); break;
613 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( op1->Integer - op2->Integer ); break;
614 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( op1->Integer * op2->Integer ); break;
615 case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( op1->Integer / op2->Integer ); break;
616 case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( op1->Integer % op2->Integer ); break;
617 case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( op1->Integer & op2->Integer ); break;
618 case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( op1->Integer | op2->Integer ); break;
619 case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( op1->Integer ^ op2->Integer ); break;
620 case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( op1->Integer << op2->Integer ); break;
621 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( op1->Integer >> op2->Integer ); break;
622 case NODETYPE_BITROTATELEFT:
623 ret = SpiderScript_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
626 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
633 case SS_DATATYPE_REAL:
637 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
644 fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
649 // Free intermediate objects
650 Object_Dereference(op1);
651 Object_Dereference(op2);
656 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
664 * \brief Define a variable
665 * \param Block Current block state
666 * \param Type Type of the variable
667 * \param Name Name of the variable
668 * \return Boolean Failure
670 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
672 tAST_Variable *var, *prev = NULL;
674 for( var = Block->FirstVar; var; prev = var, var = var->Next )
676 if( strcmp(var->Name, Name) == 0 ) {
677 fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
682 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
686 strcpy(var->Name, Name);
688 if(prev) prev->Next = var;
689 else Block->FirstVar = var;
691 //printf("Defined variable %s (%i)\n", Name, Type);
697 * \brief Set the value of a variable
699 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
704 for( bs = Block; bs; bs = bs->Parent )
706 for( var = bs->FirstVar; var; var = var->Next )
708 if( strcmp(var->Name, Name) == 0 ) {
709 if( !Block->Script->Variant->bDyamicTyped
710 && (Value && var->Type != Value->Type) ) {
711 fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
714 Object_Reference(Value);
715 Object_Dereference(var->Object);
722 if( Block->Script->Variant->bDyamicTyped )
725 var = Variable_Define(Block, Value->Type, Name);
726 Object_Reference(Value);
731 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
736 * \brief Get the value of a variable
738 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
743 for( bs = Block; bs; bs = bs->Parent )
745 for( var = bs->FirstVar; var; var = var->Next )
747 if( strcmp(var->Name, Name) == 0 ) {
748 Object_Reference(var->Object);
754 fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
760 * \brief Destorys a variable
762 void Variable_Destroy(tAST_Variable *Variable)
764 Object_Dereference(Variable->Object);