480ecc1903ffbdb9039327d03bddddba25dd763f
[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.Ident = giNextBlockIdent ++;
753                         ret = NULL;
754                         // Loop over all nodes, or until the return value is set
755                         for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
756                         {
757                                 ret = AST_ExecuteNode(&blockInfo, node);
758                                 if(ret == ERRPTR)       break;  // Error check
759                                 if(ret != NULL) Object_Dereference(ret);        // Free unused value
760                         }
761                         // Clean up variables
762                         while(blockInfo.FirstVar)
763                         {
764                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
765                                 Variable_Destroy( blockInfo.FirstVar );
766                                 blockInfo.FirstVar = nextVar;
767                         }
768                         // Clear ret if not an error
769                         if(ret != ERRPTR)       ret = NULL;
770                         
771                         // Set parent's return value if needed
772                         if( blockInfo.RetVal )
773                                 Block->RetVal = blockInfo.RetVal;
774                 }
775                 
776                 break;
777         
778         // Assignment
779         case NODETYPE_ASSIGN:
780                 // TODO: Support assigning to object attributes
781                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
782                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
783                         return ERRPTR;
784                 }
785                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
786                 if(ret == ERRPTR)       return ERRPTR;
787                 
788                 // Perform assignment operation
789                 if( Node->Assign.Operation != NODETYPE_NOP )
790                 {
791                         tSpiderValue    *varVal = Variable_GetValue(Block, Node->Assign.Dest);
792                         tSpiderValue    *value;
793                         value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
794                         if(value == ERRPTR)     return ERRPTR;
795                         if(ret) Object_Dereference(ret);
796                         if(varVal)      Object_Dereference(varVal);
797                         ret = value;
798                 }
799                 
800                 // Set the variable value
801                 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
802                         Object_Dereference( ret );
803                         return ERRPTR;
804                 }
805                 break;
806         
807         // Post increment/decrement
808         case NODETYPE_POSTINC:
809         case NODETYPE_POSTDEC:
810                 {
811                         tSpiderValue    *varVal, *value;
812                         static tSpiderValue     one = {
813                                 .Type = SS_DATATYPE_INTEGER,
814                                 .ReferenceCount = 1,
815                                 {.Integer = 1}
816                                 };
817                         
818                         // TODO: Support assigning to object attributes
819                         if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
820                                 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
821                                 return ERRPTR;
822                         }
823                 
824                         // Get values (current variable contents and a static one)
825                         varVal = Variable_GetValue(Block, Node->UniOp.Value);
826                         
827                         if( Node->Type == NODETYPE_POSTDEC )
828                                 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_SUBTRACT, varVal, &one);
829                         else
830                                 value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_ADD, varVal, &one);
831                         if( value == ERRPTR )
832                                 return ERRPTR;
833                         
834                         ret = varVal;
835                 
836                         if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
837                                 Object_Dereference( ret );
838                                 return ERRPTR;
839                         }
840                         Object_Dereference( value );
841                 }
842                 break;
843         
844         // Function Call
845         case NODETYPE_METHODCALL:
846         case NODETYPE_FUNCTIONCALL:
847         case NODETYPE_CREATEOBJECT:
848                 // Logical block (used to allocate `params`)
849                 {
850                         tSpiderNamespace        *ns = Block->CurNamespace;
851                         tSpiderValue    *params[Node->FunctionCall.NumArgs];
852                         i = 0;
853                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
854                         {
855                                 params[i] = AST_ExecuteNode(Block, node);
856                                 if( params[i] == ERRPTR ) {
857                                         while(i--)      Object_Dereference(params[i]);
858                                         ret = ERRPTR;
859                                         goto _return;
860                                 }
861                                 i ++;
862                         }
863                         
864                         if( !ns )       ns = Block->BaseNamespace;
865                         
866                         // Call the function
867                         if( Node->Type == NODETYPE_CREATEOBJECT )
868                         {
869                                 ret = SpiderScript_CreateObject(Block->Script,
870                                         ns,
871                                         Node->FunctionCall.Name,
872                                         Node->FunctionCall.NumArgs, params
873                                         );
874                         }
875                         else if( Node->Type == NODETYPE_METHODCALL )
876                         {
877                                 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
878                                 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
879                                         AST_RuntimeError(Node->FunctionCall.Object,
880                                                 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
881                                         while(i--)      Object_Dereference(params[i]);
882                                         ret = ERRPTR;
883                                         break;
884                                 }
885                                 ret = SpiderScript_ExecuteMethod(Block->Script,
886                                         obj->Object, Node->FunctionCall.Name,
887                                         Node->FunctionCall.NumArgs, params
888                                         );
889                                 Object_Dereference(obj);
890                         }
891                         else
892                         {
893                                 ret = SpiderScript_ExecuteFunction(Block->Script,
894                                         ns, Node->FunctionCall.Name,
895                                         Node->FunctionCall.NumArgs, params
896                                         );
897                         }
898
899                         
900                         // Dereference parameters
901                         while(i--)      Object_Dereference(params[i]);
902                         
903                         // falls out
904                 }
905                 break;
906         
907         // Conditional
908         case NODETYPE_IF:
909                 ret = AST_ExecuteNode(Block, Node->If.Condition);
910                 if( ret == ERRPTR )     break;
911                 if( SpiderScript_IsValueTrue(ret) ) {
912                         tmpobj = AST_ExecuteNode(Block, Node->If.True);
913                 }
914                 else {
915                         tmpobj = AST_ExecuteNode(Block, Node->If.False);
916                 }
917                 Object_Dereference(ret);
918                 if( tmpobj == ERRPTR )  return ERRPTR;
919                 Object_Dereference(tmpobj);
920                 ret = NULL;
921                 break;
922         
923         // Loop
924         case NODETYPE_LOOP:
925                 ret = AST_ExecuteNode(Block, Node->For.Init);
926                 if(ret == ERRPTR)       break;
927                 if( Node->For.bCheckAfter )
928                 {
929                         do {
930                                 Object_Dereference(ret);
931                                 ret = AST_ExecuteNode(Block, Node->For.Code);
932                                 if(ret == ERRPTR)       return ERRPTR;
933                                 Object_Dereference(ret);
934                                 ret = AST_ExecuteNode(Block, Node->For.Increment);
935                                 if(ret == ERRPTR)       return ERRPTR;
936                                 Object_Dereference(ret);
937                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
938                                 if(ret == ERRPTR)       return ERRPTR;
939                         } while( SpiderScript_IsValueTrue(ret) );
940                 }
941                 else
942                 {
943                         Object_Dereference(ret);
944                         ret = AST_ExecuteNode(Block, Node->For.Condition);
945                         if(ret == ERRPTR)       return ERRPTR;
946                         while( SpiderScript_IsValueTrue(ret) ) {
947                                 Object_Dereference(ret);
948                                 ret = AST_ExecuteNode(Block, Node->For.Code);
949                                 if(ret == ERRPTR)       return ERRPTR;
950                                 Object_Dereference(ret);
951                                 ret = AST_ExecuteNode(Block, Node->For.Increment);
952                                 if(ret == ERRPTR)       return ERRPTR;
953                                 Object_Dereference(ret);
954                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
955                                 if(ret == ERRPTR)       return ERRPTR;
956                         }
957                 }
958                 Object_Dereference(ret);
959                 ret = NULL;
960                 break;
961         
962         // Return
963         case NODETYPE_RETURN:
964                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
965                 if(ret == ERRPTR)       break;
966                 Block->RetVal = ret;    // Return value set
967                 ret = NULL;     // the `return` statement does not return a value
968                 break;
969         
970         // Define a variable
971         case NODETYPE_DEFVAR:
972                 if( Node->DefVar.InitialValue ) {
973                         tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
974                         if(tmpobj == ERRPTR)    return ERRPTR;
975                 }
976                 else {
977                         tmpobj = NULL;
978                 }
979                 ret = NULL;
980                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
981                         ret = ERRPTR;
982                 Object_Dereference(tmpobj);
983                 break;
984         
985         // Scope
986         case NODETYPE_SCOPE:
987                 {
988                 tSpiderNamespace        *ns;
989                 
990                 // Set current namespace if unset
991                 if( !Block->CurNamespace )
992                         Block->CurNamespace = Block->BaseNamespace;
993                 
994                 // Empty string means use the root namespace
995                 if( Node->Scope.Name[0] == '\0' )
996                 {
997                         ns = &Block->Script->Variant->RootNamespace;
998                 }
999                 else
1000                 {
1001                         // Otherwise scan the current namespace for the element
1002                         for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
1003                         {
1004                                 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
1005                                         break;
1006                         }
1007                 }
1008                 if(!ns) {
1009                         AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
1010                         ret = ERRPTR;
1011                         break;
1012                 }
1013                 Block->CurNamespace = ns;
1014                 
1015                 ret = AST_ExecuteNode(Block, Node->Scope.Element);
1016                 }
1017                 break;
1018         
1019         // Variable
1020         case NODETYPE_VARIABLE:
1021                 ret = Variable_GetValue( Block, Node );
1022                 break;
1023         
1024         // Element of an Object
1025         case NODETYPE_ELEMENT:
1026                 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
1027                 if(tmpobj == ERRPTR)    return ERRPTR;
1028                 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
1029                 {
1030                         AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
1031                         ret = ERRPTR;
1032                         break ;
1033                 }
1034                 
1035                 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
1036                 {
1037                         if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
1038                         {
1039                                 ret = tmpobj->Object->Attributes[i];
1040                                 Object_Reference(ret);
1041                                 break;
1042                         }
1043                 }
1044                 if( i == tmpobj->Object->Type->NAttributes )
1045                 {
1046                         AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
1047                                 Node->Scope.Name, tmpobj->Object->Type->Name);
1048                         ret = ERRPTR;
1049                 }
1050                 break;
1051
1052         // Cast a value to another
1053         case NODETYPE_CAST:
1054                 {
1055                 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
1056                 if(tmpobj == ERRPTR) return ERRPTR;
1057                 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
1058                 Object_Dereference(tmpobj);
1059                 }
1060                 break;
1061
1062         // Index into an array
1063         case NODETYPE_INDEX:
1064                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
1065                 if(op1 == ERRPTR)       return ERRPTR;
1066                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);        // Offset
1067                 if(op2 == ERRPTR) {
1068                         Object_Dereference(op1);
1069                         return ERRPTR;
1070                 }
1071                 
1072                 if( !op1 || op1->Type != SS_DATATYPE_ARRAY )
1073                 {
1074                         // TODO: Implement "operator []" on objects
1075                         AST_RuntimeError(Node, "Indexing non-array");
1076                         ret = ERRPTR;
1077                         break;
1078                 }
1079                 
1080                 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
1081                         AST_RuntimeError(Node, "Array index is not an integer");
1082                         ret = ERRPTR;
1083                         break;
1084                 }
1085                 
1086                 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
1087                 {
1088                         tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
1089                         Object_Dereference(op2);
1090                         op2 = tmpobj;
1091                 }
1092                 
1093                 if( op2->Integer >= op1->Array.Length ) {
1094                         AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
1095                                 op2->Integer, op1->Array.Length);
1096                         ret = ERRPTR;
1097                         break;
1098                 }
1099                 
1100                 ret = op1->Array.Items[ op2->Integer ];
1101                 Object_Reference(ret);
1102                 
1103                 Object_Dereference(op1);
1104                 Object_Dereference(op2);
1105                 break;
1106
1107         // TODO: Implement runtime constants
1108         case NODETYPE_CONSTANT:
1109                 // TODO: Scan namespace for function
1110                 AST_RuntimeError(Node, "TODO - Runtime Constants");
1111                 ret = ERRPTR;
1112                 break;
1113         
1114         // Constant Values
1115         case NODETYPE_STRING:
1116         case NODETYPE_INTEGER:
1117         case NODETYPE_REAL:
1118                 ret = &Node->Constant;
1119                 Object_Reference(ret);
1120                 break;
1121         
1122         // --- Operations ---
1123         // Boolean Operations
1124         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
1125                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1126                 if(op1 == ERRPTR)       return ERRPTR;
1127                 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
1128                 Object_Dereference(op1);
1129                 break;
1130         case NODETYPE_LOGICALAND:       // Logical AND (&&)
1131         case NODETYPE_LOGICALOR:        // Logical OR (||)
1132         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
1133                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1134                 if(op1 == ERRPTR)       return ERRPTR;
1135                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1136                 if(op2 == ERRPTR) {
1137                         Object_Dereference(op1);
1138                         return ERRPTR;
1139                 }
1140                 
1141                 switch( Node->Type )
1142                 {
1143                 case NODETYPE_LOGICALAND:
1144                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
1145                         break;
1146                 case NODETYPE_LOGICALOR:
1147                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
1148                         break;
1149                 case NODETYPE_LOGICALXOR:
1150                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
1151                         break;
1152                 default:        break;
1153                 }
1154                 
1155                 // Free intermediate objects
1156                 Object_Dereference(op1);
1157                 Object_Dereference(op2);
1158                 break;
1159         
1160         // Comparisons
1161         case NODETYPE_EQUALS:
1162         case NODETYPE_LESSTHAN:
1163         case NODETYPE_GREATERTHAN:
1164         case NODETYPE_LESSTHANEQUAL:
1165         case NODETYPE_GREATERTHANEQUAL:
1166                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1167                 if(op1 == ERRPTR)       return ERRPTR;
1168                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1169                 if(op2 == ERRPTR) {
1170                         Object_Dereference(op1);
1171                         ret = ERRPTR;
1172                         break;
1173                 }
1174                 
1175                 if( !op1 || !op2 ) {
1176                         AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
1177                         if(op1) Object_Dereference(op1);
1178                         if(op2) Object_Dereference(op2);
1179                         ret = SpiderScript_CreateInteger( !op1 && !op2 );
1180                         break;
1181                 }
1182                 
1183                 // Convert types
1184                 if( op1->Type != op2->Type ) {
1185                         // If dynamically typed, convert op2 to op1's type
1186                         if(Block->Script->Variant->bImplicitCasts)
1187                         {
1188                                 tmpobj = op2;
1189                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
1190                                 Object_Dereference(tmpobj);
1191                                 if(op2 == ERRPTR) {
1192                                         Object_Dereference(op1);
1193                                         return ERRPTR;
1194                                 }
1195                         }
1196                         // If statically typed, this should never happen, but catch it anyway
1197                         else {
1198                                 AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
1199                                         op1->Type, op2->Type);
1200                                 ret = ERRPTR;
1201                                 break;
1202                         }
1203                 }
1204                 // Do operation
1205                 switch(op1->Type)
1206                 {
1207                 // - String Compare (does a strcmp, well memcmp)
1208                 case SS_DATATYPE_STRING:
1209                         // Call memcmp to do most of the work
1210                         cmp = memcmp(
1211                                 op1->String.Data, op2->String.Data,
1212                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
1213                                 );
1214                         // Handle reaching the end of the string
1215                         if( cmp == 0 ) {
1216                                 if( op1->String.Length == op2->String.Length )
1217                                         cmp = 0;
1218                                 else if( op1->String.Length < op2->String.Length )
1219                                         cmp = 1;
1220                                 else
1221                                         cmp = -1;
1222                         }
1223                         break;
1224                 
1225                 // - Integer Comparisons
1226                 case SS_DATATYPE_INTEGER:
1227                         if( op1->Integer == op2->Integer )
1228                                 cmp = 0;
1229                         else if( op1->Integer < op2->Integer )
1230                                 cmp = -1;
1231                         else
1232                                 cmp = 1;
1233                         break;
1234                 // - Real Number Comparisons
1235                 case SS_DATATYPE_REAL:
1236                         cmp = (op1->Real - op2->Real) / op2->Real * 10000;      // < 0.1% difference is equality
1237                         break;
1238                 default:
1239                         AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
1240                         ret = ERRPTR;
1241                         break;
1242                 }
1243                 
1244                 // Free intermediate objects
1245                 Object_Dereference(op1);
1246                 Object_Dereference(op2);
1247                 
1248                 // Error check
1249                 if( ret == ERRPTR )
1250                         break;
1251                 
1252                 // Create return
1253                 switch(Node->Type)
1254                 {
1255                 case NODETYPE_EQUALS:   ret = SpiderScript_CreateInteger(cmp == 0);     break;
1256                 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0);      break;
1257                 case NODETYPE_GREATERTHAN:      ret = SpiderScript_CreateInteger(cmp > 0);      break;
1258                 case NODETYPE_LESSTHANEQUAL:    ret = SpiderScript_CreateInteger(cmp <= 0);     break;
1259                 case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0);     break;
1260                 default:
1261                         AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
1262                         ret = ERRPTR;
1263                         break;
1264                 }
1265                 break;
1266         
1267         // General Unary Operations
1268         case NODETYPE_BWNOT:    // Bitwise NOT (~)
1269         case NODETYPE_NEGATE:   // Negation (-)
1270                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
1271                 if(op1 == ERRPTR)       return ERRPTR;
1272                 ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
1273                 Object_Dereference(op1);
1274                 break;
1275         
1276         // General Binary Operations
1277         case NODETYPE_ADD:
1278         case NODETYPE_SUBTRACT:
1279         case NODETYPE_MULTIPLY:
1280         case NODETYPE_DIVIDE:
1281         case NODETYPE_MODULO:
1282         case NODETYPE_BWAND:
1283         case NODETYPE_BWOR:
1284         case NODETYPE_BWXOR:
1285         case NODETYPE_BITSHIFTLEFT:
1286         case NODETYPE_BITSHIFTRIGHT:
1287         case NODETYPE_BITROTATELEFT:
1288                 // Get operands
1289                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
1290                 if(op1 == ERRPTR)       return ERRPTR;
1291                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
1292                 if(op2 == ERRPTR) {
1293                         Object_Dereference(op1);
1294                         return ERRPTR;
1295                 }
1296                 
1297                 ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
1298                 
1299                 // Free intermediate objects
1300                 Object_Dereference(op1);
1301                 Object_Dereference(op2);
1302                 break;
1303         
1304         //default:
1305         //      ret = NULL;
1306         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
1307         //      break;
1308         }
1309 _return:
1310         // Reset namespace when no longer needed
1311         if( Node->Type != NODETYPE_SCOPE )
1312                 Block->CurNamespace = NULL;
1313
1314         #if TRACE_NODE_RETURNS
1315         if(ret && ret != ERRPTR) {
1316                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
1317         }
1318         else {
1319                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
1320         }
1321         #endif
1322
1323         return ret;
1324 }
1325
1326 tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value)
1327 {
1328         tSpiderValue    *ret;
1329         #if 0
1330         if( Value->Type == SS_DATATYPE_OBJECT )
1331         {
1332                 const char      *fcnname;
1333                 switch(Operation)
1334                 {
1335                 case NODETYPE_NEGATE:   fcnname = "-ve";        break;
1336                 case NODETYPE_BWNOT:    fcnname = "~";  break;
1337                 default:        fcnname = NULL; break;
1338                 }
1339                 
1340                 if( fcnname )
1341                 {
1342                         ret = Object_ExecuteMethod(Value->Object, fcnname, );
1343                         if( ret != ERRPTR )
1344                                 return ret;
1345                         // Fall through and try casting (which will usually fail)
1346                 }
1347         }
1348         #endif
1349         switch(Value->Type)
1350         {
1351         // Integer Operations
1352         case SS_DATATYPE_INTEGER:
1353                 switch(Operation)
1354                 {
1355                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Integer );    break;
1356                 case NODETYPE_BWNOT:    ret = SpiderScript_CreateInteger( ~Value->Integer );    break;
1357                 default:
1358                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
1359                         ret = ERRPTR;
1360                         break;
1361                 }
1362                 break;
1363         // Real number Operations
1364         case SS_DATATYPE_REAL:
1365                 switch(Operation)
1366                 {
1367                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Real );       break;
1368                 default:
1369                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
1370                         ret = ERRPTR;
1371                         break;
1372                 }
1373                 break;
1374         
1375         default:
1376                 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
1377                 ret = ERRPTR;
1378                 break;
1379         }
1380         
1381         return ret;
1382 }
1383
1384 tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
1385 {
1386         tSpiderValue    *preCastValue = Right;
1387         tSpiderValue    *ret;
1388         
1389         // Convert types
1390         if( Left && Right && Left->Type != Right->Type )
1391         {
1392                 #if 0
1393                 // Object types
1394                 // - Operator overload functions
1395                 if( Left->Type == SS_DATATYPE_OBJECT )
1396                 {
1397                         const char      *fcnname;
1398                         switch(Operation)
1399                         {
1400                         case NODETYPE_ADD:      fcnname = "+";  break;
1401                         case NODETYPE_SUBTRACT: fcnname = "-";  break;
1402                         case NODETYPE_MULTIPLY: fcnname = "*";  break;
1403                         case NODETYPE_DIVIDE:   fcnname = "/";  break;
1404                         case NODETYPE_MODULO:   fcnname = "%";  break;
1405                         case NODETYPE_BWAND:    fcnname = "&";  break;
1406                         case NODETYPE_BWOR:     fcnname = "|";  break;
1407                         case NODETYPE_BWXOR:    fcnname = "^";  break;
1408                         case NODETYPE_BITSHIFTLEFT:     fcnname = "<<"; break;
1409                         case NODETYPE_BITSHIFTRIGHT:fcnname = ">>";     break;
1410                         case NODETYPE_BITROTATELEFT:fcnname = "<<<";    break;
1411                         default:        fcnname = NULL; break;
1412                         }
1413                         
1414                         if( fcnname )
1415                         {
1416                                 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
1417                                 if( ret != ERRPTR )
1418                                         return ret;
1419                                 // Fall through and try casting (which will usually fail)
1420                         }
1421                 }
1422                 #endif
1423                 
1424                 // If implicit casts are allowed, convert Right to Left's type
1425                 if(Block->Script->Variant->bImplicitCasts)
1426                 {
1427                         Right = SpiderScript_CastValueTo(Left->Type, Right);
1428                         if(Right == ERRPTR)
1429                                 return ERRPTR;
1430                 }
1431                 // If statically typed, this should never happen, but catch it anyway
1432                 else {
1433                         AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
1434                         return ERRPTR;
1435                 }
1436         }
1437         
1438         // NULL Check
1439         if( Left == NULL || Right == NULL ) {
1440                 if(Right && Right != preCastValue)      free(Right);
1441                 return NULL;
1442         }
1443         
1444         // Do operation
1445         switch(Left->Type)
1446         {
1447         // String Concatenation
1448         case SS_DATATYPE_STRING:
1449                 switch(Operation)
1450                 {
1451                 case NODETYPE_ADD:      // Concatenate
1452                         ret = Object_StringConcat(Left, Right);
1453                         break;
1454                 default:
1455                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
1456                         ret = ERRPTR;
1457                         break;
1458                 }
1459                 break;
1460         // Integer Operations
1461         case SS_DATATYPE_INTEGER:
1462                 switch(Operation)
1463                 {
1464                 case NODETYPE_ADD:      ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer );     break;
1465                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer );     break;
1466                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer );     break;
1467                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer );     break;
1468                 case NODETYPE_MODULO:   ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer );     break;
1469                 case NODETYPE_BWAND:    ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer );     break;
1470                 case NODETYPE_BWOR:     ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer );     break;
1471                 case NODETYPE_BWXOR:    ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer );     break;
1472                 case NODETYPE_BITSHIFTLEFT:     ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer );    break;
1473                 case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer );        break;
1474                 case NODETYPE_BITROTATELEFT:
1475                         ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) );
1476                         break;
1477                 default:
1478                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
1479                         ret = ERRPTR;
1480                         break;
1481                 }
1482                 break;
1483         
1484         // Real Numbers
1485         case SS_DATATYPE_REAL:
1486                 switch(Operation)
1487                 {
1488                 case NODETYPE_ADD:      ret = SpiderScript_CreateReal( Left->Real + Right->Real );      break;
1489                 case NODETYPE_SUBTRACT: ret = SpiderScript_CreateReal( Left->Real - Right->Real );      break;
1490                 case NODETYPE_MULTIPLY: ret = SpiderScript_CreateReal( Left->Real * Right->Real );      break;
1491                 case NODETYPE_DIVIDE:   ret = SpiderScript_CreateReal( Left->Real / Right->Real );      break;
1492                 default:
1493                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
1494                         ret = ERRPTR;
1495                         break;
1496                 }
1497                 break;
1498         
1499         default:
1500                 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
1501                 ret = ERRPTR;
1502                 break;
1503         }
1504         
1505         if(Right && Right != preCastValue)      free(Right);
1506         
1507         return ret;
1508 }
1509
1510 /**
1511  * \brief Define a variable
1512  * \param Block Current block state
1513  * \param Type  Type of the variable
1514  * \param Name  Name of the variable
1515  * \return Boolean Failure
1516  */
1517 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
1518 {
1519         tAST_Variable   *var, *prev = NULL;
1520         
1521         for( var = Block->FirstVar; var; prev = var, var = var->Next )
1522         {
1523                 if( strcmp(var->Name, Name) == 0 ) {
1524                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
1525                         return ERRPTR;
1526                 }
1527         }
1528         
1529         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1530         var->Next = NULL;
1531         var->Type = Type;
1532         var->Object = Value;
1533         if(Value)       Object_Reference(Value);
1534         strcpy(var->Name, Name);
1535         
1536         if(prev)        prev->Next = var;
1537         else    Block->FirstVar = var;
1538         
1539         //printf("Defined variable %s (%i)\n", Name, Type);
1540         
1541         return var;
1542 }
1543
1544 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1545 {       
1546         tAST_Variable   *var = NULL;
1547         
1548         // Speed hack
1549         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1550                 var = VarNode->ValueCache;
1551                 #if TRACE_VAR_LOOKUPS
1552                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1553                         VarNode->Variable.Name, var,
1554                         VarNode->BlockState, VarNode->BlockIdent
1555                         );
1556                 #endif
1557         }
1558         else
1559         {
1560                 tAST_BlockState *bs;
1561                 for( bs = Block; bs; bs = bs->Parent )
1562                 {
1563                         for( var = bs->FirstVar; var; var = var->Next )
1564                         {
1565                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1566                                         break;
1567                         }
1568                         if(var) break;
1569                 }
1570                 
1571                 if( !var )
1572                 {
1573                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1574                                 // Define variable
1575                                 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1576                         }
1577                         else
1578                         {
1579                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1580                                 return NULL;
1581                         }
1582                 }
1583                 
1584                 #if TRACE_VAR_LOOKUPS
1585                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1586                         VarNode->Variable.Name, var,
1587                         Block, Block->Ident);
1588                 #endif
1589                 
1590                 VarNode->ValueCache = var;
1591                 VarNode->BlockState = Block;
1592                 VarNode->BlockIdent = Block->Ident;
1593         }
1594         
1595         return var;
1596 }
1597
1598 /**
1599  * \brief Set the value of a variable
1600  * \return Boolean Failure
1601  */
1602 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1603 {
1604         tAST_Variable   *var = Variable_Lookup(Block, VarNode, Value->Type);
1605         
1606         if( !var )      return -1;
1607         
1608         if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1609         {
1610                 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1611                         VarNode->Variable.Name);
1612                 return -2;
1613         }
1614
1615 //      printf("Assign %p to '%s'\n", Value, var->Name);
1616         Object_Reference(Value);
1617         Object_Dereference(var->Object);
1618         var->Object = Value;
1619         return 0;
1620 }
1621
1622 /**
1623  * \brief Get the value of a variable
1624  */
1625 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1626 {
1627         tAST_Variable   *var = Variable_Lookup(Block, VarNode, 0);
1628         
1629         if( !var )      return ERRPTR;
1630         
1631         Object_Reference(var->Object);
1632         return var->Object;
1633 }
1634
1635 /**
1636  * \brief Destorys a variable
1637  */
1638 void Variable_Destroy(tAST_Variable *Variable)
1639 {
1640 //      printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1641         Object_Dereference(Variable->Object);
1642         free(Variable);
1643 }
1644
1645 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
1646 {
1647         va_list args;
1648         
1649         if(Node) {
1650                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1651         }
1652         fprintf(stderr, "%s: ", Type);
1653         va_start(args, Format);
1654         vfprintf(stderr, Format, args);
1655         va_end(args);
1656         fprintf(stderr, "\n");
1657 }
1658 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
1659 {
1660         va_list args;
1661         
1662         if(Node) {
1663                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
1664         }
1665         fprintf(stderr, "error: ");
1666         va_start(args, Format);
1667         vfprintf(stderr, Format, args);
1668         va_end(args);
1669         fprintf(stderr, "\n");
1670 }

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