Usermode/libspiderscript - Fixed namespace scoping applying to function arguments
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / ast_to_bytecode.c
1 /*
2  * SpiderScript Library
3  *
4  * AST to Bytecode Conversion
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 #include "bytecode_gen.h"
13 #include "bytecode_ops.h"
14
15 #define TRACE_VAR_LOOKUPS       0
16 #define TRACE_NODE_RETURNS      0
17 #define MAX_NAMESPACE_DEPTH     10
18
19 // === IMPORTS ===
20 extern tSpiderFunction  *gpExports_First;
21
22 // === TYPES ===
23 typedef struct sAST_BlockInfo
24 {
25         struct sAST_BlockInfo   *Parent;
26         void    *Handle;
27         const char      *Tag;
28
29          int    BreakTarget;
30          int    ContinueTarget;
31
32          int    NamespaceDepth;
33         const char      *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
34 } tAST_BlockInfo;
35
36 // === PROTOTYPES ===
37 // Node Traversal
38  int    AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
39  int    BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode);
40 // Variables
41  int    BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
42  int    BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
43  int    BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
44 // - Errors
45 void    AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
46 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
47
48 // === GLOBALS ===
49 // int  giNextBlockIdent = 1;
50
51 // === CODE ===
52 int SpiderScript_BytecodeScript(tSpiderScript *Script)
53 {
54         tScript_Function        *fcn;
55         for(fcn = Script->Functions; fcn; fcn = fcn->Next)
56         {
57                 if( Bytecode_ConvertFunction(fcn) == 0 )
58                         return -1;
59         }
60         return 0;
61 }
62
63 /**
64  * \brief Convert a function into bytecode
65  */
66 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
67 {
68         tBC_Function    *ret;
69         tAST_BlockInfo bi = {0};
70
71         // TODO: Return BCFcn instead?
72         if(Fcn->BCFcn)  return Fcn->BCFcn;
73         
74         ret = Bytecode_CreateFunction(Fcn);
75         if(!ret)        return NULL;
76         
77         bi.Handle = ret;
78         if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
79         {
80                 Bytecode_DeleteFunction(ret);
81                 return NULL;
82         }
83
84         Bytecode_AppendConstInt(ret, 0);        // TODO: NULL
85         Bytecode_AppendReturn(ret);
86         Fcn->BCFcn = ret;
87
88         return ret;
89 }
90
91 // Indepotent operation
92 #define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
93         if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
94         Bytecode_AppendDelete(Block->Handle);\
95 } } while(0)
96
97 /**
98  * \brief Convert a node into bytecode
99  * \param Block Execution context
100  * \param Node  Node to execute
101  */
102 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
103 {
104         tAST_Node       *node;
105          int    ret = 0;
106          int    i, op = 0;
107          int    bAddedValue = 1;        // Used to tell if the value needs to be deleted
108         
109         switch(Node->Type)
110         {
111         // No Operation
112         case NODETYPE_NOP:
113                 bAddedValue = 0;
114                 break;
115         
116         // Code block
117         case NODETYPE_BLOCK:
118                 Bytecode_AppendEnterContext(Block->Handle);     // Create a new block
119                 {
120                         tAST_BlockInfo  blockInfo = {0};
121                         blockInfo.Parent = Block;
122                         blockInfo.Handle = Block->Handle;
123                         // Loop over all nodes, or until the return value is set
124                         for(node = Node->Block.FirstChild;
125                                 node;
126                                 node = node->NextSibling )
127                         {
128                                 AST_ConvertNode(Block, node, 0);
129                         }
130                 }
131                 Bytecode_AppendLeaveContext(Block->Handle);     // Leave this context
132                 break;
133         
134         // Assignment
135         case NODETYPE_ASSIGN:
136                 // Perform assignment operation
137                 if( Node->Assign.Operation != NODETYPE_NOP )
138                 {
139                         ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
140                         if(ret) return ret;
141                         ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
142                         if(ret) return ret;
143                         switch(Node->Assign.Operation)
144                         {
145                         // General Binary Operations
146                         case NODETYPE_ADD:      op = BC_OP_ADD; break;
147                         case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT;    break;
148                         case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY;    break;
149                         case NODETYPE_DIVIDE:   op = BC_OP_DIVIDE;      break;
150                         case NODETYPE_MODULO:   op = BC_OP_MODULO;      break;
151                         case NODETYPE_BWAND:    op = BC_OP_BITAND;      break;
152                         case NODETYPE_BWOR:     op = BC_OP_BITOR;       break;
153                         case NODETYPE_BWXOR:    op = BC_OP_BITXOR;      break;
154                         case NODETYPE_BITSHIFTLEFT:     op = BC_OP_BITSHIFTLEFT;        break;
155                         case NODETYPE_BITSHIFTRIGHT:    op = BC_OP_BITSHIFTRIGHT;       break;
156                         case NODETYPE_BITROTATELEFT:    op = BC_OP_BITROTATELEFT;       break;
157
158                         default:
159                                 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
160                                 break;
161                         }
162 //                      printf("assign, op = %i\n", op);
163                         Bytecode_AppendBinOp(Block->Handle, op);
164                 }
165                 else
166                 {
167                         ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
168                         if(ret) return ret;
169                 }
170                 
171                 if( bKeepValue )
172                         Bytecode_AppendDuplicate(Block->Handle);
173                 
174                 ret = BC_SaveValue(Block, Node->Assign.Dest);
175                 break;
176         
177         // Post increment/decrement
178         case NODETYPE_POSTINC:
179         case NODETYPE_POSTDEC:
180                 // Save original value if requested
181                 if(bKeepValue) {
182                         ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
183                         if(ret) return ret;
184                 }
185                 
186                 Bytecode_AppendConstInt(Block->Handle, 1);
187                 
188                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
189                 if(ret) return ret;
190
191                 if( Node->Type == NODETYPE_POSTDEC )
192                         Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
193                 else
194                         Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
195                 if(ret) return ret;
196
197                 ret = BC_SaveValue(Block, Node->UniOp.Value);
198                 break;
199
200         // Function Call
201         case NODETYPE_METHODCALL: {
202                  int    nargs = 0;
203                 
204                 ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
205                 if(ret) return ret;
206
207                 // Push arguments to the stack
208                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
209                 {
210                         ret = AST_ConvertNode(Block, node, 1);
211                         if(ret) return ret;
212                         nargs ++;
213                 }
214                 
215                 // TODO: Sanity check stack top?
216                 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
217                 
218                 CHECK_IF_NEEDED(0);     // Don't warn
219                 // TODO: Implement warn_unused_ret
220                 
221                 } break;
222         case NODETYPE_FUNCTIONCALL:
223         case NODETYPE_CREATEOBJECT: {
224                  int    nargs = 0;
225                 
226                 // Get name (mangled into a single string)
227                  int    newnamelen = 0;
228                 char    *manglename;
229                 for( i = 0; i < Block->NamespaceDepth; i ++ )
230                         newnamelen += strlen(Block->CurNamespaceStack[i]) + 1;
231                 newnamelen += strlen(Node->FunctionCall.Name) + 1;
232                 manglename = alloca(newnamelen);
233                 manglename[0] = 0;
234                 for( i = 0; i < Block->NamespaceDepth; i ++ ) {
235                          int    pos;
236                         strcat(manglename, Block->CurNamespaceStack[i]);
237                         pos = strlen(manglename);
238                         manglename[pos] = BC_NS_SEPARATOR;
239                         manglename[pos+1] = '\0';
240                 }
241                 strcat(manglename, Node->FunctionCall.Name);
242                 Block->NamespaceDepth = 0;
243
244                 // Push arguments to the stack
245                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
246                 {
247                         ret = AST_ConvertNode(Block, node, 1);
248                         if(ret) return ret;
249                         nargs ++;
250                 }
251                 
252                 // Call the function
253                 if( Node->Type == NODETYPE_CREATEOBJECT )
254                 {
255                         Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
256                 }
257                 else
258                 {
259                         Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
260                 }
261                 
262                 CHECK_IF_NEEDED(0);     // Don't warn
263                 // TODO: Implement warn_unused_ret
264                 } break;
265         
266         // Conditional
267         case NODETYPE_IF: {
268                  int    if_end;
269                 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
270                 if(ret) return ret;
271                 
272                 if_end = Bytecode_AllocateLabel(Block->Handle);
273
274                 if( Node->If.False->Type != NODETYPE_NOP )
275                 {
276                          int    if_true = Bytecode_AllocateLabel(Block->Handle);
277                         
278                         Bytecode_AppendCondJump(Block->Handle, if_true);
279         
280                         // False
281                         ret = AST_ConvertNode(Block, Node->If.False, 0);
282                         if(ret) return ret;
283                         Bytecode_AppendJump(Block->Handle, if_end);
284                         Bytecode_SetLabel(Block->Handle, if_true);
285                 }
286                 else
287                 {
288                         Bytecode_AppendCondJumpNot(Block->Handle, if_end);
289                 }
290                 
291                 // True
292                 ret = AST_ConvertNode(Block, Node->If.True, 0);
293                 if(ret) return ret;
294
295                 // End
296                 Bytecode_SetLabel(Block->Handle, if_end);
297                 } break;
298         
299         // Loop
300         case NODETYPE_LOOP: {
301                  int    loop_start, loop_end;
302                  int    saved_break, saved_continue;
303                 const char      *saved_tag;
304
305                 // Initialise
306                 ret = AST_ConvertNode(Block, Node->For.Init, 0);
307                 if(ret) return ret;
308                 
309                 loop_start = Bytecode_AllocateLabel(Block->Handle);
310                 loop_end = Bytecode_AllocateLabel(Block->Handle);
311
312                 saved_break = Block->BreakTarget;
313                 saved_continue = Block->ContinueTarget;
314                 saved_tag = Block->Tag;
315                 Block->BreakTarget = loop_end;
316                 Block->ContinueTarget = loop_end;
317                 Block->Tag = Node->For.Tag;
318
319                 Bytecode_SetLabel(Block->Handle, loop_start);
320
321                 // Check initial condition
322                 if( !Node->For.bCheckAfter )
323                 {
324                         ret = AST_ConvertNode(Block, Node->For.Condition, 1);
325                         if(ret) return ret;
326                         Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
327                         Bytecode_AppendCondJump(Block->Handle, loop_end);
328                 }
329         
330                 // Code
331                 ret = AST_ConvertNode(Block, Node->For.Code, 0);
332                 if(ret) return ret;
333                 
334                 // Increment
335                 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
336                 if(ret) return ret;
337
338                 // Tail check
339                 if( Node->For.bCheckAfter )
340                 {
341                         ret = AST_ConvertNode(Block, Node->For.Condition, 1);
342                         if(ret) return ret;
343                         Bytecode_AppendCondJump(Block->Handle, loop_start);
344                 }
345                 else
346                 {
347                         Bytecode_AppendJump(Block->Handle, loop_start);
348                 }
349
350                 Bytecode_SetLabel(Block->Handle, loop_end);
351
352                 Block->BreakTarget = saved_break;
353                 Block->ContinueTarget = saved_continue;
354                 Block->Tag = saved_tag;
355                 } break;
356         
357         // Return
358         case NODETYPE_RETURN:
359                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
360                 if(ret) return ret;
361                 Bytecode_AppendReturn(Block->Handle);
362                 break;
363         
364         case NODETYPE_BREAK:
365         case NODETYPE_CONTINUE: {
366                 tAST_BlockInfo  *bi = Block;
367                 if( Node->Variable.Name[0] ) {
368                         while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0)  bi = bi->Parent;
369                 }
370                 if( !bi )       return 1;
371                 // TODO: Check if BreakTarget/ContinueTarget are valid
372                 if( Node->Type == NODETYPE_BREAK )
373                         Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
374                 else
375                         Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
376                 } break;
377         
378         // Define a variable
379         case NODETYPE_DEFVAR:
380                 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
381                 if(ret) return ret;
382                 
383                 if( Node->DefVar.InitialValue )
384                 {
385                         ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
386                         if(ret) return ret;
387                         Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
388                 }
389                 break;
390         
391         // Scope
392         case NODETYPE_SCOPE:
393                 if( Block->NamespaceDepth == MAX_NAMESPACE_DEPTH ) {
394                         AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", MAX_NAMESPACE_DEPTH);
395                         return 2;
396                 }
397                 Block->CurNamespaceStack[ Block->NamespaceDepth ] = Node->Scope.Name;
398                 Block->NamespaceDepth ++;
399                 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
400                 if( Block->NamespaceDepth != 0 ) {
401                         AST_RuntimeError(Node, "Namespace scope used but no element at the end");
402                 }
403                 CHECK_IF_NEEDED(0);     // No warning?
404                 break;
405         
406         // Variable
407         case NODETYPE_VARIABLE:
408                 ret = BC_Variable_GetValue( Block, Node );
409                 CHECK_IF_NEEDED(1);
410                 break;
411         
412         // Element of an Object
413         case NODETYPE_ELEMENT:
414                 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
415                 if(ret) return ret;
416
417                 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
418                 CHECK_IF_NEEDED(1);
419                 break;
420
421         // Cast a value to another
422         case NODETYPE_CAST:
423                 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
424                 if(ret) return ret;
425                 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
426                 CHECK_IF_NEEDED(1);
427                 break;
428
429         // Index into an array
430         case NODETYPE_INDEX:
431                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);      // Array
432                 if(ret) return ret;
433                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);     // Offset
434                 if(ret) return ret;
435                 
436                 Bytecode_AppendIndex(Block->Handle);
437                 CHECK_IF_NEEDED(1);
438                 break;
439
440         // TODO: Implement runtime constants
441         case NODETYPE_CONSTANT:
442                 // TODO: Scan namespace for constant name
443                 AST_RuntimeError(Node, "TODO - Runtime Constants");
444                 Block->NamespaceDepth = 0;
445                 ret = -1;
446                 break;
447         
448         // Constant Values
449         case NODETYPE_STRING:
450                 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
451                 CHECK_IF_NEEDED(1);
452                 break;
453         case NODETYPE_INTEGER:
454                 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
455                 CHECK_IF_NEEDED(1);
456                 break;
457         case NODETYPE_REAL:
458                 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
459                 CHECK_IF_NEEDED(1);
460                 break;
461         
462         // --- Operations ---
463         // Boolean Operations
464         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
465                 if(!op) op = BC_OP_LOGICNOT;
466         case NODETYPE_BWNOT:    // Bitwise NOT (~)
467                 if(!op) op = BC_OP_BITNOT;
468         case NODETYPE_NEGATE:   // Negation (-)
469                 if(!op) op = BC_OP_NEG;
470                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
471                 if(ret) return ret;
472                 Bytecode_AppendUniOp(Block->Handle, op);
473                 CHECK_IF_NEEDED(1);
474                 break;
475
476         // Logic
477         case NODETYPE_LOGICALAND:       if(!op) op = BC_OP_LOGICAND;
478         case NODETYPE_LOGICALOR:        if(!op) op = BC_OP_LOGICOR;
479         case NODETYPE_LOGICALXOR:       if(!op) op = BC_OP_LOGICXOR;
480         // Comparisons
481         case NODETYPE_EQUALS:           if(!op) op = BC_OP_EQUALS;
482         case NODETYPE_NOTEQUALS:        if(!op) op = BC_OP_NOTEQUALS;
483         case NODETYPE_LESSTHAN:         if(!op) op = BC_OP_LESSTHAN;
484         case NODETYPE_GREATERTHAN:      if(!op) op = BC_OP_GREATERTHAN;
485         case NODETYPE_LESSTHANEQUAL:    if(!op) op = BC_OP_LESSTHANOREQUAL;
486         case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
487         // General Binary Operations
488         case NODETYPE_ADD:      if(!op) op = BC_OP_ADD;
489         case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
490         case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
491         case NODETYPE_DIVIDE:   if(!op) op = BC_OP_DIVIDE;
492         case NODETYPE_MODULO:   if(!op) op = BC_OP_MODULO;
493         case NODETYPE_BWAND:    if(!op) op = BC_OP_BITAND;
494         case NODETYPE_BWOR:     if(!op) op = BC_OP_BITOR;
495         case NODETYPE_BWXOR:    if(!op) op = BC_OP_BITXOR;
496         case NODETYPE_BITSHIFTLEFT:     if(!op) op = BC_OP_BITSHIFTLEFT;
497         case NODETYPE_BITSHIFTRIGHT:    if(!op) op = BC_OP_BITSHIFTRIGHT;
498         case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
499                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
500                 if(ret) return ret;
501                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
502                 if(ret) return ret;
503         
504                 Bytecode_AppendBinOp(Block->Handle, op);
505                 CHECK_IF_NEEDED(1);
506                 break;
507         
508         default:
509                 ret = -1;
510                 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
511                 break;
512         }
513
514         #if TRACE_NODE_RETURNS
515         if(ret && ret != ERRPTR) {
516                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
517         }
518         else {
519                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
520         }
521         #endif
522
523         return ret;
524 }
525
526 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
527 {
528          int    ret;
529         switch(DestNode->Type)
530         {
531         // Variable, simple
532         case NODETYPE_VARIABLE:
533                 ret = BC_Variable_SetValue( Block, DestNode );
534                 break;
535         // Array index
536         case NODETYPE_INDEX:
537                 ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1);  // Array
538                 if(ret) return ret;
539                 ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
540                 if(ret) return ret;
541                 Bytecode_AppendSetIndex( Block->Handle );
542                 break;
543         // Object element
544         case NODETYPE_ELEMENT:
545                 ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
546                 if(ret) return ret;
547                 Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
548                 break;
549         // Anything else
550         default:
551                 // TODO: Support assigning to object attributes
552                 AST_RuntimeError(DestNode, "Assignment target is not a LValue");
553                 return -1;
554         }
555         return ret;
556 }
557
558 /**
559  * \brief Define a variable
560  * \param Block Current block state
561  * \param Type  Type of the variable
562  * \param Name  Name of the variable
563  * \return Boolean Failure
564  */
565 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
566 {
567         #if 0
568         tAST_Variable   *var, *prev = NULL;
569         
570         for( var = Block->FirstVar; var; prev = var, var = var->Next )
571         {
572                 if( strcmp(var->Name, Name) == 0 ) {
573                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
574                         return ERRPTR;
575                 }
576         }
577         
578         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
579         var->Next = NULL;
580         var->Type = Type;
581         strcpy(var->Name, Name);
582         
583         if(prev)        prev->Next = var;
584         else    Block->FirstVar = var;
585         
586         return var;
587         #else
588         Bytecode_AppendDefineVar(Block->Handle, Name, Type);
589         return 0;
590         #endif
591 }
592
593 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
594 {
595         #if 0
596         tAST_Variable   *var = NULL;
597         
598         // Speed hack
599         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
600                 var = VarNode->ValueCache;
601                 #if TRACE_VAR_LOOKUPS
602                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
603                         VarNode->Variable.Name, var,
604                         VarNode->BlockState, VarNode->BlockIdent
605                         );
606                 #endif
607         }
608         else
609         {
610                 tAST_BlockInfo  *bs;
611                 for( bs = Block; bs; bs = bs->Parent )
612                 {
613                         for( var = bs->FirstVar; var; var = var->Next )
614                         {
615                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
616                                         break;
617                         }
618                         if(var) break;
619                 }
620                 
621                 if( !var )
622                 {
623                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
624                                 // Define variable
625                                 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
626                         }
627                         else
628                         {
629                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
630                                 return NULL;
631                         }
632                 }
633                 
634                 #if TRACE_VAR_LOOKUPS
635                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
636                         VarNode->Variable.Name, var,
637                         Block, Block->Ident);
638                 #endif
639                 
640                 VarNode->ValueCache = var;
641                 VarNode->BlockState = Block;
642                 VarNode->BlockIdent = Block->Ident;
643         }
644         
645         return var;
646         #else
647         return (void*)1;
648         #endif
649 }
650
651 /**
652  * \brief Set the value of a variable
653  * \return Boolean Failure
654  */
655 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
656 {
657         tAST_Variable   *var;
658         
659         var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
660         if(!var)        return -1;
661
662         // TODO: Check types
663
664         Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
665         return 0;
666 }
667
668 /**
669  * \brief Get the value of a variable
670  */
671 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
672 {
673         tAST_Variable   *var;
674
675         var = BC_Variable_Lookup(Block, VarNode, 0);    
676         if(!var)        return -1;
677         
678         Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
679         return 0;
680 }
681
682 #if 0
683 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
684 {
685         va_list args;
686         
687         if(Node) {
688                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
689         }
690         fprintf(stderr, "%s: ", Type);
691         va_start(args, Format);
692         vfprintf(stderr, Format, args);
693         va_end(args);
694         fprintf(stderr, "\n");
695 }
696 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
697 {
698         va_list args;
699         
700         if(Node) {
701                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
702         }
703         fprintf(stderr, "error: ");
704         va_start(args, Format);
705         vfprintf(stderr, Format, args);
706         va_end(args);
707         fprintf(stderr, "\n");
708 }
709 #endif

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