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

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