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

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