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

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