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

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