53558386e4822ea60c62ade946baf6070be8b6a6
[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' (ns='%s')\n",
512                         Function, Namespace->Name);
513                 return ERRPTR;
514         }
515         
516         return ret;
517 }
518
519 /**
520  * \brief Execute an object method function
521  * \param Script        Script context to execute in
522  * \param Object        Object in which to find the method
523  * \param MethodName    Name of method to call
524  * \param NArguments    Number of arguments to pass
525  * \param Arguments     Arguments passed
526  */
527 tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
528         tSpiderObject *Object, const char *MethodName,
529         int NArguments, tSpiderValue **Arguments)
530 {
531         tSpiderFunction *fcn;
532         tSpiderValue    this;
533         tSpiderValue    *newargs[NArguments+1];
534          int    i;
535         
536         // TODO: Support program defined objects
537         
538         // Search for the function
539         for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
540         {
541                 if( strcmp(fcn->Name, MethodName) == 0 )
542                         break;
543         }
544         // Error
545         if( !fcn )
546         {
547                 AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
548                         Object->Type->Name, MethodName);
549                 return ERRPTR;
550         }
551         
552         // Create the "this" argument
553         this.Type = SS_DATATYPE_OBJECT;
554         this.ReferenceCount = 1;
555         this.Object = Object;
556         newargs[0] = &this;
557         memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
558         
559         // Check the type of the arguments
560         for( i = 0; fcn->ArgTypes[i]; i ++ )
561         {
562                 if( i >= NArguments ) {
563                         for( ; fcn->ArgTypes[i]; i ++ ) ;
564                         AST_RuntimeError(NULL, "Argument count mismatch (%i passed, %i expected)",
565                                 NArguments, i);
566                         return ERRPTR;
567                 }
568                 if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
569                 {
570                         AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
571                                 Arguments[i]->Type, fcn->ArgTypes[i]);
572                         return ERRPTR;
573                 }
574         }
575         
576         // Call handler
577         return fcn->Handler(Script, NArguments+1, newargs);
578 }
579
580 /**
581  * \brief Execute a script function
582  * \param Script        Script context to execute in
583  * \param Function      Function name to execute
584  * \param NArguments    Number of arguments to pass
585  * \param Arguments     Arguments passed
586  */
587 tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
588         tSpiderNamespace *Namespace, const char *ClassName,
589         int NArguments, tSpiderValue **Arguments)
590 {
591          int    bFound = 0;     // Used to keep nesting levels down
592         tSpiderValue    *ret = ERRPTR;
593         tSpiderObjectDef        *class;
594         
595         // First: Find the function in the script
596         // TODO: Implement script-defined classes
597         #if 0
598         {
599                 tAST_Function   *astClass;
600                 for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
601                 {
602                         if( strcmp(astClass->Name, ClassName) == 0 )
603                                 break;
604                 }
605                 // Execute!
606                 if(astClass)
607                 {
608                         tAST_BlockState bs;
609                         tAST_Node       *arg;
610                          int    i = 0;
611                         
612                         // Build a block State
613                         bs.FirstVar = NULL;
614                         bs.RetVal = NULL;
615                         bs.Parent = NULL;
616                         bs.BaseNamespace = &Script->Variant->RootNamespace;
617                         bs.CurNamespace = NULL;
618                         bs.Script = Script;
619                         bs.Ident = giNextBlockIdent ++;
620                         
621                         for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
622                         {
623                                 if( i >= NArguments )   break;  // TODO: Return gracefully
624                                 // TODO: Type checks
625                                 Variable_Define(&bs,
626                                         arg->DefVar.DataType, arg->DefVar.Name,
627                                         Arguments[i]);
628                         }
629                         
630                         // Execute function
631                         ret = AST_ExecuteNode(&bs, astFcn->Code);
632                         if( ret != ERRPTR )
633                         {
634                                 Object_Dereference(ret);        // Dereference output of last block statement
635                                 ret = bs.RetVal;        // Set to return value of block
636                         }
637                         bFound = 1;
638                         
639                         while(bs.FirstVar)
640                         {
641                                 tAST_Variable   *nextVar = bs.FirstVar->Next;
642                                 Variable_Destroy( bs.FirstVar );
643                                 bs.FirstVar = nextVar;
644                         }
645                 }
646         }
647         #endif
648         
649         // Didn't find it in script?
650         if(!bFound)
651         {
652                 class = NULL;   // Just to allow the below code to be neat
653                 
654                 //if( !Namespace )
655                 //      Namespace = &Script->Variant->RootNamespace;
656                 
657                 // Second: Scan current namespace
658                 if( !class && Namespace )
659                 {
660                         for( class = Namespace->Classes; class; class = class->Next )
661                         {
662                                 if( strcmp( class->Name, ClassName ) == 0 )
663                                         break;
664                         }
665                 }
666                 
667                 #if 0
668                 // Third: Search the variant's global exports
669                 if( !class )
670                 {
671                         for( class = Script->Variant->Classes; class; class = fcn->Next )
672                         {
673                                 if( strcmp( class->Name, Function ) == 0 )
674                                         break;
675                         }
676                 }
677                 #endif
678                 
679                 #if 0
680                 // Fourth: Search language exports
681                 if( !class )
682                 {
683                         for( class = gpExports_First; class; class = fcn->Next )
684                         {
685                                 if( strcmp( class->Name, ClassName ) == 0 )
686                                         break;
687                         }
688                 }
689                 #endif
690                 
691                 // Execute!
692                 if(class)
693                 {
694                         tSpiderObject   *obj;
695                         // TODO: Type Checking
696                         
697                         // Call constructor
698                         obj = class->Constructor( NArguments, Arguments );
699                         if( obj == NULL || obj == ERRPTR )
700                                 return (void *)obj;
701                         
702                         // Creatue return object
703                         ret = malloc( sizeof(tSpiderValue) );
704                         ret->Type = SS_DATATYPE_OBJECT;
705                         ret->ReferenceCount = 1;
706                         ret->Object = obj;
707                         bFound = 1;
708                 }
709         }
710         
711         // Not found?
712         if(!bFound)
713         {
714                 fprintf(stderr, "Undefined reference to class '%s'\n", ClassName);
715                 return ERRPTR;
716         }
717         
718         return ret;
719 }
720
721
722 /**
723  * \brief Execute an AST node and return its value
724  * \param Block Execution context
725  * \param Node  Node to execute
726  */
727 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
728 {
729         tAST_Node       *node;
730         tSpiderValue    *ret = NULL, *tmpobj;
731         tSpiderValue    *op1, *op2;     // Binary operations
732          int    cmp;    // Used in comparisons
733          int    i;
734         
735         switch(Node->Type)
736         {
737         // No Operation
738         case NODETYPE_NOP:
739                 ret = NULL;
740                 break;
741         
742         // Code block
743         case NODETYPE_BLOCK:
744                 {
745                         tAST_BlockState blockInfo;
746                         blockInfo.Parent = Block;
747                         blockInfo.Script = Block->Script;
748                         blockInfo.FirstVar = NULL;
749                         blockInfo.RetVal = NULL;
750                         blockInfo.BaseNamespace = Block->BaseNamespace;
751                         blockInfo.CurNamespace = NULL;
752                         blockInfo.BreakTarget = NULL;
753                         blockInfo.Ident = giNextBlockIdent ++;
754                         ret = NULL;
755                         // Loop over all nodes, or until the return value is set
756                         for(node = Node->Block.FirstChild;
757                                 node && !blockInfo.RetVal && !blockInfo.BreakTarget;
758                                 node = node->NextSibling )
759                         {
760                                 ret = AST_ExecuteNode(&blockInfo, node);
761                                 if(ret == ERRPTR)       break;  // Error check
762                                 if(ret != NULL) Object_Dereference(ret);        // Free unused value
763                         }
764                         // Clean up variables
765                         while(blockInfo.FirstVar)
766                         {
767                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
768                                 Variable_Destroy( blockInfo.FirstVar );
769                                 blockInfo.FirstVar = nextVar;
770                         }
771                         // Clear ret if not an error
772                         if(ret != ERRPTR)       ret = NULL;
773                         
774                         // Set parent's return value if needed
775                         if( blockInfo.RetVal )
776                                 Block->RetVal = blockInfo.RetVal;
777                         if( blockInfo.BreakTarget ) {
778                                 Block->BreakTarget = blockInfo.BreakTarget;
779                                 Block->BreakType = blockInfo.BreakType;
780                         }
781                         
782                         // TODO: Unset break if break type deontes a block break
783                 }
784                 
785                 break;
786         
787         // Assignment
788         case NODETYPE_ASSIGN:
789                 // TODO: Support assigning to object attributes
790                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
791                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
792                         return ERRPTR;
793                 }
794                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
795                 if(ret == ERRPTR)       return ERRPTR;
796                 
797                 // Perform assignment operation
798                 if( Node->Assign.Operation != NODETYPE_NOP )
799                 {
800                         tSpiderValue    *varVal = Variable_GetValue(Block, Node->Assign.Dest);
801                         tSpiderValue    *value;
802                         value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
803                         if(value == ERRPTR)     return ERRPTR;
804                         if(ret) Object_Dereference(ret);
805                         if(varVal)      Object_Dereference(varVal);
806                         ret = value;
807                 }
808                 
809                 // Set the variable value
810                 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
811                         Object_Dereference( ret );
812                         return ERRPTR;
813                 }
814                 break;
815         
816         // Post increment/decrement
817         case NODETYPE_POSTINC:
818         case NODETYPE_POSTDEC:
819                 {
820                         tSpiderValue    *varVal, *value;
821                         static tSpiderValue     one = {
822                                 .Type = SS_DATATYPE_INTEGER,
823                                 .ReferenceCount = 1,
824                                 {.Integer = 1}
825                                 };
826                         
827                         // TODO: Support assigning to object attributes
828                         if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
829                                 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
830                                 return ERRPTR;
831                         }
832                 
833                         // Get values (current variable contents and a static one)
834                         varVal = Variable_GetValue(Block, Node->UniOp.Value);
835                         
836                         if( Node->Type == NODETYPE_POSTDEC )
837                                 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_SUBTRACT, varVal, &one);
838                         else
839                                 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_ADD, varVal, &one);
840                         if( value == ERRPTR )
841                                 return ERRPTR;
842                         
843                         ret = varVal;
844                 
845                         if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
846                                 Object_Dereference( ret );
847                                 return ERRPTR;
848                         }
849                         Object_Dereference( value );
850                 }
851                 break;
852         
853         // Function Call
854         case NODETYPE_METHODCALL:
855         case NODETYPE_FUNCTIONCALL:
856         case NODETYPE_CREATEOBJECT:
857                 // Logical block (used to allocate `params`)
858                 {
859                         tSpiderNamespace        *ns = Block->CurNamespace;
860                         tSpiderValue    *params[Node->FunctionCall.NumArgs];
861                         i = 0;
862                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
863                         {
864                                 params[i] = AST_ExecuteNode(Block, node);
865                                 if( params[i] == ERRPTR ) {
866                                         while(i--)      Object_Dereference(params[i]);
867                                         ret = ERRPTR;
868                                         goto _return;
869                                 }
870                                 i ++;
871                         }
872                         
873                         if( !ns )       ns = Block->BaseNamespace;
874                         
875                         // Call the function
876                         if( Node->Type == NODETYPE_CREATEOBJECT )
877                         {
878                                 ret = SpiderScript_CreateObject(Block->Script,
879                                         ns,
880                                         Node->FunctionCall.Name,
881                                         Node->FunctionCall.NumArgs, params
882                                         );
883                         }
884                         else if( Node->Type == NODETYPE_METHODCALL )
885                         {
886                                 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
887                                 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
888                                         AST_RuntimeError(Node->FunctionCall.Object,
889                                                 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
890                                         while(i--)      Object_Dereference(params[i]);
891                                         ret = ERRPTR;
892                                         break;
893                                 }
894                                 ret = SpiderScript_ExecuteMethod(Block->Script,
895                                         obj->Object, Node->FunctionCall.Name,
896                                         Node->FunctionCall.NumArgs, params
897                                         );
898                                 Object_Dereference(obj);
899                         }
900                         else
901                         {
902                                 ret = SpiderScript_ExecuteFunction(Block->Script,
903                                         ns, Node->FunctionCall.Name,
904                                         Node->FunctionCall.NumArgs, params
905                                         );
906                         }
907
908                         
909                         // Dereference parameters
910                         while(i--)      Object_Dereference(params[i]);
911                         
912                         // falls out
913                 }
914                 break;
915         
916         // Conditional
917         case NODETYPE_IF:
918                 ret = AST_ExecuteNode(Block, Node->If.Condition);
919                 if( ret == ERRPTR )     break;
920                 if( SpiderScript_IsValueTrue(ret) ) {
921                         tmpobj = AST_ExecuteNode(Block, Node->If.True);
922                 }
923                 else {
924                         tmpobj = AST_ExecuteNode(Block, Node->If.False);
925                 }
926                 Object_Dereference(ret);
927                 if( tmpobj == ERRPTR )  return ERRPTR;
928                 Object_Dereference(tmpobj);
929                 ret = NULL;
930                 break;
931         
932         // Loop
933         case NODETYPE_LOOP:
934                 // Initialise
935                 ret = AST_ExecuteNode(Block, Node->For.Init);
936                 if(ret == ERRPTR)       break;
937                 
938                 // Check initial condition
939                 if( !Node->For.bCheckAfter )
940                 {
941                         Object_Dereference(ret);
942                 
943                         ret = AST_ExecuteNode(Block, Node->For.Condition);
944                         if(ret == ERRPTR)       return ERRPTR;
945                         if(!SpiderScript_IsValueTrue(ret)) {
946                                 Object_Dereference(ret);
947                                 ret = NULL;
948                                 break;
949                         }
950                 }
951         
952                 // Perform loop
953                 for( ;; )
954                 {
955                         Object_Dereference(ret);
956                         
957                         // Code
958                         ret = AST_ExecuteNode(Block, Node->For.Code);
959                         if(ret == ERRPTR)       return ERRPTR;
960                         Object_Dereference(ret);
961                         
962                         if(Block->BreakTarget)
963                         {
964                                 if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
965                                 {
966                                         // Ours
967                                         free((void*)Block->BreakTarget);        Block->BreakTarget = NULL;
968                                         if( Block->BreakType == NODETYPE_CONTINUE ) {
969                                                 // Continue, just keep going
970                                         }
971                                         else
972                                                 break;
973                                 }
974                                 else
975                                         break;  // Break out of this loop
976                         }
977                         
978                         // Increment
979                         ret = AST_ExecuteNode(Block, Node->For.Increment);
980                         if(ret == ERRPTR)       return ERRPTR;
981                         Object_Dereference(ret);
982                         
983                         // Check condition
984                         ret = AST_ExecuteNode(Block, Node->For.Condition);
985                         if(ret == ERRPTR)       return ERRPTR;
986                         if(!SpiderScript_IsValueTrue(ret))      break;
987                 }
988                 Object_Dereference(ret);
989                 ret = NULL;
990                 break;
991         
992         // Return
993         case NODETYPE_RETURN:
994                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
995                 if(ret == ERRPTR)       break;
996                 Block->RetVal = ret;    // Return value set
997                 ret = NULL;     // the `return` statement does not return a value
998                 break;
999         
1000         case NODETYPE_BREAK:
1001         case NODETYPE_CONTINUE:
1002                 Block->BreakTarget = strdup(Node->Variable.Name);
1003                 Block->BreakType = Node->Type;
1004                 break;
1005         
1006         // Define a variable
1007         case NODETYPE_DEFVAR:
1008                 if( Node->DefVar.InitialValue ) {
1009                         tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
1010                         if(tmpobj == ERRPTR)    return ERRPTR;
1011                 }
1012                 else {
1013                         tmpobj = NULL;
1014                 }
1015                 ret = NULL;
1016                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
1017                         ret = ERRPTR;
1018                 Object_Dereference(tmpobj);
1019                 break;
1020         
1021         // Scope
1022         case NODETYPE_SCOPE:
1023                 {
1024                 tSpiderNamespace        *ns;
1025                 
1026                 // Set current namespace if unset
1027                 if( !Block->CurNamespace )
1028                         Block->CurNamespace = Block->BaseNamespace;
1029                 
1030                 // Empty string means use the root namespace
1031                 if( Node->Scope.Name[0] == '\0' )
1032                 {
1033                         ns = &Block->Script->Variant->RootNamespace;
1034                 }
1035                 else
1036                 {
1037                         // Otherwise scan the current namespace for the element
1038                         for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
1039                         {
1040                                 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
1041                                         break;
1042                         }
1043                 }
1044                 if(!ns) {
1045                         AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
1046                         ret = ERRPTR;
1047                         break;
1048                 }
1049                 Block->CurNamespace = ns;
1050                 
1051                 ret = AST_ExecuteNode(Block, Node->Scope.Element);
1052                 }
1053                 break;
1054         
1055         // Variable
1056         case NODETYPE_VARIABLE:
1057                 ret = Variable_GetValue( Block, Node );
1058                 break;
1059         
1060         // Element of an Object
1061         case NODETYPE_ELEMENT:
1062                 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
1063                 if(tmpobj == ERRPTR)    return ERRPTR;
1064                 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
1065                 {
1066                         AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
1067                         ret = ERRPTR;
1068                         break ;
1069                 }
1070                 
1071                 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
1072                 {
1073                         if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
1074                         {
1075                                 ret = tmpobj->Object->Attributes[i];
1076                                 Object_Reference(ret);
1077                                 break;
1078                         }
1079                 }
1080                 if( i == tmpobj->Object->Type->NAttributes )
1081                 {
1082                         AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
1083                                 Node->Scope.Name, tmpobj->Object->Type->Name);
1084                         ret = ERRPTR;
1085                 }
1086                 break;
1087
1088         // Cast a value to another
1089         case NODETYPE_CAST:
1090                 {
1091                 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
1092                 if(tmpobj == ERRPTR) return ERRPTR;
1093                 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
1094                 Object_Dereference(tmpobj);
1095                 }
1096                 break;
1097
1098         // Index into an array
1099         case NODETYPE_INDEX:
1100                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
1101                 if(op1 == ERRPTR)       return ERRPTR;
1102                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);        // Offset
1103                 if(op2 == ERRPTR) {
1104                         Object_Dereference(op1);
1105                         return ERRPTR;
1106                 }
1107                 
1108                 if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
1109                 {
1110                         // TODO: Implement "operator []" on objects
1111                         AST_RuntimeError(Node, "Indexing non-array");
1112                         ret = ERRPTR;
1113                         break;
1114                 }
1115                 
1116                 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
1117                         AST_RuntimeError(Node, "Array index is not an integer");
1118                         ret = ERRPTR;
1119                         break;
1120                 }
1121                 
1122                 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
1123                 {
1124                         tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
1125                         Object_Dereference(op2);
1126                         op2 = tmpobj;
1127                 }
1128                 
1129                 if( op2->Integer >= op1->Array.Length ) {
1130                         AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
1131                                 op2->Integer, op1->Array.Length);
1132                         ret = ERRPTR;
1133                         break;
1134                 }
1135                 
1136                 ret = op1->Array.Items[ op2->Integer ];
1137                 Object_Reference(ret);
1138                 
1139                 Object_Dereference(op1);
1140                 Object_Dereference(op2);
1141                 break;
1142
1143         // TODO: Implement runtime constants
1144         case NODETYPE_CONSTANT:
1145                 // TODO: Scan namespace for function
1146                 AST_RuntimeError(Node, "TODO - Runtime Constants");
1147                 ret = ERRPTR;
1148                 break;
1149         
1150         // Constant Values
1151         case NODETYPE_STRING:
1152         case NODETYPE_INTEGER:
1153         case NODETYPE_REAL:
1154                 ret = &Node->Constant;
1155                 Object_Reference(ret);
1156                 break;
1157         
1158         // --- Operations ---
1159         // Boolean Operations
1160         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
1161                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1162                 if(op1 == ERRPTR)       return ERRPTR;
1163                 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
1164                 Object_Dereference(op1);
1165                 break;
1166         case NODETYPE_LOGICALAND:       // Logical AND (&&)
1167         case NODETYPE_LOGICALOR:        // Logical OR (||)
1168         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
1169                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1170                 if(op1 == ERRPTR)       return ERRPTR;
1171                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1172                 if(op2 == ERRPTR) {
1173                         Object_Dereference(op1);
1174                         return ERRPTR;
1175                 }
1176                 
1177                 switch( Node->Type )
1178                 {
1179                 case NODETYPE_LOGICALAND:
1180                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
1181                         break;
1182                 case NODETYPE_LOGICALOR:
1183                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
1184                         break;
1185                 case NODETYPE_LOGICALXOR:
1186                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
1187                         break;
1188                 default:        break;
1189                 }
1190                 
1191                 // Free intermediate objects
1192                 Object_Dereference(op1);
1193                 Object_Dereference(op2);
1194                 break;
1195         
1196         // Comparisons
1197         case NODETYPE_EQUALS:
1198         case NODETYPE_LESSTHAN:
1199         case NODETYPE_GREATERTHAN:
1200         case NODETYPE_LESSTHANEQUAL:
1201         case NODETYPE_GREATERTHANEQUAL:
1202                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1203                 if(op1 == ERRPTR)       return ERRPTR;
1204                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1205                 if(op2 == ERRPTR) {
1206                         Object_Dereference(op1);
1207                         ret = ERRPTR;
1208                         break;
1209                 }
1210                 
1211                 if( !op1 || !op2 ) {
1212                         AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
1213                         if(op1) Object_Dereference(op1);
1214                         if(op2) Object_Dereference(op2);
1215                         ret = SpiderScript_CreateInteger( !op1 && !op2 );
1216                         break;
1217                 }
1218                 
1219                 // Convert types
1220                 if( op1->Type != op2->Type ) {
1221                         // If dynamically typed, convert op2 to op1's type
1222                         if(Block->Script->Variant->bImplicitCasts)
1223                         {
1224                                 tmpobj = op2;
1225                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
1226                                 Object_Dereference(tmpobj);
1227                                 if(op2 == ERRPTR) {
1228                                         Object_Dereference(op1);
1229                                         return ERRPTR;
1230                                 }
1231                         }
1232                         // If statically typed, this should never happen, but catch it anyway
1233                         else {
1234                                 AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
1235                                         op1->Type, op2->Type);
1236                                 ret = ERRPTR;
1237                                 break;
1238                         }
1239                 }
1240                 // Do operation
1241                 switch(op1->Type)
1242                 {
1243                 // - String Compare (does a strcmp, well memcmp)
1244                 case SS_DATATYPE_STRING:
1245                         // Call memcmp to do most of the work
1246                         cmp = memcmp(
1247                                 op1->String.Data, op2->String.Data,
1248                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
1249                                 );
1250                         // Handle reaching the end of the string
1251                         if( cmp == 0 ) {
1252                                 if( op1->String.Length == op2->String.Length )
1253                                         cmp = 0;
1254                                 else if( op1->String.Length < op2->String.Length )
1255                                         cmp = 1;
1256                                 else
1257                                         cmp = -1;
1258                         }
1259                         break;
1260                 
1261                 // - Integer Comparisons
1262                 case SS_DATATYPE_INTEGER:
1263                         if( op1->Integer == op2->Integer )
1264                                 cmp = 0;
1265                         else if( op1->Integer < op2->Integer )
1266                                 cmp = -1;
1267                         else
1268                                 cmp = 1;
1269                         break;
1270                 // - Real Number Comparisons
1271                 case SS_DATATYPE_REAL:
1272                         cmp = (op1->Real - op2->Real) / op2->Real * 10000;      // < 0.1% difference is equality
1273                         break;
1274                 default:
1275                         AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
1276                         ret = ERRPTR;
1277                         break;
1278                 }
1279                 
1280                 // Free intermediate objects
1281                 Object_Dereference(op1);
1282                 Object_Dereference(op2);
1283                 
1284                 // Error check
1285                 if( ret == ERRPTR )
1286                         break;
1287                 
1288                 // Create return
1289                 switch(Node->Type)
1290                 {
1291                 case NODETYPE_EQUALS:   ret = SpiderScript_CreateInteger(cmp == 0);     break;
1292                 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0);      break;
1293                 case NODETYPE_GREATERTHAN:      ret = SpiderScript_CreateInteger(cmp > 0);      break;
1294                 case NODETYPE_LESSTHANEQUAL:    ret = SpiderScript_CreateInteger(cmp <= 0);     break;
1295                 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0);     break;
1296                 default:
1297                         AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
1298                         ret = ERRPTR;
1299                         break;
1300                 }
1301                 break;
1302         
1303         // General Unary Operations
1304         case NODETYPE_BWNOT:    // Bitwise NOT (~)
1305         case NODETYPE_NEGATE:   // Negation (-)
1306                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1307                 if(op1 == ERRPTR)       return ERRPTR;
1308                 ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
1309                 Object_Dereference(op1);
1310                 break;
1311         
1312         // General Binary Operations
1313         case NODETYPE_ADD:
1314         case NODETYPE_SUBTRACT:
1315         case NODETYPE_MULTIPLY:
1316         case NODETYPE_DIVIDE:
1317         case NODETYPE_MODULO:
1318         case NODETYPE_BWAND:
1319         case NODETYPE_BWOR:
1320         case NODETYPE_BWXOR:
1321         case NODETYPE_BITSHIFTLEFT:
1322         case NODETYPE_BITSHIFTRIGHT:
1323         case NODETYPE_BITROTATELEFT:
1324                 // Get operands
1325                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1326                 if(op1 == ERRPTR)       return ERRPTR;
1327                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1328                 if(op2 == ERRPTR) {
1329                         Object_Dereference(op1);
1330                         return ERRPTR;
1331                 }
1332                 
1333                 ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
1334                 
1335                 // Free intermediate objects
1336                 Object_Dereference(op1);
1337                 Object_Dereference(op2);
1338                 break;
1339         
1340         //default:
1341         //      ret = NULL;
1342         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
1343         //      break;
1344         }
1345 _return:
1346         // Reset namespace when no longer needed
1347         if( Node->Type != NODETYPE_SCOPE )
1348                 Block->CurNamespace = NULL;
1349
1350         #if TRACE_NODE_RETURNS
1351         if(ret && ret != ERRPTR) {
1352                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
1353         }
1354         else {
1355                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
1356         }
1357         #endif
1358
1359         return ret;
1360 }
1361
1362 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value)
1363 {
1364         tSpiderValue    *ret;
1365         #if 0
1366         if( Value->Type == SS_DATATYPE_OBJECT )
1367         {
1368                 const char      *fcnname;
1369                 switch(Operation)
1370                 {
1371                 case NODETYPE_NEGATE:   fcnname = "-ve";        break;
1372                 case NODETYPE_BWNOT:    fcnname = "~";  break;
1373                 default:        fcnname = NULL; break;
1374                 }
1375                 
1376                 if( fcnname )
1377                 {
1378                         ret = Object_ExecuteMethod(Value->Object, fcnname, );
1379                         if( ret != ERRPTR )
1380                                 return ret;
1381                         // Fall through and try casting (which will usually fail)
1382                 }
1383         }
1384         #endif
1385         switch(Value->Type)
1386         {
1387         // Integer Operations
1388         case SS_DATATYPE_INTEGER:
1389                 switch(Operation)
1390                 {
1391                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Integer );    break;
1392                 case NODETYPE_BWNOT:    ret = SpiderScript_CreateInteger( ~Value->Integer );    break;
1393                 default:
1394                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1395                         ret = ERRPTR;
1396                         break;
1397                 }
1398                 break;
1399         // Real number Operations
1400         case SS_DATATYPE_REAL:
1401                 switch(Operation)
1402                 {
1403                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Real );       break;
1404                 default:
1405                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1406                         ret = ERRPTR;
1407                         break;
1408                 }
1409                 break;
1410         
1411         default:
1412                 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1413                 ret = ERRPTR;
1414                 break;
1415         }
1416         
1417         return ret;
1418 }
1419
1420 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1421 {
1422         tSpiderValue    *preCastValue = Right;
1423         tSpiderValue    *ret;
1424         
1425         // Convert types
1426         if( Left && Right && Left->Type != Right->Type )
1427         {
1428                 #if 0
1429                 // Object types
1430                 // - Operator overload functions
1431                 if( Left->Type == SS_DATATYPE_OBJECT )
1432                 {
1433                         const char      *fcnname;
1434                         switch(Operation)
1435                         {
1436                         case NODETYPE_ADD:      fcnname = "+";  break;
1437                         case NODETYPE_SUBTRACT: fcnname = "-";  break;
1438                         case NODETYPE_MULTIPLY: fcnname = "*";  break;
1439                         case NODETYPE_DIVIDE:   fcnname = "/";  break;
1440                         case NODETYPE_MODULO:   fcnname = "%";  break;
1441                         case NODETYPE_BWAND:    fcnname = "&";  break;
1442                         case NODETYPE_BWOR:     fcnname = "|";  break;
1443                         case NODETYPE_BWXOR:    fcnname = "^";  break;
1444                         case NODETYPE_BITSHIFTLEFT:     fcnname = "<<"; break;
1445                         case NODETYPE_BITSHIFTRIGHT:fcnname = ">>";     break;
1446                         case NODETYPE_BITROTATELEFT:fcnname = "<<<";    break;
1447                         default:        fcnname = NULL; break;
1448                         }
1449                         
1450                         if( fcnname )
1451                         {
1452                                 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1453                                 if( ret != ERRPTR )
1454                                         return ret;
1455                                 // Fall through and try casting (which will usually fail)
1456                         }
1457                 }
1458                 #endif
1459                 
1460                 // If implicit casts are allowed, convert Right to Left's type
1461                 if(Block->Script->Variant->bImplicitCasts)
1462                 {
1463                         Right = SpiderScript_CastValueTo(Left->Type, Right);
1464                         if(Right == ERRPTR)
1465                                 return ERRPTR;
1466                 }
1467                 // If statically typed, this should never happen, but catch it anyway
1468                 else {
1469                         AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
1470                         return ERRPTR;
1471                 }
1472         }
1473         
1474         // NULL Check
1475         if( Left == NULL || Right == NULL ) {
1476                 if(Right && Right != preCastValue)      free(Right);
1477                 return NULL;
1478         }
1479         
1480         // Do operation
1481         switch(Left->Type)
1482         {
1483         // String Concatenation
1484         case SS_DATATYPE_STRING:
1485                 switch(Operation)
1486                 {
1487                 case NODETYPE_ADD:      // Concatenate
1488                         ret = Object_StringConcat(Left, Right);
1489                         break;
1490                 default:
1491                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1492                         ret = ERRPTR;
1493                         break;
1494                 }
1495                 break;
1496         // Integer Operations
1497         case SS_DATATYPE_INTEGER:
1498                 switch(Operation)
1499                 {
1500                 case NODETYPE_ADD:      ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer );     break;
1501                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer );     break;
1502                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer );     break;
1503                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer );     break;
1504                 case NODETYPE_MODULO:   ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer );     break;
1505                 case NODETYPE_BWAND:    ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer );     break;
1506                 case NODETYPE_BWOR:     ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer );     break;
1507                 case NODETYPE_BWXOR:    ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer );     break;
1508                 case NODETYPE_BITSHIFTLEFT:     ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer );    break;
1509                 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer );        break;
1510                 case NODETYPE_BITROTATELEFT:
1511                         ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) );
1512                         break;
1513                 default:
1514                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
1515                         ret = ERRPTR;
1516                         break;
1517                 }
1518                 break;
1519         
1520         // Real Numbers
1521         case SS_DATATYPE_REAL:
1522                 switch(Operation)
1523                 {
1524                 case NODETYPE_ADD:      ret = SpiderScript_CreateReal( Left->Real + Right->Real );      break;
1525                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateReal( Left->Real - Right->Real );      break;
1526                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateReal( Left->Real * Right->Real );      break;
1527                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateReal( Left->Real / Right->Real );      break;
1528                 default:
1529                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1530                         ret = ERRPTR;
1531                         break;
1532                 }
1533                 break;
1534         
1535         default:
1536                 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1537                 ret = ERRPTR;
1538                 break;
1539         }
1540         
1541         if(Right && Right != preCastValue)      free(Right);
1542         
1543         return ret;
1544 }
1545
1546 /**
1547  * \brief Define a variable
1548  * \param Block Current block state
1549  * \param Type  Type of the variable
1550  * \param Name  Name of the variable
1551  * \return Boolean Failure
1552  */
1553 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1554 {
1555         tAST_Variable   *var, *prev = NULL;
1556         
1557         for( var = Block->FirstVar; var; prev = var, var = var->Next )
1558         {
1559                 if( strcmp(var->Name, Name) == 0 ) {
1560                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1561                         return ERRPTR;
1562                 }
1563         }
1564         
1565         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1566         var->Next = NULL;
1567         var->Type = Type;
1568         var->Object = Value;
1569         if(Value)       Object_Reference(Value);
1570         strcpy(var->Name, Name);
1571         
1572         if(prev)        prev->Next = var;
1573         else    Block->FirstVar = var;
1574         
1575         //printf("Defined variable %s (%i)\n", Name, Type);
1576         
1577         return var;
1578 }
1579
1580 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1581 {       
1582         tAST_Variable   *var = NULL;
1583         
1584         // Speed hack
1585         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1586                 var = VarNode->ValueCache;
1587                 #if TRACE_VAR_LOOKUPS
1588                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1589                         VarNode->Variable.Name, var,
1590                         VarNode->BlockState, VarNode->BlockIdent
1591                         );
1592                 #endif
1593         }
1594         else
1595         {
1596                 tAST_BlockState *bs;
1597                 for( bs = Block; bs; bs = bs->Parent )
1598                 {
1599                         for( var = bs->FirstVar; var; var = var->Next )
1600                         {
1601                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1602                                         break;
1603                         }
1604                         if(var) break;
1605                 }
1606                 
1607                 if( !var )
1608                 {
1609                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1610                                 // Define variable
1611                                 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1612                         }
1613                         else
1614                         {
1615                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1616                                 return NULL;
1617                         }
1618                 }
1619                 
1620                 #if TRACE_VAR_LOOKUPS
1621                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1622                         VarNode->Variable.Name, var,
1623                         Block, Block->Ident);
1624                 #endif
1625                 
1626                 VarNode->ValueCache = var;
1627                 VarNode->BlockState = Block;
1628                 VarNode->BlockIdent = Block->Ident;
1629         }
1630         
1631         return var;
1632 }
1633
1634 /**
1635  * \brief Set the value of a variable
1636  * \return Boolean Failure
1637  */
1638 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1639 {
1640         tAST_Variable   *var;
1641         
1642         var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1643         
1644         if( !var )      return -1;
1645         
1646         if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1647         {
1648                 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1649                         VarNode->Variable.Name);
1650                 return -2;
1651         }
1652
1653 //      printf("Assign %p to '%s'\n", Value, var->Name);
1654         Object_Reference(Value);
1655         Object_Dereference(var->Object);
1656         var->Object = Value;
1657         return 0;
1658 }
1659
1660 /**
1661  * \brief Get the value of a variable
1662  */
1663 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1664 {
1665         tAST_Variable   *var = Variable_Lookup(Block, VarNode, 0);
1666         
1667         if( !var )      return ERRPTR;
1668         
1669         Object_Reference(var->Object);
1670         return var->Object;
1671 }
1672
1673 /**
1674  * \brief Destorys a variable
1675  */
1676 void Variable_Destroy(tAST_Variable *Variable)
1677 {
1678 //      printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1679         Object_Dereference(Variable->Object);
1680         free(Variable);
1681 }
1682
1683 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
1684 {
1685         va_list args;
1686         
1687         if(Node) {
1688                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1689         }
1690         fprintf(stderr, "%s: ", Type);
1691         va_start(args, Format);
1692         vfprintf(stderr, Format, args);
1693         va_end(args);
1694         fprintf(stderr, "\n");
1695 }
1696 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1697 {
1698         va_list args;
1699         
1700         if(Node) {
1701                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1702         }
1703         fprintf(stderr, "error: ");
1704         va_start(args, Format);
1705         vfprintf(stderr, Format, args);
1706         va_end(args);
1707         fprintf(stderr, "\n");
1708 }

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