SpiderScript - Cleaning and sorting
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / ast_to_bytecode.c
1 /*
2  * SpiderScript Library
3  *
4  * AST to Bytecode Conversion
5  */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include "common.h"
11 #include "ast.h"
12 #include "bytecode_gen.h"
13 #include "bytecode_ops.h"
14
15 #define TRACE_VAR_LOOKUPS       0
16 #define TRACE_NODE_RETURNS      0
17
18 // === IMPORTS ===
19 extern tSpiderFunction  *gpExports_First;
20
21 // === TYPES ===
22 typedef struct sAST_BlockInfo
23 {
24         struct sAST_BlockInfo   *Parent;
25         void    *Handle;
26         const char      *Tag;
27
28          int    BreakTarget;
29          int    ContinueTarget;
30 } tAST_BlockInfo;
31
32 // === PROTOTYPES ===
33 // Node Traversal
34  int    AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node);
35 // Variables
36  int    BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
37  int    BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
38  int    BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
39 // - Errors
40 void    AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
41 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
42
43 // === GLOBALS ===
44 // int  giNextBlockIdent = 1;
45
46 // === CODE ===
47 int SpiderScript_BytecodeScript(tSpiderScript *Script)
48 {
49         tScript_Function        *fcn;
50         for(fcn = Script->Functions; fcn; fcn = fcn->Next)
51         {
52                 if( Bytecode_ConvertFunction(fcn) == 0 )
53                         return -1;
54         }
55         return 0;
56 }
57
58 /**
59  * \brief Convert a function into bytecode
60  */
61 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
62 {
63         tBC_Function    *ret;
64         tAST_BlockInfo bi = {0};
65
66         // TODO: Return BCFcn instead?
67         if(Fcn->BCFcn)  return Fcn->BCFcn;
68         
69         ret = Bytecode_CreateFunction(Fcn);
70         if(!ret)        return NULL;
71         
72         bi.Handle = ret;
73         if( AST_ConvertNode(&bi, Fcn->ASTFcn) )
74         {
75                 Bytecode_DeleteFunction(ret);
76                 return NULL;
77         }
78
79         Fcn->BCFcn = ret;
80
81         return ret;
82 }
83
84 /**
85  * \brief Convert a node into bytecode
86  * \param Block Execution context
87  * \param Node  Node to execute
88  */
89 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
90 {
91         tAST_Node       *node;
92          int    ret = 0;
93          int    i, op = 0;
94         
95         switch(Node->Type)
96         {
97         // No Operation
98         case NODETYPE_NOP:
99                 break;
100         
101         // Code block
102         case NODETYPE_BLOCK:
103                 Bytecode_AppendEnterContext(Block->Handle);     // Create a new block
104                 {
105                         tAST_BlockInfo  blockInfo;
106                         blockInfo.Parent = Block;
107                         blockInfo.Handle = Block->Handle;
108                         blockInfo.ContinueTarget = 0;
109                         blockInfo.BreakTarget = 0;
110                         // Loop over all nodes, or until the return value is set
111                         for(node = Node->Block.FirstChild;
112                                 node;
113                                 node = node->NextSibling )
114                         {
115                                 AST_ConvertNode(Block, node);
116                         }
117                 }
118                 Bytecode_AppendLeaveContext(Block->Handle);     // Leave this context
119                 break;
120         
121         // Assignment
122         case NODETYPE_ASSIGN:
123                 // TODO: Support assigning to object attributes
124                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
125                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
126                         return -1;
127                 }
128                 ret = AST_ConvertNode(Block, Node->Assign.Value);
129                 if(ret) return ret;
130                 
131                 // Perform assignment operation
132                 if( Node->Assign.Operation != NODETYPE_NOP )
133                 {
134                         
135                         ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
136                         if(ret) return ret;
137                         Bytecode_AppendBinOp(Block->Handle, Node->Assign.Operation);
138                 }
139                 
140                 // Set the variable value
141                 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
142                 break;
143         
144         // Post increment/decrement
145         case NODETYPE_POSTINC:
146         case NODETYPE_POSTDEC:
147                 Bytecode_AppendConstInt(Block->Handle, 1);
148                 
149                 // TODO: Support assigning to object attributes
150                 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
151                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
152                         return -1;
153                 }
154
155                 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
156                 if(ret) return ret;
157
158                 if( Node->Type == NODETYPE_POSTDEC )
159                         Bytecode_AppendBinOp(Block->Handle, NODETYPE_SUBTRACT);
160                 else
161                         Bytecode_AppendBinOp(Block->Handle, NODETYPE_ADD);
162                 if(ret) return ret;
163
164                 ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
165                 if(ret) return ret;
166                 break;
167         
168         // Function Call
169         case NODETYPE_METHODCALL:
170         case NODETYPE_FUNCTIONCALL:
171         case NODETYPE_CREATEOBJECT:
172                 i = 0;
173                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
174                 {
175                         ret = AST_ConvertNode(Block, node);
176                         if(ret) return ret;
177                         i ++;
178                 }
179                 
180                 // Call the function
181                 if( Node->Type == NODETYPE_CREATEOBJECT )
182                 {
183                         // TODO: Sanity check stack top
184                         Bytecode_AppendCreateObj(Block->Handle, Node->FunctionCall.Name, i);
185                 }
186                 else if( Node->Type == NODETYPE_METHODCALL )
187                 {
188                         // TODO: Sanity check stack top
189                         ret = AST_ConvertNode(Block, Node->FunctionCall.Object);
190                         if(ret) return ret;
191                         Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, i);
192                 }
193                 else
194                 {
195                         Bytecode_AppendFunctionCall(Block->Handle, Node->FunctionCall.Name, i);
196                 }
197                 break;
198         
199         // Conditional
200         case NODETYPE_IF: {
201                  int    if_true, if_end;
202                 ret = AST_ConvertNode(Block, Node->If.Condition);
203                 if(ret) return ret;
204                 
205                 if_true = Bytecode_AllocateLabel(Block->Handle);
206                 if_end = Bytecode_AllocateLabel(Block->Handle);
207         
208                 Bytecode_AppendCondJump(Block->Handle, if_true);
209
210                 // False
211                 ret = AST_ConvertNode(Block, Node->If.False);
212                 if(ret) return ret;
213                 Bytecode_AppendJump(Block->Handle, if_end);
214                 
215                 // True
216                 Bytecode_SetLabel(Block->Handle, if_true);
217                 ret = AST_ConvertNode(Block, Node->If.True);
218                 if(ret) return ret;
219
220                 // End
221                 Bytecode_SetLabel(Block->Handle, if_end);
222                 } break;
223         
224         // Loop
225         case NODETYPE_LOOP: {
226                  int    loop_start, loop_end;
227                  int    saved_break, saved_continue;
228                 const char      *saved_tag;
229
230                 // Initialise
231                 ret = AST_ConvertNode(Block, Node->For.Init);
232                 if(ret) return ret;
233                 
234                 loop_start = Bytecode_AllocateLabel(Block->Handle);
235                 loop_end = Bytecode_AllocateLabel(Block->Handle);
236
237                 saved_break = Block->BreakTarget;
238                 saved_continue = Block->ContinueTarget;
239                 saved_tag = Block->Tag;
240                 Block->BreakTarget = loop_end;
241                 Block->ContinueTarget = loop_end;
242                 Block->Tag = Node->For.Tag;
243
244                 Bytecode_SetLabel(Block->Handle, loop_start);
245
246                 // Check initial condition
247                 if( !Node->For.bCheckAfter )
248                 {
249                         ret = AST_ConvertNode(Block, Node->For.Condition);
250                         if(ret) return ret;
251                         Bytecode_AppendUniOp(Block->Handle, NODETYPE_LOGICALNOT);
252                         Bytecode_AppendCondJump(Block->Handle, loop_end);
253                 }
254         
255                 // Code
256                 ret = AST_ConvertNode(Block, Node->For.Code);
257                 if(ret) return ret;
258                 
259                 // Increment
260                 ret = AST_ConvertNode(Block, Node->For.Increment);
261                 if(ret) return ret;
262
263                 // Tail check
264                 if( Node->For.bCheckAfter )
265                 {
266                         ret = AST_ConvertNode(Block, Node->For.Condition);
267                         if(ret) return ret;
268                         Bytecode_AppendCondJump(Block->Handle, loop_start);
269                 }
270
271                 Bytecode_SetLabel(Block->Handle, loop_end);
272
273                 Block->BreakTarget = saved_break;
274                 Block->ContinueTarget = saved_continue;
275                 Block->Tag = saved_tag;
276                 } break;
277         
278         // Return
279         case NODETYPE_RETURN:
280                 ret = AST_ConvertNode(Block, Node->UniOp.Value);
281                 if(ret) return ret;
282                 Bytecode_AppendReturn(Block->Handle);
283                 break;
284         
285         case NODETYPE_BREAK:
286         case NODETYPE_CONTINUE: {
287                 tAST_BlockInfo  *bi = Block;
288                 if( Node->Variable.Name[0] ) {
289                         while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0)  bi = bi->Parent;
290                 }
291                 if( !bi )       return 1;
292                 // TODO: Check if BreakTarget/ContinueTarget are valid
293                 if( Node->Type == NODETYPE_BREAK )
294                         Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
295                 else
296                         Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
297                 } break;
298         
299         // Define a variable
300         case NODETYPE_DEFVAR:
301                 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
302                 if(ret) return ret;
303                 
304                 if( Node->DefVar.InitialValue )
305                 {
306                         ret = AST_ConvertNode(Block, Node->DefVar.InitialValue);
307                         if(ret) return ret;
308                         Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
309                 }
310                 break;
311         
312         // Scope
313         case NODETYPE_SCOPE:
314                 Bytecode_AppendSubNamespace(Block->Handle, Node->Scope.Name);
315                 ret = AST_ConvertNode(Block, Node->Scope.Element);
316                 break;
317         
318         // Variable
319         case NODETYPE_VARIABLE:
320                 ret = BC_Variable_GetValue( Block, Node );
321                 break;
322         
323         // Element of an Object
324         case NODETYPE_ELEMENT:
325                 ret = AST_ConvertNode( Block, Node->Scope.Element );
326                 if(ret) return ret;
327
328                 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
329                 break;
330
331         // Cast a value to another
332         case NODETYPE_CAST:
333                 ret = AST_ConvertNode(Block, Node->Cast.Value);
334                 if(ret) return ret;
335                 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
336                 break;
337
338         // Index into an array
339         case NODETYPE_INDEX:
340                 ret = AST_ConvertNode(Block, Node->BinOp.Left); // Array
341                 if(ret) return ret;
342                 ret = AST_ConvertNode(Block, Node->BinOp.Right);        // Offset
343                 if(ret) return ret;
344                 
345                 Bytecode_AppendIndex(Block->Handle);
346                 break;
347
348         // TODO: Implement runtime constants
349         case NODETYPE_CONSTANT:
350                 // TODO: Scan namespace for constant name
351                 AST_RuntimeError(Node, "TODO - Runtime Constants");
352                 ret = -1;
353                 break;
354         
355         // Constant Values
356         case NODETYPE_STRING:
357                 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
358                 break;
359         case NODETYPE_INTEGER:
360                 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
361                 break;
362         case NODETYPE_REAL:
363                 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Real);
364                 break;
365         
366         // --- Operations ---
367         // Boolean Operations
368         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
369                 if(!op) op = BC_OP_LOGICNOT;
370         case NODETYPE_BWNOT:    // Bitwise NOT (~)
371                 if(!op) op = BC_OP_BITNOT;
372         case NODETYPE_NEGATE:   // Negation (-)
373                 if(!op) op = BC_OP_NEG;
374                 ret = AST_ConvertNode(Block, Node->UniOp.Value);
375                 if(ret) return ret;
376                 Bytecode_AppendUniOp(Block->Handle, op);
377                 break;
378
379         case NODETYPE_LOGICALAND:       // Logical AND (&&)
380                 if(!op) op = BC_OP_LOGICAND;
381         case NODETYPE_LOGICALOR:        // Logical OR (||)
382                 if(!op) op = BC_OP_LOGICOR;
383         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
384                 if(!op) op = BC_OP_LOGICXOR;
385         // Comparisons
386         case NODETYPE_EQUALS:   if(!op) op = BC_OP_EQUALS;
387         case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
388         case NODETYPE_GREATERTHAN:      if(!op) op = BC_OP_GREATERTHAN;
389         case NODETYPE_LESSTHANEQUAL:    if(!op) op = BC_OP_LESSTHANOREQUAL;
390         case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
391         // General Binary Operations
392         case NODETYPE_ADD:      if(!op) op = BC_OP_ADD;
393         case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
394         case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
395         case NODETYPE_DIVIDE:   if(!op) op = BC_OP_DIVIDE;
396         case NODETYPE_MODULO:   if(!op) op = BC_OP_MODULO;
397         case NODETYPE_BWAND:    if(!op) op = BC_OP_BITAND;
398         case NODETYPE_BWOR:     if(!op) op = BC_OP_BITOR;
399         case NODETYPE_BWXOR:    if(!op) op = BC_OP_BITXOR;
400         case NODETYPE_BITSHIFTLEFT:     if(!op) op = BC_OP_BITSHIFTLEFT;
401         case NODETYPE_BITSHIFTRIGHT:    if(!op) op = BC_OP_BITSHIFTRIGHT;
402         case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
403                 ret = AST_ConvertNode(Block, Node->BinOp.Left);
404                 if(ret) return ret;
405                 ret = AST_ConvertNode(Block, Node->BinOp.Right);
406                 if(ret) return ret;
407                 
408                 Bytecode_AppendBinOp(Block->Handle, op);
409                 break;
410         
411         //default:
412         //      ret = NULL;
413         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
414         //      break;
415         }
416
417         #if TRACE_NODE_RETURNS
418         if(ret && ret != ERRPTR) {
419                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
420         }
421         else {
422                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
423         }
424         #endif
425
426         return ret;
427 }
428
429 /**
430  * \brief Define a variable
431  * \param Block Current block state
432  * \param Type  Type of the variable
433  * \param Name  Name of the variable
434  * \return Boolean Failure
435  */
436 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
437 {
438         #if 0
439         tAST_Variable   *var, *prev = NULL;
440         
441         for( var = Block->FirstVar; var; prev = var, var = var->Next )
442         {
443                 if( strcmp(var->Name, Name) == 0 ) {
444                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
445                         return ERRPTR;
446                 }
447         }
448         
449         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
450         var->Next = NULL;
451         var->Type = Type;
452         strcpy(var->Name, Name);
453         
454         if(prev)        prev->Next = var;
455         else    Block->FirstVar = var;
456         
457         return var;
458         #else
459         Bytecode_AppendDefineVar(Block->Handle, Name, Type);
460         return 0;
461         #endif
462 }
463
464 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
465 {
466         #if 0
467         tAST_Variable   *var = NULL;
468         
469         // Speed hack
470         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
471                 var = VarNode->ValueCache;
472                 #if TRACE_VAR_LOOKUPS
473                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
474                         VarNode->Variable.Name, var,
475                         VarNode->BlockState, VarNode->BlockIdent
476                         );
477                 #endif
478         }
479         else
480         {
481                 tAST_BlockInfo  *bs;
482                 for( bs = Block; bs; bs = bs->Parent )
483                 {
484                         for( var = bs->FirstVar; var; var = var->Next )
485                         {
486                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
487                                         break;
488                         }
489                         if(var) break;
490                 }
491                 
492                 if( !var )
493                 {
494                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
495                                 // Define variable
496                                 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
497                         }
498                         else
499                         {
500                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
501                                 return NULL;
502                         }
503                 }
504                 
505                 #if TRACE_VAR_LOOKUPS
506                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
507                         VarNode->Variable.Name, var,
508                         Block, Block->Ident);
509                 #endif
510                 
511                 VarNode->ValueCache = var;
512                 VarNode->BlockState = Block;
513                 VarNode->BlockIdent = Block->Ident;
514         }
515         
516         return var;
517         #else
518         return (void*)1;
519         #endif
520 }
521
522 /**
523  * \brief Set the value of a variable
524  * \return Boolean Failure
525  */
526 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
527 {
528         tAST_Variable   *var;
529         
530         var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
531         if(!var)        return -1;
532
533         // TODO: Check types
534
535         Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
536         return 0;
537 }
538
539 /**
540  * \brief Get the value of a variable
541  */
542 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
543 {
544         tAST_Variable   *var;
545
546         var = BC_Variable_Lookup(Block, VarNode, 0);    
547         if(!var)        return -1;
548         
549         Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
550         return 0;
551 }
552
553 #if 0
554 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
555 {
556         va_list args;
557         
558         if(Node) {
559                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
560         }
561         fprintf(stderr, "%s: ", Type);
562         va_start(args, Format);
563         vfprintf(stderr, Format, args);
564         va_end(args);
565         fprintf(stderr, "\n");
566 }
567 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
568 {
569         va_list args;
570         
571         if(Node) {
572                 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
573         }
574         fprintf(stderr, "error: ");
575         va_start(args, Format);
576         vfprintf(stderr, Format, args);
577         va_end(args);
578         fprintf(stderr, "\n");
579 }
580 #endif

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