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

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