4 * AST to Bytecode Conversion
12 #include "bytecode_gen.h"
13 #include "bytecode_ops.h"
15 #define TRACE_VAR_LOOKUPS 0
16 #define TRACE_NODE_RETURNS 0
17 #define MAX_NAMESPACE_DEPTH 10
20 extern tSpiderFunction *gpExports_First;
23 typedef struct sAST_BlockInfo
25 struct sAST_BlockInfo *Parent;
32 const char *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
37 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
39 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
40 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
41 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
43 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
44 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
47 // int giNextBlockIdent = 1;
50 int SpiderScript_BytecodeScript(tSpiderScript *Script)
52 tScript_Function *fcn;
53 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
55 if( Bytecode_ConvertFunction(fcn) == 0 )
62 * \brief Convert a function into bytecode
64 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
67 tAST_BlockInfo bi = {0};
69 // TODO: Return BCFcn instead?
70 if(Fcn->BCFcn) return Fcn->BCFcn;
72 ret = Bytecode_CreateFunction(Fcn);
76 if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
78 Bytecode_DeleteFunction(ret);
82 Bytecode_AppendConstInt(ret, 0); // TODO: NULL
83 Bytecode_AppendReturn(ret);
89 // Indepotent operation
90 #define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
91 if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
92 Bytecode_AppendDelete(Block->Handle);\
96 * \brief Convert a node into bytecode
97 * \param Block Execution context
98 * \param Node Node to execute
100 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
105 int bAddedValue = 1; // Used to tell if the value needs to be deleted
116 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
118 tAST_BlockInfo blockInfo = {0};
119 blockInfo.Parent = Block;
120 blockInfo.Handle = Block->Handle;
121 // Loop over all nodes, or until the return value is set
122 for(node = Node->Block.FirstChild;
124 node = node->NextSibling )
126 AST_ConvertNode(Block, node, 0);
129 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
133 case NODETYPE_ASSIGN:
134 // TODO: Support assigning to object attributes
135 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
136 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
140 // Perform assignment operation
141 if( Node->Assign.Operation != NODETYPE_NOP )
144 ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
146 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
148 switch(Node->Assign.Operation)
150 // General Binary Operations
151 case NODETYPE_ADD: op = BC_OP_ADD; break;
152 case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
153 case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
154 case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
155 case NODETYPE_MODULO: op = BC_OP_MODULO; break;
156 case NODETYPE_BWAND: op = BC_OP_BITAND; break;
157 case NODETYPE_BWOR: op = BC_OP_BITOR; break;
158 case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
159 case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
160 case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
161 case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
164 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
167 printf("assign, op = %i\n", op);
168 Bytecode_AppendBinOp(Block->Handle, op);
172 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
177 Bytecode_AppendDuplicate(Block->Handle);
178 // Set the variable value
179 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
182 // Post increment/decrement
183 case NODETYPE_POSTINC:
184 case NODETYPE_POSTDEC:
185 // TODO: Support assigning to object attributes
186 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
187 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
191 // Save original value if requested
193 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
197 Bytecode_AppendConstInt(Block->Handle, 1);
199 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
202 if( Node->Type == NODETYPE_POSTDEC )
203 Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
205 Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
209 ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
211 // Doesn't push unless needed
215 case NODETYPE_METHODCALL:
216 case NODETYPE_FUNCTIONCALL:
217 case NODETYPE_CREATEOBJECT: {
220 // Put the object earlier on the stack to the arguments (for exec)
221 if( Node->Type == NODETYPE_METHODCALL ) {
222 ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
226 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
228 ret = AST_ConvertNode(Block, node, 1);
234 if( Node->Type == NODETYPE_METHODCALL )
236 // TODO: Sanity check stack top
237 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
243 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
244 newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
245 newnamelen += strlen(Node->FunctionCall.Name) + 1;
246 manglename = alloca(newnamelen);
248 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
250 strcat(manglename, Block->CurNamespaceStack[i]);
251 pos = strlen(manglename);
252 manglename[pos] = BC_NS_SEPARATOR;
253 manglename[pos+1] = '\0';
255 strcat(manglename, Node->FunctionCall.Name);
257 if( Node->Type == NODETYPE_CREATEOBJECT )
259 // TODO: Sanity check stack top
260 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
264 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
267 CHECK_IF_NEEDED(0); // Don't warn
268 // TODO: Implement warn_unused_ret
274 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
277 if_end = Bytecode_AllocateLabel(Block->Handle);
279 if( Node->If.False->Type != NODETYPE_NOP )
281 int if_true = Bytecode_AllocateLabel(Block->Handle);
283 Bytecode_AppendCondJump(Block->Handle, if_true);
286 ret = AST_ConvertNode(Block, Node->If.False, 0);
288 Bytecode_AppendJump(Block->Handle, if_end);
289 Bytecode_SetLabel(Block->Handle, if_true);
293 Bytecode_AppendCondJumpNot(Block->Handle, if_end);
297 ret = AST_ConvertNode(Block, Node->If.True, 0);
301 Bytecode_SetLabel(Block->Handle, if_end);
305 case NODETYPE_LOOP: {
306 int loop_start, loop_end;
307 int saved_break, saved_continue;
308 const char *saved_tag;
311 ret = AST_ConvertNode(Block, Node->For.Init, 0);
314 loop_start = Bytecode_AllocateLabel(Block->Handle);
315 loop_end = Bytecode_AllocateLabel(Block->Handle);
317 saved_break = Block->BreakTarget;
318 saved_continue = Block->ContinueTarget;
319 saved_tag = Block->Tag;
320 Block->BreakTarget = loop_end;
321 Block->ContinueTarget = loop_end;
322 Block->Tag = Node->For.Tag;
324 Bytecode_SetLabel(Block->Handle, loop_start);
326 // Check initial condition
327 if( !Node->For.bCheckAfter )
329 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
331 Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
332 Bytecode_AppendCondJump(Block->Handle, loop_end);
336 ret = AST_ConvertNode(Block, Node->For.Code, 0);
340 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
344 if( Node->For.bCheckAfter )
346 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
348 Bytecode_AppendCondJump(Block->Handle, loop_start);
352 Bytecode_AppendJump(Block->Handle, loop_start);
355 Bytecode_SetLabel(Block->Handle, loop_end);
357 Block->BreakTarget = saved_break;
358 Block->ContinueTarget = saved_continue;
359 Block->Tag = saved_tag;
363 case NODETYPE_RETURN:
364 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
366 Bytecode_AppendReturn(Block->Handle);
370 case NODETYPE_CONTINUE: {
371 tAST_BlockInfo *bi = Block;
372 if( Node->Variable.Name[0] ) {
373 while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent;
376 // TODO: Check if BreakTarget/ContinueTarget are valid
377 if( Node->Type == NODETYPE_BREAK )
378 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
380 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
384 case NODETYPE_DEFVAR:
385 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
388 if( Node->DefVar.InitialValue )
390 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
392 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
398 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
399 if( i == MAX_NAMESPACE_DEPTH ) {
400 AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
403 Block->CurNamespaceStack[i] = Node->Scope.Name;
404 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
405 Block->CurNamespaceStack[i] = NULL;
406 CHECK_IF_NEEDED(0); // No warning?
407 // TODO: Will this collide with _CALLFUNCTION etc?
411 case NODETYPE_VARIABLE:
412 ret = BC_Variable_GetValue( Block, Node );
416 // Element of an Object
417 case NODETYPE_ELEMENT:
418 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
421 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
425 // Cast a value to another
427 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
429 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
433 // Index into an array
435 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array
437 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset
440 Bytecode_AppendIndex(Block->Handle);
444 // TODO: Implement runtime constants
445 case NODETYPE_CONSTANT:
446 // TODO: Scan namespace for constant name
447 AST_RuntimeError(Node, "TODO - Runtime Constants");
452 case NODETYPE_STRING:
453 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
456 case NODETYPE_INTEGER:
457 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
461 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
465 // --- Operations ---
466 // Boolean Operations
467 case NODETYPE_LOGICALNOT: // Logical NOT (!)
468 if(!op) op = BC_OP_LOGICNOT;
469 case NODETYPE_BWNOT: // Bitwise NOT (~)
470 if(!op) op = BC_OP_BITNOT;
471 case NODETYPE_NEGATE: // Negation (-)
472 if(!op) op = BC_OP_NEG;
473 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
475 Bytecode_AppendUniOp(Block->Handle, op);
480 case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
481 case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR;
482 case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR;
484 case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
485 case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
486 case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN;
487 case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL;
488 case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
489 // General Binary Operations
490 case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
491 case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
492 case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
493 case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
494 case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
495 case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
496 case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
497 case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
498 case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
499 case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
500 case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
501 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
503 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
506 Bytecode_AppendBinOp(Block->Handle, op);
512 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
516 #if TRACE_NODE_RETURNS
517 if(ret && ret != ERRPTR) {
518 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
521 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
529 * \brief Define a variable
530 * \param Block Current block state
531 * \param Type Type of the variable
532 * \param Name Name of the variable
533 * \return Boolean Failure
535 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
538 tAST_Variable *var, *prev = NULL;
540 for( var = Block->FirstVar; var; prev = var, var = var->Next )
542 if( strcmp(var->Name, Name) == 0 ) {
543 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
548 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
551 strcpy(var->Name, Name);
553 if(prev) prev->Next = var;
554 else Block->FirstVar = var;
558 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
563 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
566 tAST_Variable *var = NULL;
569 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
570 var = VarNode->ValueCache;
571 #if TRACE_VAR_LOOKUPS
572 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
573 VarNode->Variable.Name, var,
574 VarNode->BlockState, VarNode->BlockIdent
581 for( bs = Block; bs; bs = bs->Parent )
583 for( var = bs->FirstVar; var; var = var->Next )
585 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
593 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
595 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
599 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
604 #if TRACE_VAR_LOOKUPS
605 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
606 VarNode->Variable.Name, var,
607 Block, Block->Ident);
610 VarNode->ValueCache = var;
611 VarNode->BlockState = Block;
612 VarNode->BlockIdent = Block->Ident;
622 * \brief Set the value of a variable
623 * \return Boolean Failure
625 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
629 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
634 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
639 * \brief Get the value of a variable
641 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
645 var = BC_Variable_Lookup(Block, VarNode, 0);
648 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
653 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
658 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
660 fprintf(stderr, "%s: ", Type);
661 va_start(args, Format);
662 vfprintf(stderr, Format, args);
664 fprintf(stderr, "\n");
666 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
671 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
673 fprintf(stderr, "error: ");
674 va_start(args, Format);
675 vfprintf(stderr, Format, args);
677 fprintf(stderr, "\n");