SpiderScript - Changed method of defining variant functions (now easier to do)
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_ast.c
1 /*
2  */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include "ast.h"
7
8 // === PROTOTYPES ===
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);
17
18 tSpiderValue    *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
19
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);
24
25 // === CODE ===
26 /**
27  * \brief Dereference a created object
28  */
29 void Object_Dereference(tSpiderValue *Object)
30 {
31         if(!Object)     return ;
32         Object->ReferenceCount --;
33         if( Object->ReferenceCount == 0 ) {
34                 switch( (enum eSpiderScript_DataTypes) Object->Type )
35                 {
36                 case SS_DATATYPE_OBJECT:
37                         Object->Object->Type->Destructor( Object->Object );
38                         break;
39                 case SS_DATATYPE_OPAQUE:
40                         Object->Opaque.Destroy( Object->Opaque.Data );
41                         break;
42                 default:
43                         break;
44                 }
45                 free(Object);
46         }
47 }
48
49 void Object_Reference(tSpiderValue *Object)
50 {
51         if(!Object)     return ;
52         Object->ReferenceCount ++;
53 }
54
55 /**
56  * \brief Create an integer object
57  */
58 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
59 {
60         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
61         ret->Type = SS_DATATYPE_INTEGER;
62         ret->ReferenceCount = 1;
63         ret->Integer = Value;
64         return ret;
65 }
66
67 /**
68  * \brief Create an real number object
69  */
70 tSpiderValue *SpiderScript_CreateReal(double Value)
71 {
72         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
73         ret->Type = SS_DATATYPE_REAL;
74         ret->ReferenceCount = 1;
75         ret->Real = Value;
76         return ret;
77 }
78
79 /**
80  * \brief Create an string object
81  */
82 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
83 {
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';
90         return ret;
91 }
92
93 /**
94  * \brief Concatenate two strings
95  */
96 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
97 {
98          int    newLen = 0;
99         tSpiderValue    *ret;
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;
106         if(Str1)
107                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
108         if(Str2) {
109                 if(Str1)
110                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
111                 else
112                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
113         }
114         ret->String.Data[ newLen ] = '\0';
115         return ret;
116 }
117
118 /**
119  * \brief Cast one object to another
120  * \brief Type  Destination type
121  * \brief Source        Input data
122  */
123 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
124 {
125         tSpiderValue    *ret = ERRPTR;
126         // Check if anything needs to be done
127         if( Source->Type == Type ) {
128                 Object_Reference(Source);
129                 return Source;
130         }
131         
132         switch( (enum eSpiderScript_DataTypes)Type )
133         {
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);
139                 return ERRPTR;
140         
141         case SS_DATATYPE_INTEGER:
142                 ret = malloc(sizeof(tSpiderValue));
143                 ret->Type = SS_DATATYPE_INTEGER;
144                 ret->ReferenceCount = 1;
145                 switch(Source->Type)
146                 {
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;
150                 default:
151                         fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
152                         free(ret);
153                         ret = ERRPTR;
154                         break;
155                 }
156                 break;
157         default:
158                 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
159                 break;
160         }
161         
162         return ret;
163 }
164
165 /**
166  * \brief Condenses a value down to a boolean
167  */
168 int SpiderScript_IsValueTrue(tSpiderValue *Value)
169 {
170         if( Value == ERRPTR )   return 0;
171         if( Value == NULL )     return 0;
172         
173         switch( (enum eSpiderScript_DataTypes)Value->Type )
174         {
175         case SS_DATATYPE_UNDEF:
176         case SS_DATATYPE_NULL:
177                 return 0;
178         
179         case SS_DATATYPE_INTEGER:
180                 return !!Value->Integer;
181         
182         case SS_DATATYPE_REAL:
183                 return (-.5f < Value->Real && Value->Real < 0.5f);
184         
185         case SS_DATATYPE_STRING:
186                 return Value->String.Length > 0;
187         
188         case SS_DATATYPE_OBJECT:
189                 return Value->Object != NULL;
190         
191         case SS_DATATYPE_OPAQUE:
192                 return Value->Opaque.Data != NULL;
193         
194         case SS_DATATYPE_ARRAY:
195                 return Value->Array.Length > 0;
196         default:
197                 fprintf(stderr, "Spiderscript internal error: Unknown type %i in SpiderScript_IsValueTrue\n", Value->Type);
198                 return 0;
199         }
200         return 0;
201 }
202
203 /**
204  * \brief Dump a value into a string
205  * \return Heap string
206  */
207 char *SpiderScript_DumpValue(tSpiderValue *Value)
208 {
209         char    *ret;
210         if( Value == ERRPTR )
211                 return strdup("ERRPTR");
212         if( Value == NULL )
213                 return strdup("null");
214         
215         switch( (enum eSpiderScript_DataTypes)Value->Type )
216         {
217         case SS_DATATYPE_UNDEF: return strdup("undefined");
218         case SS_DATATYPE_NULL:  return strdup("null type");
219         
220         case SS_DATATYPE_INTEGER:
221                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
222                 sprintf(ret, "0x%lx", Value->Integer);
223                 return ret;
224         
225         case SS_DATATYPE_REAL:
226                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
227                 sprintf(ret, "%f", Value->Real);
228                 return ret;
229         
230         case SS_DATATYPE_STRING:
231                 ret = malloc( Value->String.Length + 3 );
232                 ret[0] = '"';
233                 strcpy(ret+1, Value->String.Data);
234                 ret[Value->String.Length+1] = '"';
235                 ret[Value->String.Length+2] = '\0';
236                 return ret;
237         
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);
241                 return ret;
242         
243         case SS_DATATYPE_OPAQUE:
244                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
245                 sprintf(ret, "*%p", Value->Opaque.Data);
246                 return ret;
247         
248         case SS_DATATYPE_ARRAY:
249                 return strdup("Array");
250         
251         default:
252                 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_Dump\n", Value->Type);
253                 return NULL;
254         }
255         
256 }
257
258 /**
259  * \brief Execute an AST node and return its value
260  */
261 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
262 {
263         tAST_Node       *node;
264         tSpiderValue    *ret = NULL, *tmpobj;
265         tSpiderValue    *op1, *op2;     // Binary operations
266          int    cmp;    // Used in comparisons
267         
268         switch(Node->Type)
269         {
270         // No Operation
271         case NODETYPE_NOP:      ret = NULL;     break;
272         
273         // Code block
274         case NODETYPE_BLOCK:
275                 {
276                         tAST_BlockState blockInfo;
277                         blockInfo.FirstVar = NULL;
278                         blockInfo.RetVal = NULL;
279                         blockInfo.Parent = Block;
280                         blockInfo.Script = Block->Script;
281                         ret = NULL;
282                         for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
283                         {
284                                 tmpobj = AST_ExecuteNode(&blockInfo, node);
285                                 if(tmpobj == ERRPTR) {  // Error check
286                                         ret = ERRPTR;
287                                         break ;
288                                 }
289                                 if(tmpobj)      Object_Dereference(tmpobj);     // Free unused value
290                         }
291                         // Clean up variables
292                         while(blockInfo.FirstVar)
293                         {
294                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
295                                 Variable_Destroy( blockInfo.FirstVar );
296                                 blockInfo.FirstVar = nextVar;
297                         }
298                         
299                         if( blockInfo.RetVal )
300                                 Block->RetVal = blockInfo.RetVal;
301                 }
302                 
303                 break;
304         
305         // Assignment
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");
309                         return ERRPTR;
310                 }
311                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
312                 if(ret != ERRPTR)
313                         Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
314                 break;
315         
316         // Function Call
317         case NODETYPE_FUNCTIONCALL:
318                 {
319                          int    nParams = 0;
320                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
321                                 nParams ++;
322                         }
323                         // Logical block (used to allocate `params`)
324                         {
325                                 tSpiderValue    *params[nParams];
326                                  int    i=0;
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]);
331                                                 ret = ERRPTR;
332                                                 goto _return;
333                                         }
334                                         i ++;
335                                 }
336                                 
337                                 // Call the function (SpiderScript_ExecuteMethod does the
338                                 // required namespace handling)
339                                 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
340                                 
341                                 // Dereference parameters
342                                 while(i--)      Object_Dereference(params[i]);
343                                 
344                                 // falls out
345                         }
346                 }
347                 break;
348         
349         // Conditional
350         case NODETYPE_IF:
351                 ret = AST_ExecuteNode(Block, Node->If.Condition);
352                 if( SpiderScript_IsValueTrue(ret) ) {
353                         AST_ExecuteNode(Block, Node->If.True);
354                 }
355                 else {
356                         AST_ExecuteNode(Block, Node->If.False);
357                 }
358                 Object_Dereference(ret);
359                 break;
360         
361         // Loop
362         case NODETYPE_LOOP:
363                 ret = AST_ExecuteNode(Block, Node->For.Init);
364                 if( Node->For.bCheckAfter ) {
365                         do {
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) );
371                 }
372                 else {
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);
380                         }
381                         Object_Dereference(ret);
382                 }
383                 break;
384         
385         // Return
386         case NODETYPE_RETURN:
387                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
388                 Block->RetVal = ret;    // Return value set
389                 break;
390         
391         // Define a variable
392         case NODETYPE_DEFVAR:
393                 ret = NULL;
394                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
395                         ret = ERRPTR;
396                 break;
397         
398         // Variable
399         case NODETYPE_VARIABLE:
400                 ret = Variable_GetValue( Block, Node->Variable.Name );
401                 break;
402
403         // Cast a value to another
404         case NODETYPE_CAST:
405                 ret = SpiderScript_CastValueTo(
406                         Node->Cast.DataType,
407                         AST_ExecuteNode(Block, Node->Cast.Value)
408                         );
409                 break;
410
411         // Index into an array
412         case NODETYPE_INDEX:
413                 fprintf(stderr, "TODO: Array indexing\n");
414                 ret = ERRPTR;
415                 break;
416
417         // TODO: Implement runtime constants
418         case NODETYPE_CONSTANT:
419                 fprintf(stderr, "TODO: Runtime Constants\n");
420                 ret = ERRPTR;
421                 break;
422         // Constant Values
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;
426         
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);
435                 if(op2 == ERRPTR) {
436                         Object_Dereference(op1);
437                         return ERRPTR;
438                 }
439                 
440                 switch( Node->Type )
441                 {
442                 case NODETYPE_LOGICALAND:
443                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
444                         break;
445                 case NODETYPE_LOGICALOR:
446                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
447                         break;
448                 case NODETYPE_LOGICALXOR:
449                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
450                         break;
451                 default:        break;
452                 }
453                 
454                 // Free intermediate objects
455                 Object_Dereference(op1);
456                 Object_Dereference(op2);
457                 break;
458         
459         // Comparisons
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);
466                 if(op2 == ERRPTR) {
467                         Object_Dereference(op1);
468                         return ERRPTR;
469                 }
470                 
471                 // No conversion done for NULL
472                 // TODO: Determine if this will ever be needed
473                 if( op1->Type == SS_DATATYPE_NULL )
474                 {
475                         // NULLs always typecheck
476                         ret = SpiderScript_CreateInteger(op2->Type == SS_DATATYPE_NULL);
477                         break;
478                 }
479                 
480                 // Convert types
481                 if( op1->Type != op2->Type ) {
482                         // If dynamically typed, convert op2 to op1's type
483                         if(Block->Script->Variant->bDyamicTyped)
484                         {
485                                 tmpobj = op2;
486                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
487                                 Object_Dereference(tmpobj);
488                                 if(op2 == ERRPTR) {
489                                         Object_Dereference(op1);
490                                         return ERRPTR;
491                                 }
492                         }
493                         // If statically typed, this should never happen, but catch it anyway
494                         else {
495                                 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
496                                 ret = ERRPTR;
497                                 break;
498                         }
499                 }
500                 // Do operation
501                 switch(op1->Type)
502                 {
503                 // - NULL
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
508                         cmp = memcmp(
509                                 op1->String.Data, op2->String.Data,
510                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
511                                 );
512                         // Handle reaching the end of the string
513                         if( cmp == 0 ) {
514                                 if( op1->String.Length == op2->String.Length )
515                                         cmp = 0;
516                                 else if( op1->String.Length < op2->String.Length )
517                                         cmp = 1;
518                                 else
519                                         cmp = -1;
520                         }
521                         break;
522                 default:
523                         fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
524                         ret = ERRPTR;
525                         break;
526                 }
527                 
528                 // Free intermediate objects
529                 Object_Dereference(op1);
530                 Object_Dereference(op2);
531                 
532                 // Error check
533                 if( ret == ERRPTR )
534                         break;
535                 
536                 // Create return
537                 switch(Node->Type)
538                 {
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;
542                 default:
543                         fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
544                         ret = ERRPTR;
545                         break;
546                 }
547                 break;
548         
549         // General Binary Operations
550         case NODETYPE_ADD:
551         case NODETYPE_SUBTRACT:
552         case NODETYPE_MULTIPLY:
553         case NODETYPE_DIVIDE:
554         case NODETYPE_MODULO:
555         case NODETYPE_BWAND:
556         case NODETYPE_BWOR:
557         case NODETYPE_BWXOR:
558         case NODETYPE_BITSHIFTLEFT:
559         case NODETYPE_BITSHIFTRIGHT:
560         case NODETYPE_BITROTATELEFT:
561                 // Get operands
562                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
563                 if(op1 == ERRPTR)       return ERRPTR;
564                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
565                 if(op2 == ERRPTR) {
566                         Object_Dereference(op1);
567                         return ERRPTR;
568                 }
569                 
570                 // Convert types
571                 if( op1 && op2 && op1->Type != op2->Type ) {
572                         // If dynamically typed, convert op2 to op1's type
573                         if(Block->Script->Variant->bDyamicTyped)
574                         {
575                                 tmpobj = op2;
576                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
577                                 Object_Dereference(tmpobj);
578                                 if(op2 == ERRPTR) {
579                                         Object_Dereference(op1);
580                                         return ERRPTR;
581                                 }
582                         }
583                         // If statically typed, this should never happen, but catch it anyway
584                         else {
585                                 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
586                                 ret = ERRPTR;
587                                 break;
588                         }
589                 }
590                 
591                 // Do operation
592                 switch(op1->Type)
593                 {
594                 case SS_DATATYPE_NULL:  break;
595                 // String Concatenation
596                 case SS_DATATYPE_STRING:
597                         switch(Node->Type)
598                         {
599                         case NODETYPE_ADD:      // Concatenate
600                                 ret = Object_StringConcat(op1, op2);
601                                 break;
602                         default:
603                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
604                                 ret = ERRPTR;
605                                 break;
606                         }
607                         break;
608                 // Integer Operations
609                 case SS_DATATYPE_INTEGER:
610                         switch(Node->Type)
611                         {
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)) );
624                                 break;
625                         default:
626                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
627                                 ret = ERRPTR;
628                                 break;
629                         }
630                         break;
631                 
632                 // Real Numbers
633                 case SS_DATATYPE_REAL:
634                         switch(Node->Type)
635                         {
636                         default:
637                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
638                                 ret = ERRPTR;
639                                 break;
640                         }
641                         break;
642                 
643                 default:
644                         fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
645                         ret = ERRPTR;
646                         break;
647                 }
648                 
649                 // Free intermediate objects
650                 Object_Dereference(op1);
651                 Object_Dereference(op2);
652                 break;
653         
654         //default:
655         //      ret = NULL;
656         //      fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
657         //      break;
658         }
659 _return:
660         return ret;
661 }
662
663 /**
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
669  */
670 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
671 {
672         tAST_Variable   *var, *prev = NULL;
673         
674         for( var = Block->FirstVar; var; prev = var, var = var->Next )
675         {
676                 if( strcmp(var->Name, Name) == 0 ) {
677                         fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
678                         return ERRPTR;
679                 }
680         }
681         
682         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
683         var->Next = NULL;
684         var->Type = Type;
685         var->Object = NULL;
686         strcpy(var->Name, Name);
687         
688         if(prev)        prev->Next = var;
689         else    Block->FirstVar = var;
690         
691         //printf("Defined variable %s (%i)\n", Name, Type);
692         
693         return var;
694 }
695
696 /**
697  * \brief Set the value of a variable
698  */
699 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
700 {
701         tAST_Variable   *var;
702         tAST_BlockState *bs;
703         
704         for( bs = Block; bs; bs = bs->Parent )
705         {
706                 for( var = bs->FirstVar; var; var = var->Next )
707                 {
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);
712                                         return ;
713                                 }
714                                 Object_Reference(Value);
715                                 Object_Dereference(var->Object);
716                                 var->Object = Value;
717                                 return ;
718                         }
719                 }
720         }
721         
722         if( Block->Script->Variant->bDyamicTyped )
723         {
724                 // Define variable
725                 var = Variable_Define(Block, Value->Type, Name);
726                 Object_Reference(Value);
727                 var->Object = Value;
728         }
729         else
730         {
731                 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
732         }
733 }
734
735 /**
736  * \brief Get the value of a variable
737  */
738 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
739 {
740         tAST_Variable   *var;
741         tAST_BlockState *bs;
742         
743         for( bs = Block; bs; bs = bs->Parent )
744         {
745                 for( var = bs->FirstVar; var; var = var->Next )
746                 {
747                         if( strcmp(var->Name, Name) == 0 ) {
748                                 Object_Reference(var->Object);
749                                 return var->Object;
750                         }
751                 }
752         }
753         
754         fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
755         
756         return ERRPTR;
757 }
758
759 /**
760  * \brief Destorys a variable
761  */
762 void Variable_Destroy(tAST_Variable *Variable)
763 {
764         Object_Dereference(Variable->Object);
765         free(Variable);
766 }

UCC git Repository :: git.ucc.asn.au