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

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