SpiderScript - Bugs, Documentation and a few language features
[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 #define TRACE_VAR_LOOKUPS       0
10 #define TRACE_NODE_RETURNS      0
11
12 // === IMPORTS ===
13 extern tSpiderFunction  *gpExports_First;
14
15 // === PROTOTYPES ===
16 void    Object_Dereference(tSpiderValue *Object);
17 void    Object_Reference(tSpiderValue *Object);
18 tSpiderValue    *SpiderScript_CreateInteger(uint64_t Value);
19 tSpiderValue    *SpiderScript_CreateReal(double Value);
20 tSpiderValue    *SpiderScript_CreateString(int Length, const char *Data);
21 tSpiderValue    *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
22  int    SpiderScript_IsValueTrue(tSpiderValue *Value);
23 void    SpiderScript_FreeValue(tSpiderValue *Value);
24 char    *SpiderScript_DumpValue(tSpiderValue *Value);
25
26 tSpiderValue    *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
27 tSpiderValue    *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
28 tSpiderValue    *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value);
29
30 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
31  int    Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
32 tSpiderValue    *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
33 void    Variable_Destroy(tAST_Variable *Variable);
34
35 void    AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
36 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
37
38 // === GLOBALS ===
39  int    giNextBlockIdent = 1;
40
41 // === CODE ===
42 /**
43  * \brief Dereference a created object
44  */
45 void Object_Dereference(tSpiderValue *Object)
46 {
47         if(!Object)     return ;
48         if(Object == ERRPTR)    return ;
49         Object->ReferenceCount --;
50 //      printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount);
51         if( Object->ReferenceCount == 0 ) {
52                 switch( (enum eSpiderScript_DataTypes) Object->Type )
53                 {
54                 case SS_DATATYPE_OBJECT:
55                         Object->Object->Type->Destructor( Object->Object );
56                         break;
57                 case SS_DATATYPE_OPAQUE:
58                         Object->Opaque.Destroy( Object->Opaque.Data );
59                         break;
60                 default:
61                         break;
62                 }
63                 free(Object);
64         }
65 }
66
67 void Object_Reference(tSpiderValue *Object)
68 {
69         if(!Object)     return ;
70         Object->ReferenceCount ++;
71 //      printf("%p Referenced (%i)\n", Object, Object->ReferenceCount);
72 }
73
74 /**
75  * \brief Allocate and initialise a SpiderScript object
76  */
77 tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
78 {
79          int    size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
80         tSpiderObject   *ret = malloc(size);
81         
82         ret->Type = Class;
83         ret->ReferenceCount = 1;
84         ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
85         memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
86         
87         return ret;
88 }
89
90 /**
91  * \brief Create an integer object
92  */
93 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
94 {
95         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
96         ret->Type = SS_DATATYPE_INTEGER;
97         ret->ReferenceCount = 1;
98         ret->Integer = Value;
99         return ret;
100 }
101
102 /**
103  * \brief Create an real number object
104  */
105 tSpiderValue *SpiderScript_CreateReal(double Value)
106 {
107         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
108         ret->Type = SS_DATATYPE_REAL;
109         ret->ReferenceCount = 1;
110         ret->Real = Value;
111         return ret;
112 }
113
114 /**
115  * \brief Create an string object
116  */
117 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
118 {
119         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
120         ret->Type = SS_DATATYPE_STRING;
121         ret->ReferenceCount = 1;
122         ret->String.Length = Length;
123         if( Data )
124                 memcpy(ret->String.Data, Data, Length);
125         else
126                 memset(ret->String.Data, 0, Length);
127         ret->String.Data[Length] = '\0';
128         return ret;
129 }
130
131 /**
132  * \brief Concatenate two strings
133  */
134 tSpiderValue *Object_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
135 {
136          int    newLen = 0;
137         tSpiderValue    *ret;
138         if(Str1)        newLen += Str1->String.Length;
139         if(Str2)        newLen += Str2->String.Length;
140         ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
141         ret->Type = SS_DATATYPE_STRING;
142         ret->ReferenceCount = 1;
143         ret->String.Length = newLen;
144         if(Str1)
145                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
146         if(Str2) {
147                 if(Str1)
148                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
149                 else
150                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
151         }
152         ret->String.Data[ newLen ] = '\0';
153         return ret;
154 }
155
156 /**
157  * \brief Cast one object to another
158  * \brief Type  Destination type
159  * \brief Source        Input data
160  */
161 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
162 {
163         tSpiderValue    *ret = ERRPTR;
164          int    len = 0;
165
166         if( !Source )
167         {
168                 switch(Type)
169                 {
170                 case SS_DATATYPE_INTEGER:       return SpiderScript_CreateInteger(0);
171                 case SS_DATATYPE_REAL:  return SpiderScript_CreateReal(0);
172                 case SS_DATATYPE_STRING:        return SpiderScript_CreateString(4, "null");
173                 }
174                 return NULL;
175         }
176         
177         // Check if anything needs to be done
178         if( Source->Type == Type ) {
179                 Object_Reference(Source);
180                 return Source;
181         }
182         
183         #if 0
184         {
185                 printf("Casting %i ", Source->Type);
186                 switch(Source->Type)
187                 {
188                 case SS_DATATYPE_INTEGER:       printf("0x%lx", Source->Integer);       break;
189                 case SS_DATATYPE_STRING:        printf("\"%s\"", Source->String.Data);  break;
190                 case SS_DATATYPE_REAL:  printf("%f", Source->Real);     break;
191                 default:        break;
192                 }
193                 printf(" to %i\n", Type);
194         }
195         #endif
196         
197         #if 0
198         if( Source->Type == SS_DATATYPE_OBJECT )
199         {
200                 const char      *name = NULL;
201                 switch(Type)
202                 {
203                 case SS_DATATYPE_INTEGER:       name = "cast Integer";  break;
204                 case SS_DATATYPE_REAL:          name = "cast Real";     break;
205                 case SS_DATATYPE_STRING:        name = "cast String";   break;
206                 case SS_DATATYPE_ARRAY:         name = "cast Array";    break;
207                 default:
208                         AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
209                         return ERRPTR;
210                 }
211                 if( fcnname )
212                 {
213                         ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
214                         if( ret != ERRPTR )
215                                 return ret;
216                         // Fall through and try casting (which will usually fail)
217                 }
218         }
219         #endif
220         
221         switch( (enum eSpiderScript_DataTypes)Type )
222         {
223         case SS_DATATYPE_UNDEF:
224         case SS_DATATYPE_ARRAY:
225         case SS_DATATYPE_OPAQUE:
226         case SS_DATATYPE_OBJECT:
227                 AST_RuntimeError(NULL, "Invalid cast to %i", Type);
228                 return ERRPTR;
229         
230         case SS_DATATYPE_INTEGER:
231                 ret = malloc(sizeof(tSpiderValue));
232                 ret->Type = SS_DATATYPE_INTEGER;
233                 ret->ReferenceCount = 1;
234                 switch(Source->Type)
235                 {
236                 case SS_DATATYPE_INTEGER:       break;  // Handled above
237                 case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
238                 case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
239                 default:
240                         AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
241                         free(ret);
242                         ret = ERRPTR;
243                         break;
244                 }
245                 break;
246         
247         case SS_DATATYPE_REAL:
248                 ret = malloc(sizeof(tSpiderValue));
249                 ret->Type = SS_DATATYPE_REAL;
250                 ret->ReferenceCount = 1;
251                 switch(Source->Type)
252                 {
253                 case SS_DATATYPE_STRING:        ret->Real = atof(Source->String.Data);  break;
254                 case SS_DATATYPE_INTEGER:       ret->Real = Source->Integer;    break;
255                 default:
256                         AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
257                         free(ret);
258                         ret = ERRPTR;
259                         break;
260                 }
261                 break;
262         
263         case SS_DATATYPE_STRING:
264                 switch(Source->Type)
265                 {
266                 case SS_DATATYPE_INTEGER:       len = snprintf(NULL, 0, "%li", Source->Integer);        break;
267                 case SS_DATATYPE_REAL:  len = snprintf(NULL, 0, "%g", Source->Real);    break;
268                 default:        break;
269                 }
270                 ret = malloc(sizeof(tSpiderValue) + len + 1);
271                 ret->Type = SS_DATATYPE_STRING;
272                 ret->ReferenceCount = 1;
273                 ret->String.Length = len;
274                 switch(Source->Type)
275                 {
276                 case SS_DATATYPE_INTEGER:       sprintf(ret->String.Data, "%li", Source->Integer);      break;
277                 case SS_DATATYPE_REAL:
278                         sprintf(ret->String.Data, "%g", Source->Real);  break;
279                 default:
280                         AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
281                         free(ret);
282                         ret = ERRPTR;
283                         break;
284                 }
285                 break;
286         
287         default:
288                 AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
289                 ret = ERRPTR;
290                 break;
291         }
292         
293         return ret;
294 }
295
296 /**
297  * \brief Condenses a value down to a boolean
298  */
299 int SpiderScript_IsValueTrue(tSpiderValue *Value)
300 {
301         if( Value == ERRPTR )   return 0;
302         if( Value == NULL )     return 0;
303         
304         switch( (enum eSpiderScript_DataTypes)Value->Type )
305         {
306         case SS_DATATYPE_UNDEF:
307                 return 0;
308         
309         case SS_DATATYPE_INTEGER:
310                 return !!Value->Integer;
311         
312         case SS_DATATYPE_REAL:
313                 return (-.5f < Value->Real && Value->Real < 0.5f);
314         
315         case SS_DATATYPE_STRING:
316                 return Value->String.Length > 0;
317         
318         case SS_DATATYPE_OBJECT:
319                 return Value->Object != NULL;
320         
321         case SS_DATATYPE_OPAQUE:
322                 return Value->Opaque.Data != NULL;
323         
324         case SS_DATATYPE_ARRAY:
325                 return Value->Array.Length > 0;
326         default:
327                 AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
328                 return 0;
329         }
330         return 0;
331 }
332
333 /**
334  * \brief Free a value
335  * \note Just calls Object_Dereference
336  */
337 void SpiderScript_FreeValue(tSpiderValue *Value)
338 {
339         Object_Dereference(Value);
340 }
341
342 /**
343  * \brief Dump a value into a string
344  * \return Heap string
345  */
346 char *SpiderScript_DumpValue(tSpiderValue *Value)
347 {
348         char    *ret;
349         if( Value == ERRPTR )
350                 return strdup("ERRPTR");
351         if( Value == NULL )
352                 return strdup("null");
353         
354         switch( (enum eSpiderScript_DataTypes)Value->Type )
355         {
356         case SS_DATATYPE_UNDEF: return strdup("undefined");
357         
358         case SS_DATATYPE_INTEGER:
359                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
360                 sprintf(ret, "0x%lx", Value->Integer);
361                 return ret;
362         
363         case SS_DATATYPE_REAL:
364                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
365                 sprintf(ret, "%f", Value->Real);
366                 return ret;
367         
368         case SS_DATATYPE_STRING:
369                 ret = malloc( Value->String.Length + 3 );
370                 ret[0] = '"';
371                 strcpy(ret+1, Value->String.Data);
372                 ret[Value->String.Length+1] = '"';
373                 ret[Value->String.Length+2] = '\0';
374                 return ret;
375         
376         case SS_DATATYPE_OBJECT:
377                 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
378                 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
379                 return ret;
380         
381         case SS_DATATYPE_OPAQUE:
382                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
383                 sprintf(ret, "*%p", Value->Opaque.Data);
384                 return ret;
385         
386         case SS_DATATYPE_ARRAY:
387                 return strdup("Array");
388         
389         default:
390                 AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
391                 return NULL;
392         }
393         
394 }
395
396 /**
397  * \brief Execute a script function
398  * \param Script        Script context to execute in
399  * \param Namespace     Namespace to search for the function
400  * \param Function      Function name to execute
401  * \param NArguments    Number of arguments to pass
402  * \param Arguments     Arguments passed
403  */
404 tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
405         tSpiderNamespace *Namespace, const char *Function,
406         int NArguments, tSpiderValue **Arguments)
407 {
408          int    bFound = 0;     // Used to keep nesting levels down
409         tSpiderValue    *ret = ERRPTR;
410         tSpiderFunction *fcn;
411         
412         // First: Find the function in the script
413         {
414                 tAST_Function   *astFcn;
415                 for( astFcn = Script->Script->Functions; astFcn; astFcn = astFcn->Next )
416                 {
417                         if( strcmp(astFcn->Name, Function) == 0 )
418                                 break;
419                 }
420                 // Execute!
421                 if(astFcn)
422                 {
423                         tAST_BlockState bs;
424                         tAST_Node       *arg;
425                          int    i = 0;
426                         
427                         // Build a block State
428                         bs.FirstVar = NULL;
429                         bs.RetVal = NULL;
430                         bs.Parent = NULL;
431                         bs.BaseNamespace = &Script->Variant->RootNamespace;
432                         bs.CurNamespace = NULL;
433                         bs.Script = Script;
434                         bs.Ident = giNextBlockIdent ++;
435                         
436                         // Parse arguments
437                         for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
438                         {
439                                 if( i >= NArguments )   break;  // TODO: Return gracefully
440                                 // TODO: Type checks
441                                 Variable_Define(&bs,
442                                         arg->DefVar.DataType, arg->DefVar.Name,
443                                         Arguments[i]);
444                         }
445                         
446                         // Execute function
447                         ret = AST_ExecuteNode(&bs, astFcn->Code);
448                         if(ret != ERRPTR)
449                         {
450                                 Object_Dereference(ret);        // Dereference output of last block statement
451                                 ret = bs.RetVal;        // Set to return value of block
452                         }
453                         bFound = 1;
454                         
455                         while(bs.FirstVar)
456                         {
457                                 tAST_Variable   *nextVar = bs.FirstVar->Next;
458                                 Variable_Destroy( bs.FirstVar );
459                                 bs.FirstVar = nextVar;
460                         }
461                 }
462         }
463         
464         // Didn't find it in script?
465         if(!bFound)
466         {
467                 fcn = NULL;     // Just to allow the below code to be neat
468                 
469                 // Second: Scan current namespace
470                 if( !fcn && Namespace )
471                 {
472                         for( fcn = Namespace->Functions; fcn; fcn = fcn->Next )
473                         {
474                                 if( strcmp( fcn->Name, Function ) == 0 )
475                                         break;
476                         }
477                 }
478                 
479                 // Third: Search the variant's global exports
480                 if( !fcn )
481                 {
482                         for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
483                         {
484                                 if( strcmp( fcn->Name, Function ) == 0 )
485                                         break;
486                         }
487                 }
488                 
489                 // Fourth: Search language exports
490                 if( !fcn )
491                 {
492                         for( fcn = gpExports_First; fcn; fcn = fcn->Next )
493                         {
494                                 if( strcmp( fcn->Name, Function ) == 0 )
495                                         break;
496                         }
497                 }
498                 
499                 // Execute!
500                 if(fcn)
501                 {
502                         // TODO: Type Checking
503                         ret = fcn->Handler( Script, NArguments, Arguments );
504                         bFound = 1;
505                 }
506         }
507         
508         // Not found?
509         if(!bFound)
510         {
511                 fprintf(stderr, "Undefined reference to function '%s'\n", Function);
512                 return ERRPTR;
513         }
514         
515         return ret;
516 }
517
518 /**
519  * \brief Execute an object method function
520  * \param Script        Script context to execute in
521  * \param Object        Object in which to find the method
522  * \param MethodName    Name of method to call
523  * \param NArguments    Number of arguments to pass
524  * \param Arguments     Arguments passed
525  */
526 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
527         tSpiderObject *Object, const char *MethodName,
528         int NArguments, tSpiderValue **Arguments)
529 {
530         tSpiderFunction *fcn;
531         tSpiderValue    this;
532         tSpiderValue    *newargs[NArguments+1];
533          int    i;
534         
535         // TODO: Support program defined objects
536         
537         // Search for the function
538         for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
539         {
540                 if( strcmp(fcn->Name, MethodName) == 0 )
541                         break;
542         }
543         // Error
544         if( !fcn )
545         {
546                 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
547                         Object->Type->Name, MethodName);
548                 return ERRPTR;
549         }
550         
551         // Create the "this" argument
552         this.Type = SS_DATATYPE_OBJECT;
553         this.ReferenceCount = 1;
554         this.Object = Object;
555         newargs[0] = &this;
556         memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
557         
558         // Check the type of the arguments
559         for( i = 0; fcn->ArgTypes[i]; i ++ )
560         {
561                 if( i >= NArguments ) {
562                         for( ; fcn->ArgTypes[i]; i ++ ) ;
563                         AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
564                                 NArguments, i);
565                         return ERRPTR;
566                 }
567                 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
568                 {
569                         AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
570                                 Arguments[i]->Type, fcn->ArgTypes[i]);
571                         return ERRPTR;
572                 }
573         }
574         
575         // Call handler
576         return fcn->Handler(Script, NArguments+1, newargs);
577 }
578
579 /**
580  * \brief Execute a script function
581  * \param Script        Script context to execute in
582  * \param Function      Function name to execute
583  * \param NArguments    Number of arguments to pass
584  * \param Arguments     Arguments passed
585  */
586 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
587         tSpiderNamespace *Namespace, const char *ClassName,
588         int NArguments, tSpiderValue **Arguments)
589 {
590          int    bFound = 0;     // Used to keep nesting levels down
591         tSpiderValue    *ret = ERRPTR;
592         tSpiderObjectDef        *class;
593         
594         // First: Find the function in the script
595         // TODO: Implement script-defined classes
596         #if 0
597         {
598                 tAST_Function   *astClass;
599                 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
600                 {
601                         if( strcmp(astClass->Name, ClassName) == 0 )
602                                 break;
603                 }
604                 // Execute!
605                 if(astClass)
606                 {
607                         tAST_BlockState bs;
608                         tAST_Node       *arg;
609                          int    i = 0;
610                         
611                         // Build a block State
612                         bs.FirstVar = NULL;
613                         bs.RetVal = NULL;
614                         bs.Parent = NULL;
615                         bs.BaseNamespace = &Script->Variant->RootNamespace;
616                         bs.CurNamespace = NULL;
617                         bs.Script = Script;
618                         bs.Ident = giNextBlockIdent ++;
619                         
620                         for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
621                         {
622                                 if( i >= NArguments )   break;  // TODO: Return gracefully
623                                 // TODO: Type checks
624                                 Variable_Define(&bs,
625                                         arg->DefVar.DataType, arg->DefVar.Name,
626                                         Arguments[i]);
627                         }
628                         
629                         // Execute function
630                         ret = AST_ExecuteNode(&bs, astFcn->Code);
631                         if( ret != ERRPTR )
632                         {
633                                 Object_Dereference(ret);        // Dereference output of last block statement
634                                 ret = bs.RetVal;        // Set to return value of block
635                         }
636                         bFound = 1;
637                         
638                         while(bs.FirstVar)
639                         {
640                                 tAST_Variable   *nextVar = bs.FirstVar->Next;
641                                 Variable_Destroy( bs.FirstVar );
642                                 bs.FirstVar = nextVar;
643                         }
644                 }
645         }
646         #endif
647         
648         // Didn't find it in script?
649         if(!bFound)
650         {
651                 class = NULL;   // Just to allow the below code to be neat
652                 
653                 // Second: Scan current namespace
654                 if( !class && Namespace )
655                 {
656                         for( class = Namespace->Classes; class; class = class->Next )
657                         {
658                                 if( strcmp( class->Name, ClassName ) == 0 )
659                                         break;
660                         }
661                 }
662                 
663                 #if 0
664                 // Third: Search the variant's global exports
665                 if( !class )
666                 {
667                         for( class = Script->Variant->Classes; class; class = fcn->Next )
668                         {
669                                 if( strcmp( class->Name, Function ) == 0 )
670                                         break;
671                         }
672                 }
673                 #endif
674                 
675                 #if 0
676                 // Fourth: Search language exports
677                 if( !class )
678                 {
679                         for( class = gpExports_First; class; class = fcn->Next )
680                         {
681                                 if( strcmp( class->Name, ClassName ) == 0 )
682                                         break;
683                         }
684                 }
685                 #endif
686                 
687                 // Execute!
688                 if(class)
689                 {
690                         tSpiderObject   *obj;
691                         // TODO: Type Checking
692                         
693                         // Call constructor
694                         obj = class->Constructor( NArguments, Arguments );
695                         if( obj == NULL || obj == ERRPTR )
696                                 return (void *)obj;
697                         
698                         // Creatue return object
699                         ret = malloc( sizeof(tSpiderValue) );
700                         ret->Type = SS_DATATYPE_OBJECT;
701                         ret->ReferenceCount = 1;
702                         ret->Object = obj;
703                         bFound = 1;
704                 }
705         }
706         
707         // Not found?
708         if(!bFound)
709         {
710                 fprintf(stderr, "Undefined reference to class '%s'\n", ClassName);
711                 return ERRPTR;
712         }
713         
714         return ret;
715 }
716
717
718 /**
719  * \brief Execute an AST node and return its value
720  * \param Block Execution context
721  * \param Node  Node to execute
722  */
723 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
724 {
725         tAST_Node       *node;
726         tSpiderValue    *ret = NULL, *tmpobj;
727         tSpiderValue    *op1, *op2;     // Binary operations
728          int    cmp;    // Used in comparisons
729          int    i;
730         
731         switch(Node->Type)
732         {
733         // No Operation
734         case NODETYPE_NOP:
735                 ret = NULL;
736                 break;
737         
738         // Code block
739         case NODETYPE_BLOCK:
740                 {
741                         tAST_BlockState blockInfo;
742                         blockInfo.Parent = Block;
743                         blockInfo.Script = Block->Script;
744                         blockInfo.FirstVar = NULL;
745                         blockInfo.RetVal = NULL;
746                         blockInfo.BaseNamespace = Block->BaseNamespace;
747                         blockInfo.CurNamespace = NULL;
748                         blockInfo.Ident = giNextBlockIdent ++;
749                         ret = NULL;
750                         // Loop over all nodes, or until the return value is set
751                         for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
752                         {
753                                 ret = AST_ExecuteNode(&blockInfo, node);
754                                 if(ret == ERRPTR)       break;  // Error check
755                                 if(ret != NULL) Object_Dereference(ret);        // Free unused value
756                         }
757                         // Clean up variables
758                         while(blockInfo.FirstVar)
759                         {
760                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
761                                 Variable_Destroy( blockInfo.FirstVar );
762                                 blockInfo.FirstVar = nextVar;
763                         }
764                         // Clear ret if not an error
765                         if(ret != ERRPTR)       ret = NULL;
766                         
767                         // Set parent's return value if needed
768                         if( blockInfo.RetVal )
769                                 Block->RetVal = blockInfo.RetVal;
770                 }
771                 
772                 break;
773         
774         // Assignment
775         case NODETYPE_ASSIGN:
776                 // TODO: Support assigning to object attributes
777                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
778                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
779                         return ERRPTR;
780                 }
781                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
782                 if(ret == ERRPTR)       return ERRPTR;
783                 
784                 // Perform assignment operation
785                 if( Node->Assign.Operation != NODETYPE_NOP )
786                 {
787                         tSpiderValue    *varVal = Variable_GetValue(Block, Node->Assign.Dest);
788                         tSpiderValue    *value;
789                         value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
790                         if(value == ERRPTR)     return ERRPTR;
791                         if(ret) Object_Dereference(ret);
792                         if(varVal)      Object_Dereference(varVal);
793                         ret = value;
794                 }
795                 
796                 // Set the variable value
797                 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
798                         Object_Dereference( ret );
799                         return ERRPTR;
800                 }
801                 break;
802         
803         // Post increment/decrement
804         case NODETYPE_POSTINC:
805         case NODETYPE_POSTDEC:
806                 {
807                         tSpiderValue    *varVal, *value;
808                         static tSpiderValue     one = {
809                                 .Type = SS_DATATYPE_INTEGER,
810                                 .ReferenceCount = 1,
811                                 {.Integer = 1}
812                                 };
813                         
814                         // TODO: Support assigning to object attributes
815                         if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
816                                 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
817                                 return ERRPTR;
818                         }
819                 
820                         // Get values (current variable contents and a static one)
821                         varVal = Variable_GetValue(Block, Node->UniOp.Value);
822                         
823                         if( Node->Type == NODETYPE_POSTDEC )
824                                 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_SUBTRACT, varVal, &one);
825                         else
826                                 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_ADD, varVal, &one);
827                         if( value == ERRPTR )
828                                 return ERRPTR;
829                         
830                         ret = varVal;
831                 
832                         if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
833                                 Object_Dereference( ret );
834                                 return ERRPTR;
835                         }
836                         Object_Dereference( value );
837                 }
838                 break;
839         
840         // Function Call
841         case NODETYPE_METHODCALL:
842         case NODETYPE_FUNCTIONCALL:
843         case NODETYPE_CREATEOBJECT:
844                 // Logical block (used to allocate `params`)
845                 {
846                         tSpiderValue    *params[Node->FunctionCall.NumArgs];
847                         i = 0;
848                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
849                         {
850                                 params[i] = AST_ExecuteNode(Block, node);
851                                 if( params[i] == ERRPTR ) {
852                                         while(i--)      Object_Dereference(params[i]);
853                                         ret = ERRPTR;
854                                         goto _return;
855                                 }
856                                 i ++;
857                         }
858                         
859                         if( !Block->CurNamespace )
860                                 Block->CurNamespace = Block->BaseNamespace;
861                         
862                         // Call the function
863                         if( Node->Type == NODETYPE_CREATEOBJECT )
864                         {
865                                 ret = SpiderScript_CreateObject(Block->Script,
866                                         Block->CurNamespace,
867                                         Node->FunctionCall.Name,
868                                         Node->FunctionCall.NumArgs, params
869                                         );
870                         }
871                         else if( Node->Type == NODETYPE_METHODCALL )
872                         {
873                                 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
874                                 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
875                                         AST_RuntimeError(Node->FunctionCall.Object,
876                                                 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
877                                         while(i--)      Object_Dereference(params[i]);
878                                         ret = ERRPTR;
879                                         break;
880                                 }
881                                 ret = SpiderScript_ExecuteMethod(Block->Script,
882                                         obj->Object, Node->FunctionCall.Name,
883                                         Node->FunctionCall.NumArgs, params
884                                         );
885                                 Object_Dereference(obj);
886                         }
887                         else
888                         {
889                                 ret = SpiderScript_ExecuteFunction(Block->Script,
890                                         Block->CurNamespace, Node->FunctionCall.Name,
891                                         Node->FunctionCall.NumArgs, params
892                                         );
893                         }
894
895                         
896                         // Dereference parameters
897                         while(i--)      Object_Dereference(params[i]);
898                         
899                         // falls out
900                 }
901                 break;
902         
903         // Conditional
904         case NODETYPE_IF:
905                 ret = AST_ExecuteNode(Block, Node->If.Condition);
906                 if( ret == ERRPTR )     break;
907                 if( SpiderScript_IsValueTrue(ret) ) {
908                         tmpobj = AST_ExecuteNode(Block, Node->If.True);
909                 }
910                 else {
911                         tmpobj = AST_ExecuteNode(Block, Node->If.False);
912                 }
913                 Object_Dereference(ret);
914                 if( tmpobj == ERRPTR )  return ERRPTR;
915                 Object_Dereference(tmpobj);
916                 ret = NULL;
917                 break;
918         
919         // Loop
920         case NODETYPE_LOOP:
921                 ret = AST_ExecuteNode(Block, Node->For.Init);
922                 if(ret == ERRPTR)       break;
923                 if( Node->For.bCheckAfter )
924                 {
925                         do {
926                                 Object_Dereference(ret);
927                                 ret = AST_ExecuteNode(Block, Node->For.Code);
928                                 if(ret == ERRPTR)       return ERRPTR;
929                                 Object_Dereference(ret);
930                                 ret = AST_ExecuteNode(Block, Node->For.Increment);
931                                 if(ret == ERRPTR)       return ERRPTR;
932                                 Object_Dereference(ret);
933                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
934                                 if(ret == ERRPTR)       return ERRPTR;
935                         } while( SpiderScript_IsValueTrue(ret) );
936                 }
937                 else
938                 {
939                         Object_Dereference(ret);
940                         ret = AST_ExecuteNode(Block, Node->For.Condition);
941                         if(ret == ERRPTR)       return ERRPTR;
942                         while( SpiderScript_IsValueTrue(ret) ) {
943                                 Object_Dereference(ret);
944                                 ret = AST_ExecuteNode(Block, Node->For.Code);
945                                 if(ret == ERRPTR)       return ERRPTR;
946                                 Object_Dereference(ret);
947                                 ret = AST_ExecuteNode(Block, Node->For.Increment);
948                                 if(ret == ERRPTR)       return ERRPTR;
949                                 Object_Dereference(ret);
950                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
951                                 if(ret == ERRPTR)       return ERRPTR;
952                         }
953                 }
954                 Object_Dereference(ret);
955                 ret = NULL;
956                 break;
957         
958         // Return
959         case NODETYPE_RETURN:
960                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
961                 if(ret == ERRPTR)       break;
962                 Block->RetVal = ret;    // Return value set
963                 ret = NULL;     // the `return` statement does not return a value
964                 break;
965         
966         // Define a variable
967         case NODETYPE_DEFVAR:
968                 if( Node->DefVar.InitialValue ) {
969                         tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
970                         if(tmpobj == ERRPTR)    return ERRPTR;
971                 }
972                 else {
973                         tmpobj = NULL;
974                 }
975                 ret = NULL;
976                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
977                         ret = ERRPTR;
978                 Object_Dereference(tmpobj);
979                 break;
980         
981         // Scope
982         case NODETYPE_SCOPE:
983                 {
984                 tSpiderNamespace        *ns;
985                 
986                 // Set current namespace if unset
987                 if( !Block->CurNamespace )
988                         Block->CurNamespace = Block->BaseNamespace;
989                 
990                 // Empty string means use the root namespace
991                 if( Node->Scope.Name[0] == '\0' )
992                 {
993                         ns = &Block->Script->Variant->RootNamespace;
994                 }
995                 else
996                 {
997                         // Otherwise scan the current namespace for the element
998                         for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
999                         {
1000                                 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
1001                                         break;
1002                         }
1003                 }
1004                 if(!ns) {
1005                         AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
1006                         ret = ERRPTR;
1007                         break;
1008                 }
1009                 Block->CurNamespace = ns;
1010                 
1011                 ret = AST_ExecuteNode(Block, Node->Scope.Element);
1012                 }
1013                 break;
1014         
1015         // Variable
1016         case NODETYPE_VARIABLE:
1017                 ret = Variable_GetValue( Block, Node );
1018                 break;
1019         
1020         // Element of an Object
1021         case NODETYPE_ELEMENT:
1022                 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
1023                 if(tmpobj == ERRPTR)    return ERRPTR;
1024                 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
1025                 {
1026                         AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
1027                         ret = ERRPTR;
1028                         break ;
1029                 }
1030                 
1031                 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
1032                 {
1033                         if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
1034                         {
1035                                 ret = tmpobj->Object->Attributes[i];
1036                                 Object_Reference(ret);
1037                                 break;
1038                         }
1039                 }
1040                 if( i == tmpobj->Object->Type->NAttributes )
1041                 {
1042                         AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
1043                                 Node->Scope.Name, tmpobj->Object->Type->Name);
1044                         ret = ERRPTR;
1045                 }
1046                 break;
1047
1048         // Cast a value to another
1049         case NODETYPE_CAST:
1050                 {
1051                 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
1052                 if(tmpobj == ERRPTR) return ERRPTR;
1053                 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
1054                 Object_Dereference(tmpobj);
1055                 }
1056                 break;
1057
1058         // Index into an array
1059         case NODETYPE_INDEX:
1060                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
1061                 if(op1 == ERRPTR)       return ERRPTR;
1062                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);        // Offset
1063                 if(op2 == ERRPTR) {
1064                         Object_Dereference(op1);
1065                         return ERRPTR;
1066                 }
1067                 
1068                 if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
1069                 {
1070                         // TODO: Implement "operator []" on objects
1071                         AST_RuntimeError(Node, "Indexing non-array");
1072                         ret = ERRPTR;
1073                         break;
1074                 }
1075                 
1076                 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
1077                         AST_RuntimeError(Node, "Array index is not an integer");
1078                         ret = ERRPTR;
1079                         break;
1080                 }
1081                 
1082                 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
1083                 {
1084                         tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
1085                         Object_Dereference(op2);
1086                         op2 = tmpobj;
1087                 }
1088                 
1089                 if( op2->Integer >= op1->Array.Length ) {
1090                         AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
1091                                 op2->Integer, op1->Array.Length);
1092                         ret = ERRPTR;
1093                         break;
1094                 }
1095                 
1096                 ret = op1->Array.Items[ op2->Integer ];
1097                 Object_Reference(ret);
1098                 
1099                 Object_Dereference(op1);
1100                 Object_Dereference(op2);
1101                 break;
1102
1103         // TODO: Implement runtime constants
1104         case NODETYPE_CONSTANT:
1105                 // TODO: Scan namespace for function
1106                 AST_RuntimeError(Node, "TODO - Runtime Constants");
1107                 ret = ERRPTR;
1108                 break;
1109         
1110         // Constant Values
1111         case NODETYPE_STRING:
1112         case NODETYPE_INTEGER:
1113         case NODETYPE_REAL:
1114                 ret = &Node->Constant;
1115                 Object_Reference(ret);
1116                 break;
1117         
1118         // --- Operations ---
1119         // Boolean Operations
1120         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
1121                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1122                 if(op1 == ERRPTR)       return ERRPTR;
1123                 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
1124                 Object_Dereference(op1);
1125                 break;
1126         case NODETYPE_LOGICALAND:       // Logical AND (&&)
1127         case NODETYPE_LOGICALOR:        // Logical OR (||)
1128         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
1129                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1130                 if(op1 == ERRPTR)       return ERRPTR;
1131                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1132                 if(op2 == ERRPTR) {
1133                         Object_Dereference(op1);
1134                         return ERRPTR;
1135                 }
1136                 
1137                 switch( Node->Type )
1138                 {
1139                 case NODETYPE_LOGICALAND:
1140                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
1141                         break;
1142                 case NODETYPE_LOGICALOR:
1143                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
1144                         break;
1145                 case NODETYPE_LOGICALXOR:
1146                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
1147                         break;
1148                 default:        break;
1149                 }
1150                 
1151                 // Free intermediate objects
1152                 Object_Dereference(op1);
1153                 Object_Dereference(op2);
1154                 break;
1155         
1156         // Comparisons
1157         case NODETYPE_EQUALS:
1158         case NODETYPE_LESSTHAN:
1159         case NODETYPE_GREATERTHAN:
1160         case NODETYPE_LESSTHANEQUAL:
1161         case NODETYPE_GREATERTHANEQUAL:
1162                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1163                 if(op1 == ERRPTR)       return ERRPTR;
1164                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1165                 if(op2 == ERRPTR) {
1166                         Object_Dereference(op1);
1167                         ret = ERRPTR;
1168                         break;
1169                 }
1170                 
1171                 if( !op1 || !op2 ) {
1172                         AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
1173                         if(op1) Object_Dereference(op1);
1174                         if(op2) Object_Dereference(op2);
1175                         ret = SpiderScript_CreateInteger( !op1 && !op2 );
1176                         break;
1177                 }
1178                 
1179                 // Convert types
1180                 if( op1->Type != op2->Type ) {
1181                         // If dynamically typed, convert op2 to op1's type
1182                         if(Block->Script->Variant->bImplicitCasts)
1183                         {
1184                                 tmpobj = op2;
1185                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
1186                                 Object_Dereference(tmpobj);
1187                                 if(op2 == ERRPTR) {
1188                                         Object_Dereference(op1);
1189                                         return ERRPTR;
1190                                 }
1191                         }
1192                         // If statically typed, this should never happen, but catch it anyway
1193                         else {
1194                                 AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
1195                                         op1->Type, op2->Type);
1196                                 ret = ERRPTR;
1197                                 break;
1198                         }
1199                 }
1200                 // Do operation
1201                 switch(op1->Type)
1202                 {
1203                 // - String Compare (does a strcmp, well memcmp)
1204                 case SS_DATATYPE_STRING:
1205                         // Call memcmp to do most of the work
1206                         cmp = memcmp(
1207                                 op1->String.Data, op2->String.Data,
1208                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
1209                                 );
1210                         // Handle reaching the end of the string
1211                         if( cmp == 0 ) {
1212                                 if( op1->String.Length == op2->String.Length )
1213                                         cmp = 0;
1214                                 else if( op1->String.Length < op2->String.Length )
1215                                         cmp = 1;
1216                                 else
1217                                         cmp = -1;
1218                         }
1219                         break;
1220                 
1221                 // - Integer Comparisons
1222                 case SS_DATATYPE_INTEGER:
1223                         if( op1->Integer == op2->Integer )
1224                                 cmp = 0;
1225                         else if( op1->Integer < op2->Integer )
1226                                 cmp = -1;
1227                         else
1228                                 cmp = 1;
1229                         break;
1230                 // - Real Number Comparisons
1231                 case SS_DATATYPE_REAL:
1232                         cmp = (op1->Real - op2->Real) / op2->Real * 10000;      // < 0.1% difference is equality
1233                         break;
1234                 default:
1235                         AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
1236                         ret = ERRPTR;
1237                         break;
1238                 }
1239                 
1240                 // Free intermediate objects
1241                 Object_Dereference(op1);
1242                 Object_Dereference(op2);
1243                 
1244                 // Error check
1245                 if( ret == ERRPTR )
1246                         break;
1247                 
1248                 // Create return
1249                 switch(Node->Type)
1250                 {
1251                 case NODETYPE_EQUALS:   ret = SpiderScript_CreateInteger(cmp == 0);     break;
1252                 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0);      break;
1253                 case NODETYPE_GREATERTHAN:      ret = SpiderScript_CreateInteger(cmp > 0);      break;
1254                 case NODETYPE_LESSTHANEQUAL:    ret = SpiderScript_CreateInteger(cmp <= 0);     break;
1255                 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0);     break;
1256                 default:
1257                         AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
1258                         ret = ERRPTR;
1259                         break;
1260                 }
1261                 break;
1262         
1263         // General Unary Operations
1264         case NODETYPE_BWNOT:    // Bitwise NOT (~)
1265         case NODETYPE_NEGATE:   // Negation (-)
1266                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1267                 if(op1 == ERRPTR)       return ERRPTR;
1268                 ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
1269                 Object_Dereference(op1);
1270                 break;
1271         
1272         // General Binary Operations
1273         case NODETYPE_ADD:
1274         case NODETYPE_SUBTRACT:
1275         case NODETYPE_MULTIPLY:
1276         case NODETYPE_DIVIDE:
1277         case NODETYPE_MODULO:
1278         case NODETYPE_BWAND:
1279         case NODETYPE_BWOR:
1280         case NODETYPE_BWXOR:
1281         case NODETYPE_BITSHIFTLEFT:
1282         case NODETYPE_BITSHIFTRIGHT:
1283         case NODETYPE_BITROTATELEFT:
1284                 // Get operands
1285                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1286                 if(op1 == ERRPTR)       return ERRPTR;
1287                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1288                 if(op2 == ERRPTR) {
1289                         Object_Dereference(op1);
1290                         return ERRPTR;
1291                 }
1292                 
1293                 ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
1294                 
1295                 // Free intermediate objects
1296                 Object_Dereference(op1);
1297                 Object_Dereference(op2);
1298                 break;
1299         
1300         //default:
1301         //      ret = NULL;
1302         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
1303         //      break;
1304         }
1305 _return:
1306         #if TRACE_NODE_RETURNS
1307         if(ret && ret != ERRPTR) {
1308                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
1309         }
1310         else {
1311                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
1312         }
1313         #endif
1314
1315         return ret;
1316 }
1317
1318 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value)
1319 {
1320         tSpiderValue    *ret;
1321         #if 0
1322         if( Value->Type == SS_DATATYPE_OBJECT )
1323         {
1324                 const char      *fcnname;
1325                 switch(Operation)
1326                 {
1327                 case NODETYPE_NEGATE:   fcnname = "-ve";        break;
1328                 case NODETYPE_BWNOT:    fcnname = "~";  break;
1329                 default:        fcnname = NULL; break;
1330                 }
1331                 
1332                 if( fcnname )
1333                 {
1334                         ret = Object_ExecuteMethod(Value->Object, fcnname, );
1335                         if( ret != ERRPTR )
1336                                 return ret;
1337                         // Fall through and try casting (which will usually fail)
1338                 }
1339         }
1340         #endif
1341         switch(Value->Type)
1342         {
1343         // Integer Operations
1344         case SS_DATATYPE_INTEGER:
1345                 switch(Operation)
1346                 {
1347                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Integer );    break;
1348                 case NODETYPE_BWNOT:    ret = SpiderScript_CreateInteger( ~Value->Integer );    break;
1349                 default:
1350                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1351                         ret = ERRPTR;
1352                         break;
1353                 }
1354                 break;
1355         // Real number Operations
1356         case SS_DATATYPE_REAL:
1357                 switch(Operation)
1358                 {
1359                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Real );       break;
1360                 default:
1361                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1362                         ret = ERRPTR;
1363                         break;
1364                 }
1365                 break;
1366         
1367         default:
1368                 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1369                 ret = ERRPTR;
1370                 break;
1371         }
1372         
1373         return ret;
1374 }
1375
1376 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1377 {
1378         tSpiderValue    *preCastValue = Right;
1379         tSpiderValue    *ret;
1380         
1381         // Convert types
1382         if( Left && Right && Left->Type != Right->Type )
1383         {
1384                 #if 0
1385                 // Object types
1386                 // - Operator overload functions
1387                 if( Left->Type == SS_DATATYPE_OBJECT )
1388                 {
1389                         const char      *fcnname;
1390                         switch(Operation)
1391                         {
1392                         case NODETYPE_ADD:      fcnname = "+";  break;
1393                         case NODETYPE_SUBTRACT: fcnname = "-";  break;
1394                         case NODETYPE_MULTIPLY: fcnname = "*";  break;
1395                         case NODETYPE_DIVIDE:   fcnname = "/";  break;
1396                         case NODETYPE_MODULO:   fcnname = "%";  break;
1397                         case NODETYPE_BWAND:    fcnname = "&";  break;
1398                         case NODETYPE_BWOR:     fcnname = "|";  break;
1399                         case NODETYPE_BWXOR:    fcnname = "^";  break;
1400                         case NODETYPE_BITSHIFTLEFT:     fcnname = "<<"; break;
1401                         case NODETYPE_BITSHIFTRIGHT:fcnname = ">>";     break;
1402                         case NODETYPE_BITROTATELEFT:fcnname = "<<<";    break;
1403                         default:        fcnname = NULL; break;
1404                         }
1405                         
1406                         if( fcnname )
1407                         {
1408                                 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1409                                 if( ret != ERRPTR )
1410                                         return ret;
1411                                 // Fall through and try casting (which will usually fail)
1412                         }
1413                 }
1414                 #endif
1415                 
1416                 // If implicit casts are allowed, convert Right to Left's type
1417                 if(Block->Script->Variant->bImplicitCasts)
1418                 {
1419                         Right = SpiderScript_CastValueTo(Left->Type, Right);
1420                         if(Right == ERRPTR)
1421                                 return ERRPTR;
1422                 }
1423                 // If statically typed, this should never happen, but catch it anyway
1424                 else {
1425                         AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
1426                         return ERRPTR;
1427                 }
1428         }
1429         
1430         // NULL Check
1431         if( Left == NULL || Right == NULL ) {
1432                 if(Right && Right != preCastValue)      free(Right);
1433                 return NULL;
1434         }
1435         
1436         // Do operation
1437         switch(Left->Type)
1438         {
1439         // String Concatenation
1440         case SS_DATATYPE_STRING:
1441                 switch(Operation)
1442                 {
1443                 case NODETYPE_ADD:      // Concatenate
1444                         ret = Object_StringConcat(Left, Right);
1445                         break;
1446                 default:
1447                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1448                         ret = ERRPTR;
1449                         break;
1450                 }
1451                 break;
1452         // Integer Operations
1453         case SS_DATATYPE_INTEGER:
1454                 switch(Operation)
1455                 {
1456                 case NODETYPE_ADD:      ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer );     break;
1457                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer );     break;
1458                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer );     break;
1459                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer );     break;
1460                 case NODETYPE_MODULO:   ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer );     break;
1461                 case NODETYPE_BWAND:    ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer );     break;
1462                 case NODETYPE_BWOR:     ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer );     break;
1463                 case NODETYPE_BWXOR:    ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer );     break;
1464                 case NODETYPE_BITSHIFTLEFT:     ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer );    break;
1465                 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer );        break;
1466                 case NODETYPE_BITROTATELEFT:
1467                         ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) );
1468                         break;
1469                 default:
1470                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
1471                         ret = ERRPTR;
1472                         break;
1473                 }
1474                 break;
1475         
1476         // Real Numbers
1477         case SS_DATATYPE_REAL:
1478                 switch(Operation)
1479                 {
1480                 case NODETYPE_ADD:      ret = SpiderScript_CreateReal( Left->Real + Right->Real );      break;
1481                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateReal( Left->Real - Right->Real );      break;
1482                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateReal( Left->Real * Right->Real );      break;
1483                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateReal( Left->Real / Right->Real );      break;
1484                 default:
1485                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1486                         ret = ERRPTR;
1487                         break;
1488                 }
1489                 break;
1490         
1491         default:
1492                 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1493                 ret = ERRPTR;
1494                 break;
1495         }
1496         
1497         if(Right && Right != preCastValue)      free(Right);
1498         
1499         return ret;
1500 }
1501
1502 /**
1503  * \brief Define a variable
1504  * \param Block Current block state
1505  * \param Type  Type of the variable
1506  * \param Name  Name of the variable
1507  * \return Boolean Failure
1508  */
1509 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1510 {
1511         tAST_Variable   *var, *prev = NULL;
1512         
1513         for( var = Block->FirstVar; var; prev = var, var = var->Next )
1514         {
1515                 if( strcmp(var->Name, Name) == 0 ) {
1516                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1517                         return ERRPTR;
1518                 }
1519         }
1520         
1521         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1522         var->Next = NULL;
1523         var->Type = Type;
1524         var->Object = Value;
1525         if(Value)       Object_Reference(Value);
1526         strcpy(var->Name, Name);
1527         
1528         if(prev)        prev->Next = var;
1529         else    Block->FirstVar = var;
1530         
1531         //printf("Defined variable %s (%i)\n", Name, Type);
1532         
1533         return var;
1534 }
1535
1536 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1537 {       
1538         tAST_Variable   *var = NULL;
1539         
1540         // Speed hack
1541         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1542                 var = VarNode->ValueCache;
1543                 #if TRACE_VAR_LOOKUPS
1544                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1545                         VarNode->Variable.Name, var,
1546                         VarNode->BlockState, VarNode->BlockIdent
1547                         );
1548                 #endif
1549         }
1550         else
1551         {
1552                 tAST_BlockState *bs;
1553                 for( bs = Block; bs; bs = bs->Parent )
1554                 {
1555                         for( var = bs->FirstVar; var; var = var->Next )
1556                         {
1557                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1558                                         break;
1559                         }
1560                         if(var) break;
1561                 }
1562                 
1563                 if( !var )
1564                 {
1565                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1566                                 // Define variable
1567                                 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1568                         }
1569                         else
1570                         {
1571                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1572                                 return NULL;
1573                         }
1574                 }
1575                 
1576                 #if TRACE_VAR_LOOKUPS
1577                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1578                         VarNode->Variable.Name, var,
1579                         Block, Block->Ident);
1580                 #endif
1581                 
1582                 VarNode->ValueCache = var;
1583                 VarNode->BlockState = Block;
1584                 VarNode->BlockIdent = Block->Ident;
1585         }
1586         
1587         return var;
1588 }
1589
1590 /**
1591  * \brief Set the value of a variable
1592  * \return Boolean Failure
1593  */
1594 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1595 {
1596         tAST_Variable   *var = Variable_Lookup(Block, VarNode, Value->Type);
1597         
1598         if( !var )      return -1;
1599         
1600         if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1601         {
1602                 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1603                         VarNode->Variable.Name);
1604                 return -2;
1605         }
1606
1607 //      printf("Assign %p to '%s'\n", Value, var->Name);
1608         Object_Reference(Value);
1609         Object_Dereference(var->Object);
1610         var->Object = Value;
1611         return 0;
1612 }
1613
1614 /**
1615  * \brief Get the value of a variable
1616  */
1617 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1618 {
1619         tAST_Variable   *var = Variable_Lookup(Block, VarNode, 0);
1620         
1621         if( !var )      return ERRPTR;
1622         
1623         Object_Reference(var->Object);
1624         return var->Object;
1625 }
1626
1627 /**
1628  * \brief Destorys a variable
1629  */
1630 void Variable_Destroy(tAST_Variable *Variable)
1631 {
1632 //      printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1633         Object_Dereference(Variable->Object);
1634         free(Variable);
1635 }
1636
1637 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
1638 {
1639         va_list args;
1640         
1641         if(Node) {
1642                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1643         }
1644         fprintf(stderr, "%s: ", Type);
1645         va_start(args, Format);
1646         vfprintf(stderr, Format, args);
1647         va_end(args);
1648         fprintf(stderr, "\n");
1649 }
1650 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1651 {
1652         va_list args;
1653         
1654         if(Node) {
1655                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1656         }
1657         fprintf(stderr, "error: ");
1658         va_start(args, Format);
1659         vfprintf(stderr, Format, args);
1660         va_end(args);
1661         fprintf(stderr, "\n");
1662 }

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