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;
33 const char *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
38 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
39 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode);
41 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
42 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
43 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
45 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
46 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
49 // int giNextBlockIdent = 1;
52 int SpiderScript_BytecodeScript(tSpiderScript *Script)
54 tScript_Function *fcn;
55 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
57 if( Bytecode_ConvertFunction(fcn) == 0 )
64 * \brief Convert a function into bytecode
66 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
69 tAST_BlockInfo bi = {0};
71 // TODO: Return BCFcn instead?
72 if(Fcn->BCFcn) return Fcn->BCFcn;
74 ret = Bytecode_CreateFunction(Fcn);
78 if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
80 Bytecode_DeleteFunction(ret);
84 Bytecode_AppendConstInt(ret, 0); // TODO: NULL
85 Bytecode_AppendReturn(ret);
91 // Indepotent operation
92 #define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
93 if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
94 Bytecode_AppendDelete(Block->Handle);\
98 * \brief Convert a node into bytecode
99 * \param Block Execution context
100 * \param Node Node to execute
102 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
107 int bAddedValue = 1; // Used to tell if the value needs to be deleted
118 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
120 tAST_BlockInfo blockInfo = {0};
121 blockInfo.Parent = Block;
122 blockInfo.Handle = Block->Handle;
123 // Loop over all nodes, or until the return value is set
124 for(node = Node->Block.FirstChild;
126 node = node->NextSibling )
128 AST_ConvertNode(Block, node, 0);
131 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
135 case NODETYPE_ASSIGN:
136 // Perform assignment operation
137 if( Node->Assign.Operation != NODETYPE_NOP )
139 ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
141 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
143 switch(Node->Assign.Operation)
145 // General Binary Operations
146 case NODETYPE_ADD: op = BC_OP_ADD; break;
147 case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
148 case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
149 case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
150 case NODETYPE_MODULO: op = BC_OP_MODULO; break;
151 case NODETYPE_BWAND: op = BC_OP_BITAND; break;
152 case NODETYPE_BWOR: op = BC_OP_BITOR; break;
153 case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
154 case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
155 case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
156 case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
159 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
162 // printf("assign, op = %i\n", op);
163 Bytecode_AppendBinOp(Block->Handle, op);
167 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
172 Bytecode_AppendDuplicate(Block->Handle);
174 ret = BC_SaveValue(Block, Node->Assign.Dest);
177 // Post increment/decrement
178 case NODETYPE_POSTINC:
179 case NODETYPE_POSTDEC:
180 // Save original value if requested
182 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
186 Bytecode_AppendConstInt(Block->Handle, 1);
188 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
191 if( Node->Type == NODETYPE_POSTDEC )
192 Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
194 Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
197 ret = BC_SaveValue(Block, Node->UniOp.Value);
201 case NODETYPE_METHODCALL: {
204 ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
207 // Push arguments to the stack
208 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
210 ret = AST_ConvertNode(Block, node, 1);
215 // TODO: Sanity check stack top?
216 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
218 CHECK_IF_NEEDED(0); // Don't warn
219 // TODO: Implement warn_unused_ret
222 case NODETYPE_FUNCTIONCALL:
223 case NODETYPE_CREATEOBJECT: {
226 // Get name (mangled into a single string)
229 for( i = 0; i < Block->NamespaceDepth; i ++ )
230 newnamelen += strlen(Block->CurNamespaceStack[i]) + 1;
231 newnamelen += strlen(Node->FunctionCall.Name) + 1;
232 manglename = alloca(newnamelen);
234 for( i = 0; i < Block->NamespaceDepth; 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);
242 Block->NamespaceDepth = 0;
244 // Push arguments to the stack
245 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
247 ret = AST_ConvertNode(Block, node, 1);
253 if( Node->Type == NODETYPE_CREATEOBJECT )
255 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
259 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
262 CHECK_IF_NEEDED(0); // Don't warn
263 // TODO: Implement warn_unused_ret
269 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
272 if_end = Bytecode_AllocateLabel(Block->Handle);
274 if( Node->If.False->Type != NODETYPE_NOP )
276 int if_true = Bytecode_AllocateLabel(Block->Handle);
278 Bytecode_AppendCondJump(Block->Handle, if_true);
281 ret = AST_ConvertNode(Block, Node->If.False, 0);
283 Bytecode_AppendJump(Block->Handle, if_end);
284 Bytecode_SetLabel(Block->Handle, if_true);
288 Bytecode_AppendCondJumpNot(Block->Handle, if_end);
292 ret = AST_ConvertNode(Block, Node->If.True, 0);
296 Bytecode_SetLabel(Block->Handle, if_end);
300 case NODETYPE_LOOP: {
301 int loop_start, loop_end;
302 int saved_break, saved_continue;
303 const char *saved_tag;
306 ret = AST_ConvertNode(Block, Node->For.Init, 0);
309 loop_start = Bytecode_AllocateLabel(Block->Handle);
310 loop_end = Bytecode_AllocateLabel(Block->Handle);
312 saved_break = Block->BreakTarget;
313 saved_continue = Block->ContinueTarget;
314 saved_tag = Block->Tag;
315 Block->BreakTarget = loop_end;
316 Block->ContinueTarget = loop_end;
317 Block->Tag = Node->For.Tag;
319 Bytecode_SetLabel(Block->Handle, loop_start);
321 // Check initial condition
322 if( !Node->For.bCheckAfter )
324 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
326 Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
327 Bytecode_AppendCondJump(Block->Handle, loop_end);
331 ret = AST_ConvertNode(Block, Node->For.Code, 0);
335 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
339 if( Node->For.bCheckAfter )
341 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
343 Bytecode_AppendCondJump(Block->Handle, loop_start);
347 Bytecode_AppendJump(Block->Handle, loop_start);
350 Bytecode_SetLabel(Block->Handle, loop_end);
352 Block->BreakTarget = saved_break;
353 Block->ContinueTarget = saved_continue;
354 Block->Tag = saved_tag;
358 case NODETYPE_RETURN:
359 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
361 Bytecode_AppendReturn(Block->Handle);
365 case NODETYPE_CONTINUE: {
366 tAST_BlockInfo *bi = Block;
367 if( Node->Variable.Name[0] ) {
368 while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent;
371 // TODO: Check if BreakTarget/ContinueTarget are valid
372 if( Node->Type == NODETYPE_BREAK )
373 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
375 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
379 case NODETYPE_DEFVAR:
380 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
383 if( Node->DefVar.InitialValue )
385 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
387 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
393 if( Block->NamespaceDepth == MAX_NAMESPACE_DEPTH ) {
394 AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", MAX_NAMESPACE_DEPTH);
397 Block->CurNamespaceStack[ Block->NamespaceDepth ] = Node->Scope.Name;
398 Block->NamespaceDepth ++;
399 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
400 if( Block->NamespaceDepth != 0 ) {
401 AST_RuntimeError(Node, "Namespace scope used but no element at the end");
403 CHECK_IF_NEEDED(0); // No warning?
407 case NODETYPE_VARIABLE:
408 ret = BC_Variable_GetValue( Block, Node );
412 // Element of an Object
413 case NODETYPE_ELEMENT:
414 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
417 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
421 // Cast a value to another
423 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
425 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
429 // Index into an array
431 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array
433 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset
436 Bytecode_AppendIndex(Block->Handle);
440 // TODO: Implement runtime constants
441 case NODETYPE_CONSTANT:
442 // TODO: Scan namespace for constant name
443 AST_RuntimeError(Node, "TODO - Runtime Constants");
444 Block->NamespaceDepth = 0;
449 case NODETYPE_STRING:
450 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
453 case NODETYPE_INTEGER:
454 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
458 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
462 // --- Operations ---
463 // Boolean Operations
464 case NODETYPE_LOGICALNOT: // Logical NOT (!)
465 if(!op) op = BC_OP_LOGICNOT;
466 case NODETYPE_BWNOT: // Bitwise NOT (~)
467 if(!op) op = BC_OP_BITNOT;
468 case NODETYPE_NEGATE: // Negation (-)
469 if(!op) op = BC_OP_NEG;
470 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
472 Bytecode_AppendUniOp(Block->Handle, op);
477 case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
478 case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR;
479 case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR;
481 case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
482 case NODETYPE_NOTEQUALS: if(!op) op = BC_OP_NOTEQUALS;
483 case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
484 case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN;
485 case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL;
486 case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
487 // General Binary Operations
488 case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
489 case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
490 case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
491 case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
492 case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
493 case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
494 case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
495 case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
496 case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
497 case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
498 case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
499 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
501 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
504 Bytecode_AppendBinOp(Block->Handle, op);
510 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
514 #if TRACE_NODE_RETURNS
515 if(ret && ret != ERRPTR) {
516 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
519 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
526 int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
529 switch(DestNode->Type)
532 case NODETYPE_VARIABLE:
533 ret = BC_Variable_SetValue( Block, DestNode );
537 ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1); // Array
539 ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
541 Bytecode_AppendSetIndex( Block->Handle );
544 case NODETYPE_ELEMENT:
545 ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
547 Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
551 // TODO: Support assigning to object attributes
552 AST_RuntimeError(DestNode, "Assignment target is not a LValue");
559 * \brief Define a variable
560 * \param Block Current block state
561 * \param Type Type of the variable
562 * \param Name Name of the variable
563 * \return Boolean Failure
565 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
568 tAST_Variable *var, *prev = NULL;
570 for( var = Block->FirstVar; var; prev = var, var = var->Next )
572 if( strcmp(var->Name, Name) == 0 ) {
573 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
578 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
581 strcpy(var->Name, Name);
583 if(prev) prev->Next = var;
584 else Block->FirstVar = var;
588 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
593 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
596 tAST_Variable *var = NULL;
599 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
600 var = VarNode->ValueCache;
601 #if TRACE_VAR_LOOKUPS
602 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
603 VarNode->Variable.Name, var,
604 VarNode->BlockState, VarNode->BlockIdent
611 for( bs = Block; bs; bs = bs->Parent )
613 for( var = bs->FirstVar; var; var = var->Next )
615 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
623 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
625 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
629 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
634 #if TRACE_VAR_LOOKUPS
635 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
636 VarNode->Variable.Name, var,
637 Block, Block->Ident);
640 VarNode->ValueCache = var;
641 VarNode->BlockState = Block;
642 VarNode->BlockIdent = Block->Ident;
652 * \brief Set the value of a variable
653 * \return Boolean Failure
655 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
659 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
664 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
669 * \brief Get the value of a variable
671 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
675 var = BC_Variable_Lookup(Block, VarNode, 0);
678 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
683 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
688 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
690 fprintf(stderr, "%s: ", Type);
691 va_start(args, Format);
692 vfprintf(stderr, Format, args);
694 fprintf(stderr, "\n");
696 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
701 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
703 fprintf(stderr, "error: ");
704 va_start(args, Format);
705 vfprintf(stderr, Format, args);
707 fprintf(stderr, "\n");