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

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