Usermode/SpiderScript - Added language namespace exports
[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                 ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT);
513                 if(ret < 0)     return -1;
514
515                 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
516                 ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
517                 if(ret < 0)     return -1;
518                 CHECK_IF_NEEDED(1);
519                 break;
520
521         // Cast a value to another
522         case NODETYPE_CAST:
523                 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
524                 if(ret) return ret;
525                 ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
526                 if(ret < 0)     return -1;
527                 
528                 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
529                 ret = _StackPush(Block, Node, Node->Cast.DataType);
530                 if(ret < 0)     return -1;
531                 CHECK_IF_NEEDED(1);
532                 break;
533
534         // Index into an array
535         case NODETYPE_INDEX:
536                 // - Array
537                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
538                 if(ret) return ret;
539                 //  > Type check
540                 ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
541                 if(ret < 0)     return -1;
542                 if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) {
543                         AST_RuntimeError(Node, "Type mismatch, Expected an array, got %i",
544                                 ret);
545                         return -2;
546                 }
547                 i = ret;        // Hackily save the datatype
548
549                 // - Offset
550                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
551                 if(ret) return ret;
552                 ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER);
553                 if(ret < 0)     return -1;
554                 
555                 Bytecode_AppendIndex(Block->Handle);
556                 
557                 // Update the array depth
558                 if( i != SS_DATATYPE_ARRAY ) {
559                         i = SS_DOWNARRAY(i);    // Decrease the array level
560                 }
561                 ret = _StackPush(Block, Node, i);
562                 if(ret < 0)     return -1;
563                 
564                 CHECK_IF_NEEDED(1);
565                 break;
566
567         // TODO: Implement runtime constants
568         case NODETYPE_CONSTANT:
569                 // TODO: Scan namespace for constant name
570                 AST_RuntimeError(Node, "TODO - Runtime Constants");
571                 Block->NamespaceDepth = 0;
572                 return -1;
573         
574         // Constant Values
575         case NODETYPE_STRING:
576                 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
577                 ret = _StackPush(Block, Node, SS_DATATYPE_STRING);
578                 if(ret < 0)     return -1;
579                 CHECK_IF_NEEDED(1);
580                 break;
581         case NODETYPE_INTEGER:
582                 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
583                 ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER);
584                 if(ret < 0)     return -1;
585                 CHECK_IF_NEEDED(1);
586                 break;
587         case NODETYPE_REAL:
588                 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
589                 ret = _StackPush(Block, Node, SS_DATATYPE_REAL);
590                 if(ret < 0)     return -1;
591                 CHECK_IF_NEEDED(1);
592                 break;
593         case NODETYPE_NULL:
594                 Bytecode_AppendConstNull(Block->Handle);
595                 ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
596                 if(ret < 0)     return -1;
597                 CHECK_IF_NEEDED(1);
598                 break;
599
600         // --- Operations ---
601         // Boolean Operations
602         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
603                 if(!op) op = BC_OP_LOGICNOT;
604         case NODETYPE_BWNOT:    // Bitwise NOT (~)
605                 if(!op) op = BC_OP_BITNOT;
606         case NODETYPE_NEGATE:   // Negation (-)
607                 if(!op) op = BC_OP_NEG;
608                 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
609                 if(ret) return ret;
610                 ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF);   // TODO: Integer/Real/Undef
611                 if(ret < 0)     return -1;
612
613                 Bytecode_AppendUniOp(Block->Handle, op);
614                 ret = _StackPush(Block, Node, ret);     // TODO: Logic = _INTEGER, Neg = No change
615                 if(ret < 0)     return -1;
616                 
617                 CHECK_IF_NEEDED(1);
618                 break;
619
620         // Logic
621         case NODETYPE_LOGICALAND:       if(!op) op = BC_OP_LOGICAND;
622         case NODETYPE_LOGICALOR:        if(!op) op = BC_OP_LOGICOR;
623         case NODETYPE_LOGICALXOR:       if(!op) op = BC_OP_LOGICXOR;
624         // Comparisons
625         case NODETYPE_EQUALS:           if(!op) op = BC_OP_EQUALS;
626         case NODETYPE_NOTEQUALS:        if(!op) op = BC_OP_NOTEQUALS;
627         case NODETYPE_LESSTHAN:         if(!op) op = BC_OP_LESSTHAN;
628         case NODETYPE_GREATERTHAN:      if(!op) op = BC_OP_GREATERTHAN;
629         case NODETYPE_LESSTHANEQUAL:    if(!op) op = BC_OP_LESSTHANOREQUAL;
630         case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
631         // General Binary Operations
632         case NODETYPE_ADD:      if(!op) op = BC_OP_ADD;
633         case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
634         case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
635         case NODETYPE_DIVIDE:   if(!op) op = BC_OP_DIVIDE;
636         case NODETYPE_MODULO:   if(!op) op = BC_OP_MODULO;
637         case NODETYPE_BWAND:    if(!op) op = BC_OP_BITAND;
638         case NODETYPE_BWOR:     if(!op) op = BC_OP_BITOR;
639         case NODETYPE_BWXOR:    if(!op) op = BC_OP_BITXOR;
640         case NODETYPE_BITSHIFTLEFT:     if(!op) op = BC_OP_BITSHIFTLEFT;
641         case NODETYPE_BITSHIFTRIGHT:    if(!op) op = BC_OP_BITSHIFTRIGHT;
642         case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
643                 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
644                 if(ret) return ret;
645                 ret = _StackPop(Block, Node->BinOp.Left, SS_DATATYPE_UNDEF);    // TODO: Integer/Real/Object
646                 if(ret < 0)     return -1;
647         
648                 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
649                 if(ret) return ret;
650                 ret = _StackPop(Block, Node->BinOp.Right, SS_DATATYPE_UNDEF);   // TODO: Integer/Real/Object
651                 if(ret < 0)     return -1;
652                 
653                 Bytecode_AppendBinOp(Block->Handle, op);
654                 _StackPush(Block, Node, ret);
655                 CHECK_IF_NEEDED(1);
656                 break;
657         
658         default:
659                 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
660                 return -1;
661         }
662
663         return 0;
664 }
665
666 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
667 {
668          int    ret, type;
669         switch(DestNode->Type)
670         {
671         // Variable, simple
672         case NODETYPE_VARIABLE:
673                 ret = BC_Variable_SetValue( Block, DestNode );
674                 if(ret) return ret;
675                 break;
676         // Array index
677         case NODETYPE_INDEX:
678                 ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1);  // Array
679                 if(ret) return ret;
680                 ret = _StackPop(Block, DestNode->BinOp.Left, SS_DATATYPE_UNDEF);
681                 if(ret < 0)     return -1;
682                 if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) {
683                         AST_RuntimeError(DestNode, "Type mismatch, Expected an array, got %i",
684                                 ret);
685                         return -2;
686                 }
687                 type = SS_DOWNARRAY(ret);
688                 
689                 ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
690                 if(ret) return ret;
691                 ret = _StackPop(Block, DestNode->BinOp.Right, SS_DATATYPE_INTEGER);
692                 if(ret < 0)     return -1;
693                 
694                 Bytecode_AppendSetIndex( Block->Handle );
695                 _StackPop(Block, DestNode, type);
696                 break;
697         // Object element
698         case NODETYPE_ELEMENT:
699                 ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
700                 if(ret) return ret;
701                 ret = _StackPop(Block, DestNode->Scope.Element, SS_DATATYPE_OBJECT);
702                 if(ret < 0)     return -1;
703                 
704                 Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
705                 break;
706         // Anything else
707         default:
708                 // TODO: Support assigning to object attributes
709                 AST_RuntimeError(DestNode, "Assignment target is not a LValue");
710                 return -1;
711         }
712         return 0;
713 }
714
715 /**
716  * \brief Define a variable
717  * \param Block Current block state
718  * \param Type  Type of the variable
719  * \param Name  Name of the variable
720  * \return Boolean Failure
721  */
722 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
723 {
724         tAST_Variable   *var, *prev = NULL;
725         
726         for( var = Block->FirstVar; var; prev = var, var = var->Next )
727         {
728                 if( strcmp(var->Name, Name) == 0 ) {
729                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
730                         return -1;
731                 }
732         }
733         
734         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
735         var->Next = NULL;
736         var->Type = Type;
737         strcpy(var->Name, Name);
738         
739         if(prev)        prev->Next = var;
740         else    Block->FirstVar = var;
741         
742         Bytecode_AppendDefineVar(Block->Handle, Name, Type);
743         return 0;
744 }
745
746 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
747 {
748         tAST_Variable   *var = NULL;
749         tAST_BlockInfo  *bs;
750         
751         for( bs = Block; bs; bs = bs->Parent )
752         {
753                 for( var = bs->FirstVar; var; var = var->Next )
754                 {
755                         if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
756                                 break;
757                 }
758                 if(var) break;
759         }
760
761         if( !var )
762         {
763 //              if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
764 //                      // Define variable
765 //                      var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
766 //              }
767 //              else
768 //              {
769                         AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
770                         return NULL;
771 //              }
772         }
773                 
774         #if TRACE_VAR_LOOKUPS
775         AST_RuntimeMessage(VarNode, "debug", "Variable lookup of '%s' %p type %i",
776                 VarNode->Variable.Name, var, var->Type);
777         #endif
778         
779         return var;
780 }
781
782 /**
783  * \brief Set the value of a variable
784  * \return Boolean Failure
785  */
786 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
787 {
788         tAST_Variable   *var;
789         
790         // TODO: Implicit definition type
791         var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
792         if(!var)        return -1;
793
794         // TODO: Check types
795
796         _StackPop(Block, VarNode, var->Type);
797         Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
798         return 0;
799 }
800
801 /**
802  * \brief Get the value of a variable
803  */
804 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
805 {
806         tAST_Variable   *var;
807
808         var = BC_Variable_Lookup(Block, VarNode, 0);    
809         if(!var)        return -1;
810         
811         _StackPush(Block, VarNode, var->Type);
812         Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
813         return 0;
814 }
815
816 void BC_Variable_Clear(tAST_BlockInfo *Block)
817 {
818         tAST_Variable   *var;
819         for( var = Block->FirstVar; var; )
820         {
821                 tAST_Variable   *tv = var->Next;
822                 free( var );
823                 var = tv;
824         }
825         Block->FirstVar = NULL;
826 }
827
828 #if 0
829 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
830 {
831         va_list args;
832         
833         if(Node) {
834                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
835         }
836         fprintf(stderr, "%s: ", Type);
837         va_start(args, Format);
838         vfprintf(stderr, Format, args);
839         va_end(args);
840         fprintf(stderr, "\n");
841 }
842 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
843 {
844         va_list args;
845         
846         if(Node) {
847                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
848         }
849         fprintf(stderr, "error: ");
850         va_start(args, Format);
851         vfprintf(stderr, Format, args);
852         va_end(args);
853         fprintf(stderr, "\n");
854 }
855 #endif
856
857 int _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type)
858 {
859         if(Block->StackDepth == MAX_STACK_DEPTH - 1) {
860                 AST_RuntimeError(Node, "BUG - Stack overflow in AST-Bytecode conversion (node=%i)",
861                         Node->Type);
862                 return -1;
863         }
864
865         #if TRACE_TYPE_STACK
866         AST_RuntimeMessage(Node, "_StackPush", "%x - NT%i", Type, Node->Type);
867         #endif
868         Block->Stack[ ++Block->StackDepth ] = Type;
869         return Type;
870 }
871
872 int _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType)
873 {
874         if(Block->StackDepth == 0) {
875                 AST_RuntimeError(Node, "BUG - Stack underflow in AST-Bytecode conversion (node=%i)",
876                         Node->Type);
877                 return -1;
878         }
879         #if TRACE_TYPE_STACK
880         AST_RuntimeMessage(Node, "_StackPop", "%x(?==%x) - NT%i",
881                 Block->Stack[ Block->StackDepth ], WantedType, Node->Type);
882         #endif
883         if(WantedType != SS_DATATYPE_UNDEF && Block->Stack[ Block->StackDepth ] != SS_DATATYPE_UNDEF)
884         {
885                 if( Block->Stack[ Block->StackDepth ] != WantedType ) {
886                         AST_RuntimeError(Node, "AST-Bytecode - Type mismatch (wanted %x got %x)",
887                                 WantedType, Block->Stack[ Block->StackDepth ]);
888                         // TODO: Message?
889                         return -2;
890                 }
891         }
892         return Block->Stack[Block->StackDepth--];
893 }
894

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