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

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