Usermode/libspiderscript - Cleaning code, made bytecode dump smaller
[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                 // Push arguments to the stack
212                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
213                 {
214                         ret = AST_ConvertNode(Block, node, 1);
215                         if(ret) return ret;
216                         nargs ++;
217                 }
218                 
219                 // Call the function
220                 if( Node->Type == NODETYPE_METHODCALL )
221                 {
222                         // TODO: Sanity check stack top
223                         Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
224                 }
225                 else
226                 {
227                          int    newnamelen = 0;
228                         char    *manglename;
229                         for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; 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 < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; 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                                 
243                         if( Node->Type == NODETYPE_CREATEOBJECT )
244                         {
245                                 // TODO: Sanity check stack top
246                                 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
247                         }
248                         else
249                         {
250                                 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
251                         }
252                 }
253                 CHECK_IF_NEEDED(0);     // Don't warn
254                 // TODO: Implement warn_unused_ret
255                 } break;
256         
257         // Conditional
258         case NODETYPE_IF: {
259                  int    if_end;
260                 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
261                 if(ret) return ret;
262                 
263                 if_end = Bytecode_AllocateLabel(Block->Handle);
264
265                 if( Node->If.False->Type != NODETYPE_NOP )
266                 {
267                          int    if_true = Bytecode_AllocateLabel(Block->Handle);
268                         
269                         Bytecode_AppendCondJump(Block->Handle, if_true);
270         
271                         // False
272                         ret = AST_ConvertNode(Block, Node->If.False, 0);
273                         if(ret) return ret;
274                         Bytecode_AppendJump(Block->Handle, if_end);
275                         Bytecode_SetLabel(Block->Handle, if_true);
276                 }
277                 else
278                 {
279                         Bytecode_AppendCondJumpNot(Block->Handle, if_end);
280                 }
281                 
282                 // True
283                 ret = AST_ConvertNode(Block, Node->If.True, 0);
284                 if(ret) return ret;
285
286                 // End
287                 Bytecode_SetLabel(Block->Handle, if_end);
288                 } break;
289         
290         // Loop
291         case NODETYPE_LOOP: {
292                  int    loop_start, loop_end;
293                  int    saved_break, saved_continue;
294                 const char      *saved_tag;
295
296                 // Initialise
297                 ret = AST_ConvertNode(Block, Node->For.Init, 0);
298                 if(ret) return ret;
299                 
300                 loop_start = Bytecode_AllocateLabel(Block->Handle);
301                 loop_end = Bytecode_AllocateLabel(Block->Handle);
302
303                 saved_break = Block->BreakTarget;
304                 saved_continue = Block->ContinueTarget;
305                 saved_tag = Block->Tag;
306                 Block->BreakTarget = loop_end;
307                 Block->ContinueTarget = loop_end;
308                 Block->Tag = Node->For.Tag;
309
310                 Bytecode_SetLabel(Block->Handle, loop_start);
311
312                 // Check initial condition
313                 if( !Node->For.bCheckAfter )
314                 {
315                         ret = AST_ConvertNode(Block, Node->For.Condition, 1);
316                         if(ret) return ret;
317                         Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
318                         Bytecode_AppendCondJump(Block->Handle, loop_end);
319                 }
320         
321                 // Code
322                 ret = AST_ConvertNode(Block, Node->For.Code, 0);
323                 if(ret) return ret;
324                 
325                 // Increment
326                 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
327                 if(ret) return ret;
328
329                 // Tail check
330                 if( Node->For.bCheckAfter )
331                 {
332                         ret = AST_ConvertNode(Block, Node->For.Condition, 1);
333                         if(ret) return ret;
334                         Bytecode_AppendCondJump(Block->Handle, loop_start);
335                 }
336                 else
337                 {
338                         Bytecode_AppendJump(Block->Handle, loop_start);
339                 }
340
341                 Bytecode_SetLabel(Block->Handle, loop_end);
342
343                 Block->BreakTarget = saved_break;
344                 Block->ContinueTarget = saved_continue;
345                 Block->Tag = saved_tag;
346                 } break;
347         
348         // Return
349         case NODETYPE_RETURN:
350                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
351                 if(ret) return ret;
352                 Bytecode_AppendReturn(Block->Handle);
353                 break;
354         
355         case NODETYPE_BREAK:
356         case NODETYPE_CONTINUE: {
357                 tAST_BlockInfo  *bi = Block;
358                 if( Node->Variable.Name[0] ) {
359                         while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0)  bi = bi->Parent;
360                 }
361                 if( !bi )       return 1;
362                 // TODO: Check if BreakTarget/ContinueTarget are valid
363                 if( Node->Type == NODETYPE_BREAK )
364                         Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
365                 else
366                         Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
367                 } break;
368         
369         // Define a variable
370         case NODETYPE_DEFVAR:
371                 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
372                 if(ret) return ret;
373                 
374                 if( Node->DefVar.InitialValue )
375                 {
376                         ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
377                         if(ret) return ret;
378                         Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
379                 }
380                 break;
381         
382         // Scope
383         case NODETYPE_SCOPE:
384                 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
385                 if( i == MAX_NAMESPACE_DEPTH ) {
386                         AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
387                         return 2;
388                 }
389                 Block->CurNamespaceStack[i] = Node->Scope.Name;
390                 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
391                 Block->CurNamespaceStack[i] = NULL;
392                 CHECK_IF_NEEDED(0);     // No warning?
393                 // TODO: Will this collide with _CALLFUNCTION etc?
394                 break;
395         
396         // Variable
397         case NODETYPE_VARIABLE:
398                 ret = BC_Variable_GetValue( Block, Node );
399                 CHECK_IF_NEEDED(1);
400                 break;
401         
402         // Element of an Object
403         case NODETYPE_ELEMENT:
404                 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
405                 if(ret) return ret;
406
407                 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
408                 CHECK_IF_NEEDED(1);
409                 break;
410
411         // Cast a value to another
412         case NODETYPE_CAST:
413                 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
414                 if(ret) return ret;
415                 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
416                 CHECK_IF_NEEDED(1);
417                 break;
418
419         // Index into an array
420         case NODETYPE_INDEX:
421                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);      // Array
422                 if(ret) return ret;
423                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);     // Offset
424                 if(ret) return ret;
425                 
426                 Bytecode_AppendIndex(Block->Handle);
427                 CHECK_IF_NEEDED(1);
428                 break;
429
430         // TODO: Implement runtime constants
431         case NODETYPE_CONSTANT:
432                 // TODO: Scan namespace for constant name
433                 AST_RuntimeError(Node, "TODO - Runtime Constants");
434                 ret = -1;
435                 break;
436         
437         // Constant Values
438         case NODETYPE_STRING:
439                 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
440                 CHECK_IF_NEEDED(1);
441                 break;
442         case NODETYPE_INTEGER:
443                 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
444                 CHECK_IF_NEEDED(1);
445                 break;
446         case NODETYPE_REAL:
447                 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
448                 CHECK_IF_NEEDED(1);
449                 break;
450         
451         // --- Operations ---
452         // Boolean Operations
453         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
454                 if(!op) op = BC_OP_LOGICNOT;
455         case NODETYPE_BWNOT:    // Bitwise NOT (~)
456                 if(!op) op = BC_OP_BITNOT;
457         case NODETYPE_NEGATE:   // Negation (-)
458                 if(!op) op = BC_OP_NEG;
459                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
460                 if(ret) return ret;
461                 Bytecode_AppendUniOp(Block->Handle, op);
462                 CHECK_IF_NEEDED(1);
463                 break;
464
465         // Logic
466         case NODETYPE_LOGICALAND:       if(!op) op = BC_OP_LOGICAND;
467         case NODETYPE_LOGICALOR:        if(!op) op = BC_OP_LOGICOR;
468         case NODETYPE_LOGICALXOR:       if(!op) op = BC_OP_LOGICXOR;
469         // Comparisons
470         case NODETYPE_EQUALS:           if(!op) op = BC_OP_EQUALS;
471         case NODETYPE_NOTEQUALS:        if(!op) op = BC_OP_NOTEQUALS;
472         case NODETYPE_LESSTHAN:         if(!op) op = BC_OP_LESSTHAN;
473         case NODETYPE_GREATERTHAN:      if(!op) op = BC_OP_GREATERTHAN;
474         case NODETYPE_LESSTHANEQUAL:    if(!op) op = BC_OP_LESSTHANOREQUAL;
475         case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
476         // General Binary Operations
477         case NODETYPE_ADD:      if(!op) op = BC_OP_ADD;
478         case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
479         case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
480         case NODETYPE_DIVIDE:   if(!op) op = BC_OP_DIVIDE;
481         case NODETYPE_MODULO:   if(!op) op = BC_OP_MODULO;
482         case NODETYPE_BWAND:    if(!op) op = BC_OP_BITAND;
483         case NODETYPE_BWOR:     if(!op) op = BC_OP_BITOR;
484         case NODETYPE_BWXOR:    if(!op) op = BC_OP_BITXOR;
485         case NODETYPE_BITSHIFTLEFT:     if(!op) op = BC_OP_BITSHIFTLEFT;
486         case NODETYPE_BITSHIFTRIGHT:    if(!op) op = BC_OP_BITSHIFTRIGHT;
487         case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
488                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
489                 if(ret) return ret;
490                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
491                 if(ret) return ret;
492         
493                 Bytecode_AppendBinOp(Block->Handle, op);
494                 CHECK_IF_NEEDED(1);
495                 break;
496         
497         default:
498                 ret = -1;
499                 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
500                 break;
501         }
502
503         #if TRACE_NODE_RETURNS
504         if(ret && ret != ERRPTR) {
505                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
506         }
507         else {
508                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
509         }
510         #endif
511
512         return ret;
513 }
514
515 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
516 {
517          int    ret;
518         switch(DestNode->Type)
519         {
520         // Variable, simple
521         case NODETYPE_VARIABLE:
522                 ret = BC_Variable_SetValue( Block, DestNode );
523                 break;
524         // Array index
525         case NODETYPE_INDEX:
526                 ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1);  // Array
527                 if(ret) return ret;
528                 ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
529                 if(ret) return ret;
530                 Bytecode_AppendSetIndex( Block->Handle );
531                 break;
532         // Object element
533         case NODETYPE_ELEMENT:
534                 ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
535                 if(ret) return ret;
536                 Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
537                 break;
538         // Anything else
539         default:
540                 // TODO: Support assigning to object attributes
541                 AST_RuntimeError(DestNode, "Assignment target is not a LValue");
542                 return -1;
543         }
544         return ret;
545 }
546
547 /**
548  * \brief Define a variable
549  * \param Block Current block state
550  * \param Type  Type of the variable
551  * \param Name  Name of the variable
552  * \return Boolean Failure
553  */
554 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
555 {
556         #if 0
557         tAST_Variable   *var, *prev = NULL;
558         
559         for( var = Block->FirstVar; var; prev = var, var = var->Next )
560         {
561                 if( strcmp(var->Name, Name) == 0 ) {
562                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
563                         return ERRPTR;
564                 }
565         }
566         
567         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
568         var->Next = NULL;
569         var->Type = Type;
570         strcpy(var->Name, Name);
571         
572         if(prev)        prev->Next = var;
573         else    Block->FirstVar = var;
574         
575         return var;
576         #else
577         Bytecode_AppendDefineVar(Block->Handle, Name, Type);
578         return 0;
579         #endif
580 }
581
582 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
583 {
584         #if 0
585         tAST_Variable   *var = NULL;
586         
587         // Speed hack
588         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
589                 var = VarNode->ValueCache;
590                 #if TRACE_VAR_LOOKUPS
591                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
592                         VarNode->Variable.Name, var,
593                         VarNode->BlockState, VarNode->BlockIdent
594                         );
595                 #endif
596         }
597         else
598         {
599                 tAST_BlockInfo  *bs;
600                 for( bs = Block; bs; bs = bs->Parent )
601                 {
602                         for( var = bs->FirstVar; var; var = var->Next )
603                         {
604                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
605                                         break;
606                         }
607                         if(var) break;
608                 }
609                 
610                 if( !var )
611                 {
612                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
613                                 // Define variable
614                                 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
615                         }
616                         else
617                         {
618                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
619                                 return NULL;
620                         }
621                 }
622                 
623                 #if TRACE_VAR_LOOKUPS
624                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
625                         VarNode->Variable.Name, var,
626                         Block, Block->Ident);
627                 #endif
628                 
629                 VarNode->ValueCache = var;
630                 VarNode->BlockState = Block;
631                 VarNode->BlockIdent = Block->Ident;
632         }
633         
634         return var;
635         #else
636         return (void*)1;
637         #endif
638 }
639
640 /**
641  * \brief Set the value of a variable
642  * \return Boolean Failure
643  */
644 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
645 {
646         tAST_Variable   *var;
647         
648         var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
649         if(!var)        return -1;
650
651         // TODO: Check types
652
653         Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
654         return 0;
655 }
656
657 /**
658  * \brief Get the value of a variable
659  */
660 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
661 {
662         tAST_Variable   *var;
663
664         var = BC_Variable_Lookup(Block, VarNode, 0);    
665         if(!var)        return -1;
666         
667         Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
668         return 0;
669 }
670
671 #if 0
672 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
673 {
674         va_list args;
675         
676         if(Node) {
677                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
678         }
679         fprintf(stderr, "%s: ", Type);
680         va_start(args, Format);
681         vfprintf(stderr, Format, args);
682         va_end(args);
683         fprintf(stderr, "\n");
684 }
685 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
686 {
687         va_list args;
688         
689         if(Node) {
690                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
691         }
692         fprintf(stderr, "error: ");
693         va_start(args, Format);
694         vfprintf(stderr, Format, args);
695         va_end(args);
696         fprintf(stderr, "\n");
697 }
698 #endif

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