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

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