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

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