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);
88 * \brief Convert a node into bytecode
89 * \param Block Execution context
90 * \param Node Node to execute
92 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
108 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
110 tAST_BlockInfo blockInfo = {0};
111 blockInfo.Parent = Block;
112 blockInfo.Handle = Block->Handle;
113 // Loop over all nodes, or until the return value is set
114 for(node = Node->Block.FirstChild;
116 node = node->NextSibling )
118 AST_ConvertNode(Block, node, 0);
121 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
126 case NODETYPE_ASSIGN:
127 // TODO: Support assigning to object attributes
128 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
129 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
133 // Perform assignment operation
134 if( Node->Assign.Operation != NODETYPE_NOP )
137 ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
139 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
141 switch(Node->Assign.Operation)
143 // General Binary Operations
144 case NODETYPE_ADD: op = BC_OP_ADD; break;
145 case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
146 case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
147 case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
148 case NODETYPE_MODULO: op = BC_OP_MODULO; break;
149 case NODETYPE_BWAND: op = BC_OP_BITAND; break;
150 case NODETYPE_BWOR: op = BC_OP_BITOR; break;
151 case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
152 case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
153 case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
154 case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
157 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
160 printf("assign, op = %i\n", op);
161 Bytecode_AppendBinOp(Block->Handle, op);
165 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
170 Bytecode_AppendDuplicate(Block->Handle);
171 // Set the variable value
172 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
176 // Post increment/decrement
177 case NODETYPE_POSTINC:
178 case NODETYPE_POSTDEC:
179 Bytecode_AppendConstInt(Block->Handle, 1);
181 // TODO: Support assigning to object attributes
182 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
183 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
187 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
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_Variable_SetValue(Block, Node->UniOp.Value);
201 case NODETYPE_METHODCALL:
202 case NODETYPE_FUNCTIONCALL:
203 case NODETYPE_CREATEOBJECT: {
205 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
207 ret = AST_ConvertNode(Block, node, 1);
213 if( Node->Type == NODETYPE_METHODCALL )
215 // TODO: Sanity check stack top
216 ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
218 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
224 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
225 newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
226 newnamelen += strlen(Node->FunctionCall.Name) + 1;
227 manglename = alloca(newnamelen);
229 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
231 strcat(manglename, Block->CurNamespaceStack[i]);
232 pos = strlen(manglename);
233 manglename[pos] = BC_NS_SEPARATOR;
234 manglename[pos+1] = '\0';
236 strcat(manglename, Node->FunctionCall.Name);
238 if( Node->Type == NODETYPE_CREATEOBJECT )
240 // TODO: Sanity check stack top
241 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
245 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
253 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
256 if_end = Bytecode_AllocateLabel(Block->Handle);
258 if( Node->If.False->Type != NODETYPE_NOP )
260 int if_true = Bytecode_AllocateLabel(Block->Handle);
262 Bytecode_AppendCondJump(Block->Handle, if_true);
265 ret = AST_ConvertNode(Block, Node->If.False, 0);
267 Bytecode_AppendJump(Block->Handle, if_end);
268 Bytecode_SetLabel(Block->Handle, if_true);
272 Bytecode_AppendCondJumpNot(Block->Handle, if_end);
276 ret = AST_ConvertNode(Block, Node->If.True, 0);
280 Bytecode_SetLabel(Block->Handle, if_end);
285 case NODETYPE_LOOP: {
286 int loop_start, loop_end;
287 int saved_break, saved_continue;
288 const char *saved_tag;
291 ret = AST_ConvertNode(Block, Node->For.Init, 0);
294 loop_start = Bytecode_AllocateLabel(Block->Handle);
295 loop_end = Bytecode_AllocateLabel(Block->Handle);
297 saved_break = Block->BreakTarget;
298 saved_continue = Block->ContinueTarget;
299 saved_tag = Block->Tag;
300 Block->BreakTarget = loop_end;
301 Block->ContinueTarget = loop_end;
302 Block->Tag = Node->For.Tag;
304 Bytecode_SetLabel(Block->Handle, loop_start);
306 // Check initial condition
307 if( !Node->For.bCheckAfter )
309 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
311 Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
312 Bytecode_AppendCondJump(Block->Handle, loop_end);
316 ret = AST_ConvertNode(Block, Node->For.Code, 0);
320 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
324 if( Node->For.bCheckAfter )
326 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
328 Bytecode_AppendCondJump(Block->Handle, loop_start);
332 Bytecode_AppendJump(Block->Handle, loop_start);
335 Bytecode_SetLabel(Block->Handle, loop_end);
337 Block->BreakTarget = saved_break;
338 Block->ContinueTarget = saved_continue;
339 Block->Tag = saved_tag;
344 case NODETYPE_RETURN:
345 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
347 Bytecode_AppendReturn(Block->Handle);
352 case NODETYPE_CONTINUE: {
353 tAST_BlockInfo *bi = Block;
354 if( Node->Variable.Name[0] ) {
355 while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent;
358 // TODO: Check if BreakTarget/ContinueTarget are valid
359 if( Node->Type == NODETYPE_BREAK )
360 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
362 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
367 case NODETYPE_DEFVAR:
368 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
371 if( Node->DefVar.InitialValue )
373 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
375 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
382 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
383 if( i == MAX_NAMESPACE_DEPTH ) {
384 AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
387 Block->CurNamespaceStack[i] = Node->Scope.Name;
388 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
389 Block->CurNamespaceStack[i] = NULL;
393 case NODETYPE_VARIABLE:
394 ret = BC_Variable_GetValue( Block, Node );
397 // Element of an Object
398 case NODETYPE_ELEMENT:
399 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
402 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
405 // Cast a value to another
407 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
409 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
412 // Index into an array
414 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array
416 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset
419 Bytecode_AppendIndex(Block->Handle);
422 // TODO: Implement runtime constants
423 case NODETYPE_CONSTANT:
424 // TODO: Scan namespace for constant name
425 AST_RuntimeError(Node, "TODO - Runtime Constants");
430 case NODETYPE_STRING:
431 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
433 case NODETYPE_INTEGER:
434 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
437 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
440 // --- Operations ---
441 // Boolean Operations
442 case NODETYPE_LOGICALNOT: // Logical NOT (!)
443 if(!op) op = BC_OP_LOGICNOT;
444 case NODETYPE_BWNOT: // Bitwise NOT (~)
445 if(!op) op = BC_OP_BITNOT;
446 case NODETYPE_NEGATE: // Negation (-)
447 if(!op) op = BC_OP_NEG;
448 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
450 Bytecode_AppendUniOp(Block->Handle, op);
454 case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
455 case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR;
456 case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR;
458 case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
459 case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
460 case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN;
461 case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL;
462 case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
463 // General Binary Operations
464 case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
465 case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
466 case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
467 case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
468 case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
469 case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
470 case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
471 case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
472 case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
473 case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
474 case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
475 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
477 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
480 Bytecode_AppendBinOp(Block->Handle, op);
485 AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
489 #if TRACE_NODE_RETURNS
490 if(ret && ret != ERRPTR) {
491 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
494 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
498 if( !bKeepValue && bAddedValue )
499 Bytecode_AppendDelete(Block->Handle);
505 * \brief Define a variable
506 * \param Block Current block state
507 * \param Type Type of the variable
508 * \param Name Name of the variable
509 * \return Boolean Failure
511 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
514 tAST_Variable *var, *prev = NULL;
516 for( var = Block->FirstVar; var; prev = var, var = var->Next )
518 if( strcmp(var->Name, Name) == 0 ) {
519 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
524 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
527 strcpy(var->Name, Name);
529 if(prev) prev->Next = var;
530 else Block->FirstVar = var;
534 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
539 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
542 tAST_Variable *var = NULL;
545 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
546 var = VarNode->ValueCache;
547 #if TRACE_VAR_LOOKUPS
548 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
549 VarNode->Variable.Name, var,
550 VarNode->BlockState, VarNode->BlockIdent
557 for( bs = Block; bs; bs = bs->Parent )
559 for( var = bs->FirstVar; var; var = var->Next )
561 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
569 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
571 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
575 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
580 #if TRACE_VAR_LOOKUPS
581 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
582 VarNode->Variable.Name, var,
583 Block, Block->Ident);
586 VarNode->ValueCache = var;
587 VarNode->BlockState = Block;
588 VarNode->BlockIdent = Block->Ident;
598 * \brief Set the value of a variable
599 * \return Boolean Failure
601 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
605 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
610 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
615 * \brief Get the value of a variable
617 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
621 var = BC_Variable_Lookup(Block, VarNode, 0);
624 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
629 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
634 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
636 fprintf(stderr, "%s: ", Type);
637 va_start(args, Format);
638 vfprintf(stderr, Format, args);
640 fprintf(stderr, "\n");
642 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
647 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
649 fprintf(stderr, "error: ");
650 va_start(args, Format);
651 vfprintf(stderr, Format, args);
653 fprintf(stderr, "\n");