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 int 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 if(Object == ERRPTR) return ;
33 Object->ReferenceCount --;
34 if( Object->ReferenceCount == 0 ) {
35 switch( (enum eSpiderScript_DataTypes) Object->Type )
37 case SS_DATATYPE_OBJECT:
38 Object->Object->Type->Destructor( Object->Object );
40 case SS_DATATYPE_OPAQUE:
41 Object->Opaque.Destroy( Object->Opaque.Data );
50 void Object_Reference(tSpiderValue *Object)
53 Object->ReferenceCount ++;
57 * \brief Create an integer object
59 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
61 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
62 ret->Type = SS_DATATYPE_INTEGER;
63 ret->ReferenceCount = 1;
69 * \brief Create an real number object
71 tSpiderValue *SpiderScript_CreateReal(double Value)
73 tSpiderValue *ret = malloc( sizeof(tSpiderValue) );
74 ret->Type = SS_DATATYPE_REAL;
75 ret->ReferenceCount = 1;
81 * \brief Create an string object
83 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
85 tSpiderValue *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
86 ret->Type = SS_DATATYPE_STRING;
87 ret->ReferenceCount = 1;
88 ret->String.Length = Length;
89 memcpy(ret->String.Data, Data, Length);
90 ret->String.Data[Length] = '\0';
95 * \brief Concatenate two strings
97 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
101 if(Str1) newLen += Str1->String.Length;
102 if(Str2) newLen += Str2->String.Length;
103 ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
104 ret->Type = SS_DATATYPE_STRING;
105 ret->ReferenceCount = 1;
106 ret->String.Length = newLen;
108 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
111 memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
113 memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
115 ret->String.Data[ newLen ] = '\0';
120 * \brief Cast one object to another
121 * \brief Type Destination type
122 * \brief Source Input data
124 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
126 tSpiderValue *ret = ERRPTR;
129 if( !Source ) return NULL;
131 // Check if anything needs to be done
132 if( Source->Type == Type ) {
133 Object_Reference(Source);
137 switch( (enum eSpiderScript_DataTypes)Type )
139 case SS_DATATYPE_UNDEF:
140 case SS_DATATYPE_ARRAY:
141 case SS_DATATYPE_OPAQUE:
142 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast to %i\n", Type);
145 case SS_DATATYPE_INTEGER:
146 ret = malloc(sizeof(tSpiderValue));
147 ret->Type = SS_DATATYPE_INTEGER;
148 ret->ReferenceCount = 1;
151 case SS_DATATYPE_INTEGER: break; // Handled above
152 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
153 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
155 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
162 case SS_DATATYPE_STRING:
165 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
166 case SS_DATATYPE_REAL: snprintf(NULL, 0, "%f", Source->Real); break;
169 ret = malloc(sizeof(tSpiderValue) + len + 1);
170 ret->Type = SS_DATATYPE_STRING;
171 ret->ReferenceCount = 1;
172 ret->String.Length = len;
175 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
176 case SS_DATATYPE_REAL: sprintf(ret->String.Data, "%f", Source->Real); break;
178 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
186 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
194 * \brief Condenses a value down to a boolean
196 int SpiderScript_IsValueTrue(tSpiderValue *Value)
198 if( Value == ERRPTR ) return 0;
199 if( Value == NULL ) return 0;
201 switch( (enum eSpiderScript_DataTypes)Value->Type )
203 case SS_DATATYPE_UNDEF:
206 case SS_DATATYPE_INTEGER:
207 return !!Value->Integer;
209 case SS_DATATYPE_REAL:
210 return (-.5f < Value->Real && Value->Real < 0.5f);
212 case SS_DATATYPE_STRING:
213 return Value->String.Length > 0;
215 case SS_DATATYPE_OBJECT:
216 return Value->Object != NULL;
218 case SS_DATATYPE_OPAQUE:
219 return Value->Opaque.Data != NULL;
221 case SS_DATATYPE_ARRAY:
222 return Value->Array.Length > 0;
224 fprintf(stderr, "Spiderscript internal error: Unknown type %i in SpiderScript_IsValueTrue\n", Value->Type);
231 * \brief Dump a value into a string
232 * \return Heap string
234 char *SpiderScript_DumpValue(tSpiderValue *Value)
237 if( Value == ERRPTR )
238 return strdup("ERRPTR");
240 return strdup("null");
242 switch( (enum eSpiderScript_DataTypes)Value->Type )
244 case SS_DATATYPE_UNDEF: return strdup("undefined");
246 case SS_DATATYPE_INTEGER:
247 ret = malloc( sizeof(Value->Integer)*2 + 3 );
248 sprintf(ret, "0x%lx", Value->Integer);
251 case SS_DATATYPE_REAL:
252 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
253 sprintf(ret, "%f", Value->Real);
256 case SS_DATATYPE_STRING:
257 ret = malloc( Value->String.Length + 3 );
259 strcpy(ret+1, Value->String.Data);
260 ret[Value->String.Length+1] = '"';
261 ret[Value->String.Length+2] = '\0';
264 case SS_DATATYPE_OBJECT:
265 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
266 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
269 case SS_DATATYPE_OPAQUE:
270 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
271 sprintf(ret, "*%p", Value->Opaque.Data);
274 case SS_DATATYPE_ARRAY:
275 return strdup("Array");
278 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_Dump\n", Value->Type);
285 * \brief Execute an AST node and return its value
287 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
290 tSpiderValue *ret = NULL, *tmpobj;
291 tSpiderValue *op1, *op2; // Binary operations
292 int cmp; // Used in comparisons
297 case NODETYPE_NOP: ret = NULL; break;
302 tAST_BlockState blockInfo;
303 blockInfo.FirstVar = NULL;
304 blockInfo.RetVal = NULL;
305 blockInfo.Parent = Block;
306 blockInfo.Script = Block->Script;
308 for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
310 tmpobj = AST_ExecuteNode(&blockInfo, node);
311 if(tmpobj == ERRPTR) { // Error check
315 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
317 // Clean up variables
318 while(blockInfo.FirstVar)
320 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
321 Variable_Destroy( blockInfo.FirstVar );
322 blockInfo.FirstVar = nextVar;
325 if( blockInfo.RetVal )
326 Block->RetVal = blockInfo.RetVal;
332 case NODETYPE_ASSIGN:
333 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
334 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
337 ret = AST_ExecuteNode(Block, Node->Assign.Value);
340 if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) {
341 Object_Dereference( ret );
342 fprintf(stderr, "on line %i\n", Node->Line);
349 case NODETYPE_FUNCTIONCALL:
352 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
355 // Logical block (used to allocate `params`)
357 tSpiderValue *params[nParams];
359 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
360 params[i] = AST_ExecuteNode(Block, node);
361 if( params[i] == ERRPTR ) {
362 while(i--) Object_Dereference(params[i]);
369 // Call the function (SpiderScript_ExecuteMethod does the
370 // required namespace handling)
371 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
373 // Dereference parameters
374 while(i--) Object_Dereference(params[i]);
383 ret = AST_ExecuteNode(Block, Node->If.Condition);
384 if( SpiderScript_IsValueTrue(ret) ) {
385 AST_ExecuteNode(Block, Node->If.True);
388 AST_ExecuteNode(Block, Node->If.False);
390 Object_Dereference(ret);
395 ret = AST_ExecuteNode(Block, Node->For.Init);
396 if( Node->For.bCheckAfter ) {
398 Object_Dereference(ret);
399 ret = AST_ExecuteNode(Block, Node->For.Code);
400 Object_Dereference(ret);
401 ret = AST_ExecuteNode(Block, Node->For.Condition);
402 } while( SpiderScript_IsValueTrue(ret) );
405 Object_Dereference(ret);
406 ret = AST_ExecuteNode(Block, Node->For.Condition);
407 while( SpiderScript_IsValueTrue(ret) ) {
408 Object_Dereference(ret);
409 ret = AST_ExecuteNode(Block, Node->For.Code);
410 Object_Dereference(ret);
411 ret = AST_ExecuteNode(Block, Node->For.Condition);
413 Object_Dereference(ret);
418 case NODETYPE_RETURN:
419 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
420 Block->RetVal = ret; // Return value set
424 case NODETYPE_DEFVAR:
426 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
431 case NODETYPE_VARIABLE:
432 ret = Variable_GetValue( Block, Node->Variable.Name );
435 // Cast a value to another
437 ret = SpiderScript_CastValueTo(
439 AST_ExecuteNode(Block, Node->Cast.Value)
443 // Index into an array
445 fprintf(stderr, "TODO: Array indexing\n");
449 // TODO: Implement runtime constants
450 case NODETYPE_CONSTANT:
451 fprintf(stderr, "TODO: Runtime Constants\n");
455 case NODETYPE_STRING: ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data ); break;
456 case NODETYPE_INTEGER: ret = SpiderScript_CreateInteger( Node->Integer ); break;
457 case NODETYPE_REAL: ret = SpiderScript_CreateReal( Node->Real ); break;
459 // --- Operations ---
460 // Boolean Operations
461 case NODETYPE_LOGICALAND: // Logical AND (&&)
462 case NODETYPE_LOGICALOR: // Logical OR (||)
463 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
464 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
465 if(op1 == ERRPTR) return ERRPTR;
466 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
468 Object_Dereference(op1);
474 case NODETYPE_LOGICALAND:
475 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
477 case NODETYPE_LOGICALOR:
478 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
480 case NODETYPE_LOGICALXOR:
481 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
486 // Free intermediate objects
487 Object_Dereference(op1);
488 Object_Dereference(op2);
492 case NODETYPE_EQUALS:
493 case NODETYPE_LESSTHAN:
494 case NODETYPE_GREATERTHAN:
495 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
496 if(op1 == ERRPTR) return ERRPTR;
497 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
499 Object_Dereference(op1);
504 if( op1->Type != op2->Type ) {
505 // If dynamically typed, convert op2 to op1's type
506 if(Block->Script->Variant->bDyamicTyped)
509 op2 = SpiderScript_CastValueTo(op1->Type, op2);
510 Object_Dereference(tmpobj);
512 Object_Dereference(op1);
516 // If statically typed, this should never happen, but catch it anyway
518 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast (line %i)\n",
527 // - String Compare (does a strcmp, well memcmp)
528 case SS_DATATYPE_STRING:
529 // Call memcmp to do most of the work
531 op1->String.Data, op2->String.Data,
532 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
534 // Handle reaching the end of the string
536 if( op1->String.Length == op2->String.Length )
538 else if( op1->String.Length < op2->String.Length )
545 fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
550 // Free intermediate objects
551 Object_Dereference(op1);
552 Object_Dereference(op2);
561 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
562 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
563 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
565 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
571 // General Binary Operations
573 case NODETYPE_SUBTRACT:
574 case NODETYPE_MULTIPLY:
575 case NODETYPE_DIVIDE:
576 case NODETYPE_MODULO:
580 case NODETYPE_BITSHIFTLEFT:
581 case NODETYPE_BITSHIFTRIGHT:
582 case NODETYPE_BITROTATELEFT:
584 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
585 if(op1 == ERRPTR) return ERRPTR;
586 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
588 Object_Dereference(op1);
593 if( op1 && op2 && op1->Type != op2->Type ) {
594 // If dynamically typed, convert op2 to op1's type
595 if(Block->Script->Variant->bDyamicTyped)
598 op2 = SpiderScript_CastValueTo(op1->Type, op2);
599 Object_Dereference(tmpobj);
601 Object_Dereference(op1);
605 // If statically typed, this should never happen, but catch it anyway
608 "PARSER ERROR: Statically typed implicit cast (from %i to %i)\n",
617 if( op1 == NULL || op2 == NULL ) {
625 // String Concatenation
626 case SS_DATATYPE_STRING:
629 case NODETYPE_ADD: // Concatenate
630 ret = Object_StringConcat(op1, op2);
633 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
638 // Integer Operations
639 case SS_DATATYPE_INTEGER:
642 case NODETYPE_ADD: ret = SpiderScript_CreateInteger( op1->Integer + op2->Integer ); break;
643 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( op1->Integer - op2->Integer ); break;
644 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( op1->Integer * op2->Integer ); break;
645 case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( op1->Integer / op2->Integer ); break;
646 case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( op1->Integer % op2->Integer ); break;
647 case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( op1->Integer & op2->Integer ); break;
648 case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( op1->Integer | op2->Integer ); break;
649 case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( op1->Integer ^ op2->Integer ); break;
650 case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( op1->Integer << op2->Integer ); break;
651 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( op1->Integer >> op2->Integer ); break;
652 case NODETYPE_BITROTATELEFT:
653 ret = SpiderScript_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
656 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
663 case SS_DATATYPE_REAL:
667 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
674 fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
679 // Free intermediate objects
680 Object_Dereference(op1);
681 Object_Dereference(op2);
686 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
694 * \brief Define a variable
695 * \param Block Current block state
696 * \param Type Type of the variable
697 * \param Name Name of the variable
698 * \return Boolean Failure
700 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
702 tAST_Variable *var, *prev = NULL;
704 for( var = Block->FirstVar; var; prev = var, var = var->Next )
706 if( strcmp(var->Name, Name) == 0 ) {
707 fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
712 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
716 strcpy(var->Name, Name);
718 if(prev) prev->Next = var;
719 else Block->FirstVar = var;
721 //printf("Defined variable %s (%i)\n", Name, Type);
727 * \brief Set the value of a variable
728 * \return Boolean Failure
730 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
735 for( bs = Block; bs; bs = bs->Parent )
737 for( var = bs->FirstVar; var; var = var->Next )
739 if( strcmp(var->Name, Name) == 0 ) {
740 if( !Block->Script->Variant->bDyamicTyped
741 && (Value && var->Type != Value->Type) ) {
742 fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
745 Object_Reference(Value);
746 Object_Dereference(var->Object);
753 if( Block->Script->Variant->bDyamicTyped )
756 var = Variable_Define(Block, Value->Type, Name);
757 Object_Reference(Value);
763 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
769 * \brief Get the value of a variable
771 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
776 for( bs = Block; bs; bs = bs->Parent )
778 for( var = bs->FirstVar; var; var = var->Next )
780 if( strcmp(var->Name, Name) == 0 ) {
781 Object_Reference(var->Object);
787 fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
793 * \brief Destorys a variable
795 void Variable_Destroy(tAST_Variable *Variable)
797 Object_Dereference(Variable->Object);