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

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