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 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 // Check if anything needs to be done
130 if( Source->Type == Type ) {
131 Object_Reference(Source);
135 switch( (enum eSpiderScript_DataTypes)Type )
137 case SS_DATATYPE_UNDEF:
138 case SS_DATATYPE_NULL:
139 case SS_DATATYPE_ARRAY:
140 case SS_DATATYPE_OPAQUE:
141 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast to %i\n", Type);
144 case SS_DATATYPE_INTEGER:
145 ret = malloc(sizeof(tSpiderValue));
146 ret->Type = SS_DATATYPE_INTEGER;
147 ret->ReferenceCount = 1;
150 case SS_DATATYPE_INTEGER: break; // Handled above
151 case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break;
152 case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
154 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
161 case SS_DATATYPE_STRING:
164 case SS_DATATYPE_INTEGER: len = snprintf(NULL, 0, "%li", Source->Integer); break;
165 case SS_DATATYPE_REAL: snprintf(NULL, 0, "%f", Source->Real); break;
168 ret = malloc(sizeof(tSpiderValue) + len + 1);
169 ret->Type = SS_DATATYPE_STRING;
170 ret->ReferenceCount = 1;
171 ret->String.Length = len;
174 case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break;
175 case SS_DATATYPE_REAL: sprintf(ret->String.Data, "%f", Source->Real); break;
177 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
185 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
193 * \brief Condenses a value down to a boolean
195 int SpiderScript_IsValueTrue(tSpiderValue *Value)
197 if( Value == ERRPTR ) return 0;
198 if( Value == NULL ) return 0;
200 switch( (enum eSpiderScript_DataTypes)Value->Type )
202 case SS_DATATYPE_UNDEF:
203 case SS_DATATYPE_NULL:
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");
245 case SS_DATATYPE_NULL: return strdup("null type");
247 case SS_DATATYPE_INTEGER:
248 ret = malloc( sizeof(Value->Integer)*2 + 3 );
249 sprintf(ret, "0x%lx", Value->Integer);
252 case SS_DATATYPE_REAL:
253 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
254 sprintf(ret, "%f", Value->Real);
257 case SS_DATATYPE_STRING:
258 ret = malloc( Value->String.Length + 3 );
260 strcpy(ret+1, Value->String.Data);
261 ret[Value->String.Length+1] = '"';
262 ret[Value->String.Length+2] = '\0';
265 case SS_DATATYPE_OBJECT:
266 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
267 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
270 case SS_DATATYPE_OPAQUE:
271 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
272 sprintf(ret, "*%p", Value->Opaque.Data);
275 case SS_DATATYPE_ARRAY:
276 return strdup("Array");
279 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_Dump\n", Value->Type);
286 * \brief Execute an AST node and return its value
288 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
291 tSpiderValue *ret = NULL, *tmpobj;
292 tSpiderValue *op1, *op2; // Binary operations
293 int cmp; // Used in comparisons
298 case NODETYPE_NOP: ret = NULL; break;
303 tAST_BlockState blockInfo;
304 blockInfo.FirstVar = NULL;
305 blockInfo.RetVal = NULL;
306 blockInfo.Parent = Block;
307 blockInfo.Script = Block->Script;
309 for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
311 tmpobj = AST_ExecuteNode(&blockInfo, node);
312 if(tmpobj == ERRPTR) { // Error check
316 if(tmpobj) Object_Dereference(tmpobj); // Free unused value
318 // Clean up variables
319 while(blockInfo.FirstVar)
321 tAST_Variable *nextVar = blockInfo.FirstVar->Next;
322 Variable_Destroy( blockInfo.FirstVar );
323 blockInfo.FirstVar = nextVar;
326 if( blockInfo.RetVal )
327 Block->RetVal = blockInfo.RetVal;
333 case NODETYPE_ASSIGN:
334 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
335 fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
338 ret = AST_ExecuteNode(Block, Node->Assign.Value);
340 Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
344 case NODETYPE_FUNCTIONCALL:
347 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
350 // Logical block (used to allocate `params`)
352 tSpiderValue *params[nParams];
354 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
355 params[i] = AST_ExecuteNode(Block, node);
356 if( params[i] == ERRPTR ) {
357 while(i--) Object_Dereference(params[i]);
364 // Call the function (SpiderScript_ExecuteMethod does the
365 // required namespace handling)
366 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
368 // Dereference parameters
369 while(i--) Object_Dereference(params[i]);
378 ret = AST_ExecuteNode(Block, Node->If.Condition);
379 if( SpiderScript_IsValueTrue(ret) ) {
380 AST_ExecuteNode(Block, Node->If.True);
383 AST_ExecuteNode(Block, Node->If.False);
385 Object_Dereference(ret);
390 ret = AST_ExecuteNode(Block, Node->For.Init);
391 if( Node->For.bCheckAfter ) {
393 Object_Dereference(ret);
394 ret = AST_ExecuteNode(Block, Node->For.Code);
395 Object_Dereference(ret);
396 ret = AST_ExecuteNode(Block, Node->For.Condition);
397 } while( SpiderScript_IsValueTrue(ret) );
400 Object_Dereference(ret);
401 ret = AST_ExecuteNode(Block, Node->For.Condition);
402 while( SpiderScript_IsValueTrue(ret) ) {
403 Object_Dereference(ret);
404 ret = AST_ExecuteNode(Block, Node->For.Code);
405 Object_Dereference(ret);
406 ret = AST_ExecuteNode(Block, Node->For.Condition);
408 Object_Dereference(ret);
413 case NODETYPE_RETURN:
414 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
415 Block->RetVal = ret; // Return value set
419 case NODETYPE_DEFVAR:
421 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
426 case NODETYPE_VARIABLE:
427 ret = Variable_GetValue( Block, Node->Variable.Name );
430 // Cast a value to another
432 ret = SpiderScript_CastValueTo(
434 AST_ExecuteNode(Block, Node->Cast.Value)
438 // Index into an array
440 fprintf(stderr, "TODO: Array indexing\n");
444 // TODO: Implement runtime constants
445 case NODETYPE_CONSTANT:
446 fprintf(stderr, "TODO: Runtime Constants\n");
450 case NODETYPE_STRING: ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data ); break;
451 case NODETYPE_INTEGER: ret = SpiderScript_CreateInteger( Node->Integer ); break;
452 case NODETYPE_REAL: ret = SpiderScript_CreateReal( Node->Real ); break;
454 // --- Operations ---
455 // Boolean Operations
456 case NODETYPE_LOGICALAND: // Logical AND (&&)
457 case NODETYPE_LOGICALOR: // Logical OR (||)
458 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
459 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
460 if(op1 == ERRPTR) return ERRPTR;
461 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
463 Object_Dereference(op1);
469 case NODETYPE_LOGICALAND:
470 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
472 case NODETYPE_LOGICALOR:
473 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
475 case NODETYPE_LOGICALXOR:
476 ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
481 // Free intermediate objects
482 Object_Dereference(op1);
483 Object_Dereference(op2);
487 case NODETYPE_EQUALS:
488 case NODETYPE_LESSTHAN:
489 case NODETYPE_GREATERTHAN:
490 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
491 if(op1 == ERRPTR) return ERRPTR;
492 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
494 Object_Dereference(op1);
498 // No conversion done for NULL
499 // TODO: Determine if this will ever be needed
500 if( op1->Type == SS_DATATYPE_NULL )
502 // NULLs always typecheck
503 ret = SpiderScript_CreateInteger(op2->Type == SS_DATATYPE_NULL);
508 if( op1->Type != op2->Type ) {
509 // If dynamically typed, convert op2 to op1's type
510 if(Block->Script->Variant->bDyamicTyped)
513 op2 = SpiderScript_CastValueTo(op1->Type, op2);
514 Object_Dereference(tmpobj);
516 Object_Dereference(op1);
520 // If statically typed, this should never happen, but catch it anyway
522 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast (line %i)\n",
532 case SS_DATATYPE_NULL: break;
533 // - String Compare (does a strcmp, well memcmp)
534 case SS_DATATYPE_STRING:
535 // Call memcmp to do most of the work
537 op1->String.Data, op2->String.Data,
538 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
540 // Handle reaching the end of the string
542 if( op1->String.Length == op2->String.Length )
544 else if( op1->String.Length < op2->String.Length )
551 fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
556 // Free intermediate objects
557 Object_Dereference(op1);
558 Object_Dereference(op2);
567 case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
568 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
569 case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
571 fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
577 // General Binary Operations
579 case NODETYPE_SUBTRACT:
580 case NODETYPE_MULTIPLY:
581 case NODETYPE_DIVIDE:
582 case NODETYPE_MODULO:
586 case NODETYPE_BITSHIFTLEFT:
587 case NODETYPE_BITSHIFTRIGHT:
588 case NODETYPE_BITROTATELEFT:
590 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
591 if(op1 == ERRPTR) return ERRPTR;
592 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
594 Object_Dereference(op1);
599 if( op1 && op2 && op1->Type != op2->Type ) {
600 // If dynamically typed, convert op2 to op1's type
601 if(Block->Script->Variant->bDyamicTyped)
604 op2 = SpiderScript_CastValueTo(op1->Type, op2);
605 Object_Dereference(tmpobj);
607 Object_Dereference(op1);
611 // If statically typed, this should never happen, but catch it anyway
614 "PARSER ERROR: Statically typed implicit cast (from %i to %i)\n",
625 case SS_DATATYPE_NULL: break;
626 // String Concatenation
627 case SS_DATATYPE_STRING:
630 case NODETYPE_ADD: // Concatenate
631 ret = Object_StringConcat(op1, op2);
634 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
639 // Integer Operations
640 case SS_DATATYPE_INTEGER:
643 case NODETYPE_ADD: ret = SpiderScript_CreateInteger( op1->Integer + op2->Integer ); break;
644 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( op1->Integer - op2->Integer ); break;
645 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( op1->Integer * op2->Integer ); break;
646 case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( op1->Integer / op2->Integer ); break;
647 case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( op1->Integer % op2->Integer ); break;
648 case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( op1->Integer & op2->Integer ); break;
649 case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( op1->Integer | op2->Integer ); break;
650 case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( op1->Integer ^ op2->Integer ); break;
651 case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( op1->Integer << op2->Integer ); break;
652 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( op1->Integer >> op2->Integer ); break;
653 case NODETYPE_BITROTATELEFT:
654 ret = SpiderScript_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
657 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
664 case SS_DATATYPE_REAL:
668 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
675 fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
680 // Free intermediate objects
681 Object_Dereference(op1);
682 Object_Dereference(op2);
687 // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
695 * \brief Define a variable
696 * \param Block Current block state
697 * \param Type Type of the variable
698 * \param Name Name of the variable
699 * \return Boolean Failure
701 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
703 tAST_Variable *var, *prev = NULL;
705 for( var = Block->FirstVar; var; prev = var, var = var->Next )
707 if( strcmp(var->Name, Name) == 0 ) {
708 fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
713 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
717 strcpy(var->Name, Name);
719 if(prev) prev->Next = var;
720 else Block->FirstVar = var;
722 //printf("Defined variable %s (%i)\n", Name, Type);
728 * \brief Set the value of a variable
730 void 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);
762 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
767 * \brief Get the value of a variable
769 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
774 for( bs = Block; bs; bs = bs->Parent )
776 for( var = bs->FirstVar; var; var = var->Next )
778 if( strcmp(var->Name, Name) == 0 ) {
779 Object_Reference(var->Object);
785 fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
791 * \brief Destorys a variable
793 void Variable_Destroy(tAST_Variable *Variable)
795 Object_Dereference(Variable->Object);