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

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