SpiderScript - A day of debugging and improvements
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_ast.c
1 /*
2  */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <stdarg.h>
6 #include <string.h>
7 #include "ast.h"
8
9 // === PROTOTYPES ===
10 void    Object_Dereference(tSpiderValue *Object);
11 void    Object_Reference(tSpiderValue *Object);
12 tSpiderValue    *SpiderScript_CreateInteger(uint64_t Value);
13 tSpiderValue    *SpiderScript_CreateReal(double Value);
14 tSpiderValue    *SpiderScript_CreateString(int Length, const char *Data);
15 tSpiderValue    *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
16  int    SpiderScript_IsValueTrue(tSpiderValue *Value);
17 void    SpiderScript_FreeValue(tSpiderValue *Value);
18 char    *SpiderScript_DumpValue(tSpiderValue *Value);
19
20 tSpiderValue    *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
21 tSpiderValue    *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right);
22
23 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
24  int    Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
25 tSpiderValue    *Variable_GetValue(tAST_BlockState *Block, const char *Name);
26 void    Variable_Destroy(tAST_Variable *Variable);
27
28 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
29
30 // === CODE ===
31 /**
32  * \brief Dereference a created object
33  */
34 void Object_Dereference(tSpiderValue *Object)
35 {
36         if(!Object)     return ;
37         if(Object == ERRPTR)    return ;
38         Object->ReferenceCount --;
39 //      printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount);
40         if( Object->ReferenceCount == 0 ) {
41                 switch( (enum eSpiderScript_DataTypes) Object->Type )
42                 {
43                 case SS_DATATYPE_OBJECT:
44                         Object->Object->Type->Destructor( Object->Object );
45                         break;
46                 case SS_DATATYPE_OPAQUE:
47                         Object->Opaque.Destroy( Object->Opaque.Data );
48                         break;
49                 default:
50                         break;
51                 }
52                 free(Object);
53         }
54 }
55
56 void Object_Reference(tSpiderValue *Object)
57 {
58         if(!Object)     return ;
59         Object->ReferenceCount ++;
60 //      printf("%p Referenced (%i)\n", Object, Object->ReferenceCount);
61 }
62
63 /**
64  * \brief Create an integer object
65  */
66 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
67 {
68         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
69         ret->Type = SS_DATATYPE_INTEGER;
70         ret->ReferenceCount = 1;
71         ret->Integer = Value;
72         return ret;
73 }
74
75 /**
76  * \brief Create an real number object
77  */
78 tSpiderValue *SpiderScript_CreateReal(double Value)
79 {
80         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
81         ret->Type = SS_DATATYPE_REAL;
82         ret->ReferenceCount = 1;
83         ret->Real = Value;
84         return ret;
85 }
86
87 /**
88  * \brief Create an string object
89  */
90 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
91 {
92         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
93         ret->Type = SS_DATATYPE_STRING;
94         ret->ReferenceCount = 1;
95         ret->String.Length = Length;
96         memcpy(ret->String.Data, Data, Length);
97         ret->String.Data[Length] = '\0';
98         return ret;
99 }
100
101 /**
102  * \brief Concatenate two strings
103  */
104 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
105 {
106          int    newLen = 0;
107         tSpiderValue    *ret;
108         if(Str1)        newLen += Str1->String.Length;
109         if(Str2)        newLen += Str2->String.Length;
110         ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
111         ret->Type = SS_DATATYPE_STRING;
112         ret->ReferenceCount = 1;
113         ret->String.Length = newLen;
114         if(Str1)
115                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
116         if(Str2) {
117                 if(Str1)
118                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
119                 else
120                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
121         }
122         ret->String.Data[ newLen ] = '\0';
123         return ret;
124 }
125
126 /**
127  * \brief Cast one object to another
128  * \brief Type  Destination type
129  * \brief Source        Input data
130  */
131 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
132 {
133         tSpiderValue    *ret = ERRPTR;
134          int    len = 0;
135
136         if( !Source )   return NULL;
137         
138         // Check if anything needs to be done
139         if( Source->Type == Type ) {
140                 Object_Reference(Source);
141                 return Source;
142         }
143         
144         switch( (enum eSpiderScript_DataTypes)Type )
145         {
146         case SS_DATATYPE_UNDEF:
147         case SS_DATATYPE_ARRAY:
148         case SS_DATATYPE_OPAQUE:
149                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
150                 return ERRPTR;
151         
152         case SS_DATATYPE_INTEGER:
153                 ret = malloc(sizeof(tSpiderValue));
154                 ret->Type = SS_DATATYPE_INTEGER;
155                 ret->ReferenceCount = 1;
156                 switch(Source->Type)
157                 {
158                 case SS_DATATYPE_INTEGER:       break;  // Handled above
159                 case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
160                 case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
161                 default:
162                         AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
163                         free(ret);
164                         ret = ERRPTR;
165                         break;
166                 }
167                 break;
168         
169         case SS_DATATYPE_STRING:
170                 switch(Source->Type)
171                 {
172                 case SS_DATATYPE_INTEGER:       len = snprintf(NULL, 0, "%li", Source->Integer);        break;
173                 case SS_DATATYPE_REAL:  snprintf(NULL, 0, "%f", Source->Real);  break;
174                 default:        break;
175                 }
176                 ret = malloc(sizeof(tSpiderValue) + len + 1);
177                 ret->Type = SS_DATATYPE_STRING;
178                 ret->ReferenceCount = 1;
179                 ret->String.Length = len;
180                 switch(Source->Type)
181                 {
182                 case SS_DATATYPE_INTEGER:       sprintf(ret->String.Data, "%li", Source->Integer);      break;
183                 case SS_DATATYPE_REAL:  sprintf(ret->String.Data, "%f", Source->Real);  break;
184                 default:
185                         AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
186                         free(ret);
187                         ret = ERRPTR;
188                         break;
189                 }
190                 break;
191         
192         default:
193                 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target");
194                 break;
195         }
196         
197         return ret;
198 }
199
200 /**
201  * \brief Condenses a value down to a boolean
202  */
203 int SpiderScript_IsValueTrue(tSpiderValue *Value)
204 {
205         if( Value == ERRPTR )   return 0;
206         if( Value == NULL )     return 0;
207         
208         switch( (enum eSpiderScript_DataTypes)Value->Type )
209         {
210         case SS_DATATYPE_UNDEF:
211                 return 0;
212         
213         case SS_DATATYPE_INTEGER:
214                 return !!Value->Integer;
215         
216         case SS_DATATYPE_REAL:
217                 return (-.5f < Value->Real && Value->Real < 0.5f);
218         
219         case SS_DATATYPE_STRING:
220                 return Value->String.Length > 0;
221         
222         case SS_DATATYPE_OBJECT:
223                 return Value->Object != NULL;
224         
225         case SS_DATATYPE_OPAQUE:
226                 return Value->Opaque.Data != NULL;
227         
228         case SS_DATATYPE_ARRAY:
229                 return Value->Array.Length > 0;
230         default:
231                 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
232                 return 0;
233         }
234         return 0;
235 }
236
237 /**
238  * \brief Free a value
239  * \note Just calls Object_Dereference
240  */
241 void SpiderScript_FreeValue(tSpiderValue *Value)
242 {
243         Object_Dereference(Value);
244 }
245
246 /**
247  * \brief Dump a value into a string
248  * \return Heap string
249  */
250 char *SpiderScript_DumpValue(tSpiderValue *Value)
251 {
252         char    *ret;
253         if( Value == ERRPTR )
254                 return strdup("ERRPTR");
255         if( Value == NULL )
256                 return strdup("null");
257         
258         switch( (enum eSpiderScript_DataTypes)Value->Type )
259         {
260         case SS_DATATYPE_UNDEF: return strdup("undefined");
261         
262         case SS_DATATYPE_INTEGER:
263                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
264                 sprintf(ret, "0x%lx", Value->Integer);
265                 return ret;
266         
267         case SS_DATATYPE_REAL:
268                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
269                 sprintf(ret, "%f", Value->Real);
270                 return ret;
271         
272         case SS_DATATYPE_STRING:
273                 ret = malloc( Value->String.Length + 3 );
274                 ret[0] = '"';
275                 strcpy(ret+1, Value->String.Data);
276                 ret[Value->String.Length+1] = '"';
277                 ret[Value->String.Length+2] = '\0';
278                 return ret;
279         
280         case SS_DATATYPE_OBJECT:
281                 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
282                 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
283                 return ret;
284         
285         case SS_DATATYPE_OPAQUE:
286                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
287                 sprintf(ret, "*%p", Value->Opaque.Data);
288                 return ret;
289         
290         case SS_DATATYPE_ARRAY:
291                 return strdup("Array");
292         
293         default:
294                 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
295                 return NULL;
296         }
297         
298 }
299
300 /**
301  * \brief Execute an AST node and return its value
302  */
303 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
304 {
305         tAST_Node       *node;
306         tSpiderValue    *ret = NULL, *tmpobj;
307         tSpiderValue    *op1, *op2;     // Binary operations
308          int    cmp;    // Used in comparisons
309         
310         switch(Node->Type)
311         {
312         // No Operation
313         case NODETYPE_NOP:      ret = NULL;     break;
314         
315         // Code block
316         case NODETYPE_BLOCK:
317                 {
318                         tAST_BlockState blockInfo;
319                         blockInfo.FirstVar = NULL;
320                         blockInfo.RetVal = NULL;
321                         blockInfo.Parent = Block;
322                         blockInfo.Script = Block->Script;
323                         ret = NULL;
324                         for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
325                         {
326                                 tmpobj = AST_ExecuteNode(&blockInfo, node);
327                                 if(tmpobj == ERRPTR) {  // Error check
328                                         ret = ERRPTR;
329                                         break ;
330                                 }
331                                 if(tmpobj)      Object_Dereference(tmpobj);     // Free unused value
332                                 tmpobj = NULL;
333                         }
334                         // Clean up variables
335                         while(blockInfo.FirstVar)
336                         {
337                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
338                                 Variable_Destroy( blockInfo.FirstVar );
339                                 blockInfo.FirstVar = nextVar;
340                         }
341                         
342                         if( blockInfo.RetVal )
343                                 Block->RetVal = blockInfo.RetVal;
344                 }
345                 
346                 break;
347         
348         // Assignment
349         case NODETYPE_ASSIGN:
350                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
351                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
352                         return ERRPTR;
353                 }
354                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
355                 if(ret == ERRPTR)
356                         return ERRPTR;
357                 
358                 if( Node->Assign.Operation != NODETYPE_NOP )
359                 {
360                         tSpiderValue    *varVal = Variable_GetValue(Block, Node->Assign.Dest->Variable.Name);
361                         tSpiderValue    *value;
362                         value = AST_ExecuteNode_BinOp(Block, Node->Assign.Operation, varVal, ret);
363                         if( value == ERRPTR )
364                                 return ERRPTR;
365                         if(ret) Object_Dereference(ret);
366                         Object_Dereference(varVal);
367                         ret = value;
368                 }
369                 
370                 if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) {
371                         Object_Dereference( ret );
372                         return ERRPTR;
373                 }
374                 break;
375         
376         // Function Call
377         case NODETYPE_FUNCTIONCALL:
378                 {
379                          int    nParams = 0;
380                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
381                                 nParams ++;
382                         }
383                         // Logical block (used to allocate `params`)
384                         {
385                                 tSpiderValue    *params[nParams];
386                                  int    i=0;
387                                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
388                                         params[i] = AST_ExecuteNode(Block, node);
389                                         if( params[i] == ERRPTR ) {
390                                                 while(i--)      Object_Dereference(params[i]);
391                                                 ret = ERRPTR;
392                                                 goto _return;
393                                         }
394                                         i ++;
395                                 }
396                                 
397                                 // Call the function (SpiderScript_ExecuteMethod does the
398                                 // required namespace handling)
399                                 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
400                                 
401                                 // Dereference parameters
402                                 while(i--)      Object_Dereference(params[i]);
403                                 
404                                 // falls out
405                         }
406                 }
407                 break;
408         
409         // Conditional
410         case NODETYPE_IF:
411                 ret = AST_ExecuteNode(Block, Node->If.Condition);
412                 if( SpiderScript_IsValueTrue(ret) ) {
413                         Object_Dereference(AST_ExecuteNode(Block, Node->If.True));
414                 }
415                 else {
416                         Object_Dereference(AST_ExecuteNode(Block, Node->If.False));
417                 }
418                 Object_Dereference(ret);
419                 ret = NULL;
420                 break;
421         
422         // Loop
423         case NODETYPE_LOOP:
424                 ret = AST_ExecuteNode(Block, Node->For.Init);
425                 if( Node->For.bCheckAfter )
426                 {
427                         do {
428                                 Object_Dereference(ret);
429                                 ret = AST_ExecuteNode(Block, Node->For.Code);
430                                 Object_Dereference(ret);
431                                 ret = AST_ExecuteNode(Block, Node->For.Increment);
432                                 Object_Dereference(ret);
433                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
434                         } while( SpiderScript_IsValueTrue(ret) );
435                 }
436                 else
437                 {
438                         Object_Dereference(ret);
439                         ret = AST_ExecuteNode(Block, Node->For.Condition);
440                         while( SpiderScript_IsValueTrue(ret) ) {
441                                 Object_Dereference(ret);
442                                 ret = AST_ExecuteNode(Block, Node->For.Code);
443                                 Object_Dereference(ret);
444                                 ret = AST_ExecuteNode(Block, Node->For.Increment);
445                                 Object_Dereference(ret);
446                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
447                         }
448                 }
449                 Object_Dereference(ret);
450                 ret = NULL;
451                 break;
452         
453         // Return
454         case NODETYPE_RETURN:
455                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
456                 Block->RetVal = ret;    // Return value set
457                 //Object_Reference(ret);        // Make sure it exists after return
458                 ret = NULL;     // the `return` statement does not return a value
459                 break;
460         
461         // Define a variable
462         case NODETYPE_DEFVAR:
463                 ret = NULL;
464                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
465                         ret = ERRPTR;
466                 break;
467         
468         // Variable
469         case NODETYPE_VARIABLE:
470                 ret = Variable_GetValue( Block, Node->Variable.Name );
471                 break;
472
473         // Cast a value to another
474         case NODETYPE_CAST:
475                 {
476                 tSpiderValue    *tmp = AST_ExecuteNode(Block, Node->Cast.Value);
477                 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmp );
478                 Object_Dereference(tmp);
479                 }
480                 break;
481
482         // Index into an array
483         case NODETYPE_INDEX:
484                 AST_RuntimeError(Node, "TODO - Array Indexing");
485                 ret = ERRPTR;
486                 break;
487
488         // TODO: Implement runtime constants
489         case NODETYPE_CONSTANT:
490                 AST_RuntimeError(Node, "TODO - Runtime Constants");
491                 ret = ERRPTR;
492                 break;
493         // Constant Values
494         case NODETYPE_STRING:   ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data );      break;
495         case NODETYPE_INTEGER:  ret = SpiderScript_CreateInteger( Node->Integer );      break;
496         case NODETYPE_REAL:     ret = SpiderScript_CreateReal( Node->Real );    break;
497         
498         // --- Operations ---
499         // Boolean Operations
500         case NODETYPE_LOGICALAND:       // Logical AND (&&)
501         case NODETYPE_LOGICALOR:        // Logical OR (||)
502         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
503                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
504                 if(op1 == ERRPTR)       return ERRPTR;
505                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
506                 if(op2 == ERRPTR) {
507                         Object_Dereference(op1);
508                         return ERRPTR;
509                 }
510                 
511                 switch( Node->Type )
512                 {
513                 case NODETYPE_LOGICALAND:
514                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
515                         break;
516                 case NODETYPE_LOGICALOR:
517                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
518                         break;
519                 case NODETYPE_LOGICALXOR:
520                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
521                         break;
522                 default:        break;
523                 }
524                 
525                 // Free intermediate objects
526                 Object_Dereference(op1);
527                 Object_Dereference(op2);
528                 break;
529         
530         // Comparisons
531         case NODETYPE_EQUALS:
532         case NODETYPE_LESSTHAN:
533         case NODETYPE_GREATERTHAN:
534                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
535                 if(op1 == ERRPTR)       return ERRPTR;
536                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
537                 if(op2 == ERRPTR) {
538                         Object_Dereference(op1);
539                         return ERRPTR;
540                 }
541                 
542                 // Convert types
543                 if( op1->Type != op2->Type ) {
544                         // If dynamically typed, convert op2 to op1's type
545                         if(Block->Script->Variant->bDyamicTyped)
546                         {
547                                 tmpobj = op2;
548                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
549                                 Object_Dereference(tmpobj);
550                                 if(op2 == ERRPTR) {
551                                         Object_Dereference(op1);
552                                         return ERRPTR;
553                                 }
554                         }
555                         // If statically typed, this should never happen, but catch it anyway
556                         else {
557                                 AST_RuntimeError(Node, "Statically typed implicit cast");
558                                 ret = ERRPTR;
559                                 break;
560                         }
561                 }
562                 // Do operation
563                 switch(op1->Type)
564                 {
565                 // - String Compare (does a strcmp, well memcmp)
566                 case SS_DATATYPE_STRING:
567                         // Call memcmp to do most of the work
568                         cmp = memcmp(
569                                 op1->String.Data, op2->String.Data,
570                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
571                                 );
572                         // Handle reaching the end of the string
573                         if( cmp == 0 ) {
574                                 if( op1->String.Length == op2->String.Length )
575                                         cmp = 0;
576                                 else if( op1->String.Length < op2->String.Length )
577                                         cmp = 1;
578                                 else
579                                         cmp = -1;
580                         }
581                         break;
582                 
583                 // - Integer Comparisons
584                 case SS_DATATYPE_INTEGER:
585                         if( op1->Integer == op2->Integer )
586                                 cmp = 0;
587                         else if( op1->Integer < op2->Integer )
588                                 cmp = -1;
589                         else
590                                 cmp = 1;
591                         break;
592                 default:
593                         AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
594                         ret = ERRPTR;
595                         break;
596                 }
597                 
598                 // Free intermediate objects
599                 Object_Dereference(op1);
600                 Object_Dereference(op2);
601                 
602                 // Error check
603                 if( ret == ERRPTR )
604                         break;
605                 
606                 // Create return
607                 switch(Node->Type)
608                 {
609                 case NODETYPE_EQUALS:   ret = SpiderScript_CreateInteger(cmp == 0);     break;
610                 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0);      break;
611                 case NODETYPE_GREATERTHAN:      ret = SpiderScript_CreateInteger(cmp > 0);      break;
612                 default:
613                         AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
614                         ret = ERRPTR;
615                         break;
616                 }
617                 break;
618         
619         // General Binary Operations
620         case NODETYPE_ADD:
621         case NODETYPE_SUBTRACT:
622         case NODETYPE_MULTIPLY:
623         case NODETYPE_DIVIDE:
624         case NODETYPE_MODULO:
625         case NODETYPE_BWAND:
626         case NODETYPE_BWOR:
627         case NODETYPE_BWXOR:
628         case NODETYPE_BITSHIFTLEFT:
629         case NODETYPE_BITSHIFTRIGHT:
630         case NODETYPE_BITROTATELEFT:
631                 // Get operands
632                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
633                 if(op1 == ERRPTR)       return ERRPTR;
634                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
635                 if(op2 == ERRPTR) {
636                         Object_Dereference(op1);
637                         return ERRPTR;
638                 }
639                 
640                 ret = AST_ExecuteNode_BinOp(Block, Node->Type, op1, op2);
641                 
642                 // Free intermediate objects
643                 Object_Dereference(op1);
644                 Object_Dereference(op2);
645                 break;
646         
647         //default:
648         //      ret = NULL;
649         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
650         //      break;
651         }
652 _return:
653         return ret;
654 }
655
656 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right)
657 {
658         tSpiderValue    *preCastValue = Right;
659         tSpiderValue    *ret;
660         
661         // Convert types
662         if( Left && Right && Left->Type != Right->Type )
663         {
664                 #if 0
665                 // Object types
666                 // - Operator overload functions
667                 if( Left->Type == SS_DATATYPE_OBJECT )
668                 {
669                         const char      *fcnname;
670                         switch(Operation)
671                         {
672                         case NODETYPE_ADD:      fcnname = "+";  break;
673                         case NODETYPE_SUBTRACT: fcnname = "-";  break;
674                         case NODETYPE_MULTIPLY: fcnname = "*";  break;
675                         case NODETYPE_DIVIDE:   fcnname = "/";  break;
676                         case NODETYPE_MODULO:   fcnname = "%";  break;
677                         case NODETYPE_BWAND:    fcnname = "&";  break;
678                         case NODETYPE_BWOR:     fcnname = "|";  break;
679                         case NODETYPE_BWXOR:    fcnname = "^";  break;
680                         case NODETYPE_BITSHIFTLEFT:     fcnname = "<<"; break;
681                         case NODETYPE_BITSHIFTRIGHT:fcnname = ">>";     break;
682                         case NODETYPE_BITROTATELEFT:fcnname = "<<<";    break;
683                         default:        fcnname = NULL; break;
684                         }
685                         
686                         if( fcnname )
687                         {
688                                 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
689                                 if( ret != ERRPTR )
690                                         return ret;
691                                 // Fall through and try casting (which will usually fail)
692                         }
693                 }
694                 #endif
695                 
696                 // If implicit casts are allowed, convert Right to Left's type
697                 if(Block->Script->Variant->bImplicitCasts)
698                 {
699                         Right = SpiderScript_CastValueTo(Left->Type, Right);
700                         if(Right == ERRPTR)
701                                 return ERRPTR;
702                 }
703                 // If statically typed, this should never happen, but catch it anyway
704                 else {
705                         AST_RuntimeError(NULL, "Implicit cast not allowed (from %i to %i)\n", Right->Type, Left->Type);
706                         return ERRPTR;
707                 }
708         }
709         
710         // NULL Check
711         if( Left == NULL || Right == NULL ) {
712                 if(Right && Right != preCastValue)      free(Right);
713                 return NULL;
714         }
715         
716         // Do operation
717         switch(Left->Type)
718         {
719         // String Concatenation
720         case SS_DATATYPE_STRING:
721                 switch(Operation)
722                 {
723                 case NODETYPE_ADD:      // Concatenate
724                         ret = Object_StringConcat(Left, Right);
725                         break;
726                 default:
727                         AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
728                         ret = ERRPTR;
729                         break;
730                 }
731                 break;
732         // Integer Operations
733         case SS_DATATYPE_INTEGER:
734                 switch(Operation)
735                 {
736                 case NODETYPE_ADD:      ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer );     break;
737                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer );     break;
738                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer );     break;
739                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer );     break;
740                 case NODETYPE_MODULO:   ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer );     break;
741                 case NODETYPE_BWAND:    ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer );     break;
742                 case NODETYPE_BWOR:     ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer );     break;
743                 case NODETYPE_BWXOR:    ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer );     break;
744                 case NODETYPE_BITSHIFTLEFT:     ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer );    break;
745                 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer );        break;
746                 case NODETYPE_BITROTATELEFT:
747                         ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) );
748                         break;
749                 default:
750                         AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Operation);
751                         ret = ERRPTR;
752                         break;
753                 }
754                 break;
755         
756         // Real Numbers
757         case SS_DATATYPE_REAL:
758                 switch(Operation)
759                 {
760                 default:
761                         AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
762                         ret = ERRPTR;
763                         break;
764                 }
765                 break;
766         
767         default:
768                 AST_RuntimeError(NULL, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
769                 ret = ERRPTR;
770                 break;
771         }
772         
773         if(Right && Right != preCastValue)      free(Right);
774         
775         return ret;
776 }
777
778 /**
779  * \brief Define a variable
780  * \param Block Current block state
781  * \param Type  Type of the variable
782  * \param Name  Name of the variable
783  * \return Boolean Failure
784  */
785 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
786 {
787         tAST_Variable   *var, *prev = NULL;
788         
789         for( var = Block->FirstVar; var; prev = var, var = var->Next )
790         {
791                 if( strcmp(var->Name, Name) == 0 ) {
792                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
793                         return ERRPTR;
794                 }
795         }
796         
797         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
798         var->Next = NULL;
799         var->Type = Type;
800         var->Object = NULL;
801         strcpy(var->Name, Name);
802         
803         if(prev)        prev->Next = var;
804         else    Block->FirstVar = var;
805         
806         //printf("Defined variable %s (%i)\n", Name, Type);
807         
808         return var;
809 }
810
811 /**
812  * \brief Set the value of a variable
813  * \return Boolean Failure
814  */
815 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
816 {
817         tAST_Variable   *var;
818         tAST_BlockState *bs;
819         
820         for( bs = Block; bs; bs = bs->Parent )
821         {
822                 for( var = bs->FirstVar; var; var = var->Next )
823                 {
824                         if( strcmp(var->Name, Name) == 0 )
825                         {
826                                 if( !Block->Script->Variant->bDyamicTyped
827                                  && (Value && var->Type != Value->Type) )
828                                 {
829                                         AST_RuntimeError(NULL, "Type mismatch assigning to '%s'", Name);
830                                         return -2;
831                                 }
832 //                              printf("Assign %p to '%s'\n", Value, var->Name);
833                                 Object_Reference(Value);
834                                 Object_Dereference(var->Object);
835                                 var->Object = Value;
836                                 return 0;
837                         }
838                 }
839         }
840         
841         if( Block->Script->Variant->bDyamicTyped )
842         {
843                 // Define variable
844                 var = Variable_Define(Block, Value->Type, Name);
845                 Object_Reference(Value);
846                 var->Object = Value;
847                 return 0;
848         }
849         else
850         {
851                 AST_RuntimeError(NULL, "Variable '%s' set while undefined", Name);
852                 return -1;
853         }
854 }
855
856 /**
857  * \brief Get the value of a variable
858  */
859 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
860 {
861         tAST_Variable   *var;
862         tAST_BlockState *bs;
863         
864         for( bs = Block; bs; bs = bs->Parent )
865         {
866                 for( var = bs->FirstVar; var; var = var->Next )
867                 {
868                         if( strcmp(var->Name, Name) == 0 ) {
869                                 Object_Reference(var->Object);
870                                 return var->Object;
871                         }
872                 }
873         }
874         
875         
876         AST_RuntimeError(NULL, "Variable '%s' used undefined", Name);
877         
878         return ERRPTR;
879 }
880
881 /**
882  * \brief Destorys a variable
883  */
884 void Variable_Destroy(tAST_Variable *Variable)
885 {
886 //      printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
887         Object_Dereference(Variable->Object);
888         free(Variable);
889 }
890
891 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
892 {
893         va_list args;
894         
895         fprintf(stderr, "ERROR: ");
896         va_start(args, Format);
897         vfprintf(stderr, Format, args);
898         va_end(args);
899         fprintf(stderr, "\n");
900         
901         if(Node)
902         {
903                 fprintf(stderr, "   at %s:%i\n", Node->File, Node->Line);
904         }
905 }

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