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);
38 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode);
40 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
41 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
42 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
44 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
45 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
48 // int giNextBlockIdent = 1;
51 int SpiderScript_BytecodeScript(tSpiderScript *Script)
53 tScript_Function *fcn;
54 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
56 if( Bytecode_ConvertFunction(fcn) == 0 )
63 * \brief Convert a function into bytecode
65 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
68 tAST_BlockInfo bi = {0};
70 // TODO: Return BCFcn instead?
71 if(Fcn->BCFcn) return Fcn->BCFcn;
73 ret = Bytecode_CreateFunction(Fcn);
77 if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
79 Bytecode_DeleteFunction(ret);
83 Bytecode_AppendConstInt(ret, 0); // TODO: NULL
84 Bytecode_AppendReturn(ret);
90 // Indepotent operation
91 #define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
92 if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
93 Bytecode_AppendDelete(Block->Handle);\
97 * \brief Convert a node into bytecode
98 * \param Block Execution context
99 * \param Node Node to execute
101 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
106 int bAddedValue = 1; // Used to tell if the value needs to be deleted
117 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
119 tAST_BlockInfo blockInfo = {0};
120 blockInfo.Parent = Block;
121 blockInfo.Handle = Block->Handle;
122 // Loop over all nodes, or until the return value is set
123 for(node = Node->Block.FirstChild;
125 node = node->NextSibling )
127 AST_ConvertNode(Block, node, 0);
130 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
134 case NODETYPE_ASSIGN:
135 // Perform assignment operation
136 if( Node->Assign.Operation != NODETYPE_NOP )
138 ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
140 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
142 switch(Node->Assign.Operation)
144 // General Binary Operations
145 case NODETYPE_ADD: op = BC_OP_ADD; break;
146 case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
147 case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
148 case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
149 case NODETYPE_MODULO: op = BC_OP_MODULO; break;
150 case NODETYPE_BWAND: op = BC_OP_BITAND; break;
151 case NODETYPE_BWOR: op = BC_OP_BITOR; break;
152 case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
153 case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
154 case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
155 case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
158 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
161 // printf("assign, op = %i\n", op);
162 Bytecode_AppendBinOp(Block->Handle, op);
166 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
171 Bytecode_AppendDuplicate(Block->Handle);
173 ret = BC_SaveValue(Block, Node->Assign.Dest);
176 // Post increment/decrement
177 case NODETYPE_POSTINC:
178 case NODETYPE_POSTDEC:
179 // Save original value if requested
181 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
185 Bytecode_AppendConstInt(Block->Handle, 1);
187 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
190 if( Node->Type == NODETYPE_POSTDEC )
191 Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
193 Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
196 ret = BC_SaveValue(Block, Node->UniOp.Value);
200 case NODETYPE_METHODCALL:
201 case NODETYPE_FUNCTIONCALL:
202 case NODETYPE_CREATEOBJECT: {
205 // Put the object earlier on the stack to the arguments (for exec)
206 if( Node->Type == NODETYPE_METHODCALL ) {
207 ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
211 // Push arguments to the stack
212 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
214 ret = AST_ConvertNode(Block, node, 1);
220 if( Node->Type == NODETYPE_METHODCALL )
222 // TODO: Sanity check stack top
223 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
229 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
230 newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
231 newnamelen += strlen(Node->FunctionCall.Name) + 1;
232 manglename = alloca(newnamelen);
234 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
236 strcat(manglename, Block->CurNamespaceStack[i]);
237 pos = strlen(manglename);
238 manglename[pos] = BC_NS_SEPARATOR;
239 manglename[pos+1] = '\0';
241 strcat(manglename, Node->FunctionCall.Name);
243 if( Node->Type == NODETYPE_CREATEOBJECT )
245 // TODO: Sanity check stack top
246 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
250 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
253 CHECK_IF_NEEDED(0); // Don't warn
254 // TODO: Implement warn_unused_ret
260 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
263 if_end = Bytecode_AllocateLabel(Block->Handle);
265 if( Node->If.False->Type != NODETYPE_NOP )
267 int if_true = Bytecode_AllocateLabel(Block->Handle);
269 Bytecode_AppendCondJump(Block->Handle, if_true);
272 ret = AST_ConvertNode(Block, Node->If.False, 0);
274 Bytecode_AppendJump(Block->Handle, if_end);
275 Bytecode_SetLabel(Block->Handle, if_true);
279 Bytecode_AppendCondJumpNot(Block->Handle, if_end);
283 ret = AST_ConvertNode(Block, Node->If.True, 0);
287 Bytecode_SetLabel(Block->Handle, if_end);
291 case NODETYPE_LOOP: {
292 int loop_start, loop_end;
293 int saved_break, saved_continue;
294 const char *saved_tag;
297 ret = AST_ConvertNode(Block, Node->For.Init, 0);
300 loop_start = Bytecode_AllocateLabel(Block->Handle);
301 loop_end = Bytecode_AllocateLabel(Block->Handle);
303 saved_break = Block->BreakTarget;
304 saved_continue = Block->ContinueTarget;
305 saved_tag = Block->Tag;
306 Block->BreakTarget = loop_end;
307 Block->ContinueTarget = loop_end;
308 Block->Tag = Node->For.Tag;
310 Bytecode_SetLabel(Block->Handle, loop_start);
312 // Check initial condition
313 if( !Node->For.bCheckAfter )
315 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
317 Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
318 Bytecode_AppendCondJump(Block->Handle, loop_end);
322 ret = AST_ConvertNode(Block, Node->For.Code, 0);
326 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
330 if( Node->For.bCheckAfter )
332 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
334 Bytecode_AppendCondJump(Block->Handle, loop_start);
338 Bytecode_AppendJump(Block->Handle, loop_start);
341 Bytecode_SetLabel(Block->Handle, loop_end);
343 Block->BreakTarget = saved_break;
344 Block->ContinueTarget = saved_continue;
345 Block->Tag = saved_tag;
349 case NODETYPE_RETURN:
350 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
352 Bytecode_AppendReturn(Block->Handle);
356 case NODETYPE_CONTINUE: {
357 tAST_BlockInfo *bi = Block;
358 if( Node->Variable.Name[0] ) {
359 while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent;
362 // TODO: Check if BreakTarget/ContinueTarget are valid
363 if( Node->Type == NODETYPE_BREAK )
364 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
366 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
370 case NODETYPE_DEFVAR:
371 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
374 if( Node->DefVar.InitialValue )
376 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
378 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
384 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
385 if( i == MAX_NAMESPACE_DEPTH ) {
386 AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
389 Block->CurNamespaceStack[i] = Node->Scope.Name;
390 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
391 Block->CurNamespaceStack[i] = NULL;
392 CHECK_IF_NEEDED(0); // No warning?
393 // TODO: Will this collide with _CALLFUNCTION etc?
397 case NODETYPE_VARIABLE:
398 ret = BC_Variable_GetValue( Block, Node );
402 // Element of an Object
403 case NODETYPE_ELEMENT:
404 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
407 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
411 // Cast a value to another
413 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
415 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
419 // Index into an array
421 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array
423 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset
426 Bytecode_AppendIndex(Block->Handle);
430 // TODO: Implement runtime constants
431 case NODETYPE_CONSTANT:
432 // TODO: Scan namespace for constant name
433 AST_RuntimeError(Node, "TODO - Runtime Constants");
438 case NODETYPE_STRING:
439 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
442 case NODETYPE_INTEGER:
443 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
447 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
451 // --- Operations ---
452 // Boolean Operations
453 case NODETYPE_LOGICALNOT: // Logical NOT (!)
454 if(!op) op = BC_OP_LOGICNOT;
455 case NODETYPE_BWNOT: // Bitwise NOT (~)
456 if(!op) op = BC_OP_BITNOT;
457 case NODETYPE_NEGATE: // Negation (-)
458 if(!op) op = BC_OP_NEG;
459 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
461 Bytecode_AppendUniOp(Block->Handle, op);
466 case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
467 case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR;
468 case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR;
470 case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
471 case NODETYPE_NOTEQUALS: if(!op) op = BC_OP_NOTEQUALS;
472 case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
473 case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN;
474 case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL;
475 case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
476 // General Binary Operations
477 case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
478 case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
479 case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
480 case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
481 case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
482 case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
483 case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
484 case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
485 case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
486 case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
487 case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
488 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
490 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
493 Bytecode_AppendBinOp(Block->Handle, op);
499 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
503 #if TRACE_NODE_RETURNS
504 if(ret && ret != ERRPTR) {
505 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
508 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
515 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
518 switch(DestNode->Type)
521 case NODETYPE_VARIABLE:
522 ret = BC_Variable_SetValue( Block, DestNode );
526 ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1); // Array
528 ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
530 Bytecode_AppendSetIndex( Block->Handle );
533 case NODETYPE_ELEMENT:
534 ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
536 Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
540 // TODO: Support assigning to object attributes
541 AST_RuntimeError(DestNode, "Assignment target is not a LValue");
548 * \brief Define a variable
549 * \param Block Current block state
550 * \param Type Type of the variable
551 * \param Name Name of the variable
552 * \return Boolean Failure
554 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
557 tAST_Variable *var, *prev = NULL;
559 for( var = Block->FirstVar; var; prev = var, var = var->Next )
561 if( strcmp(var->Name, Name) == 0 ) {
562 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
567 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
570 strcpy(var->Name, Name);
572 if(prev) prev->Next = var;
573 else Block->FirstVar = var;
577 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
582 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
585 tAST_Variable *var = NULL;
588 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
589 var = VarNode->ValueCache;
590 #if TRACE_VAR_LOOKUPS
591 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
592 VarNode->Variable.Name, var,
593 VarNode->BlockState, VarNode->BlockIdent
600 for( bs = Block; bs; bs = bs->Parent )
602 for( var = bs->FirstVar; var; var = var->Next )
604 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
612 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
614 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
618 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
623 #if TRACE_VAR_LOOKUPS
624 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
625 VarNode->Variable.Name, var,
626 Block, Block->Ident);
629 VarNode->ValueCache = var;
630 VarNode->BlockState = Block;
631 VarNode->BlockIdent = Block->Ident;
641 * \brief Set the value of a variable
642 * \return Boolean Failure
644 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
648 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
653 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
658 * \brief Get the value of a variable
660 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
664 var = BC_Variable_Lookup(Block, VarNode, 0);
667 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
672 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
677 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
679 fprintf(stderr, "%s: ", Type);
680 va_start(args, Format);
681 vfprintf(stderr, Format, args);
683 fprintf(stderr, "\n");
685 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
690 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
692 fprintf(stderr, "error: ");
693 va_start(args, Format);
694 vfprintf(stderr, Format, args);
696 fprintf(stderr, "\n");