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
19 extern tSpiderFunction *gpExports_First;
22 typedef struct sAST_BlockInfo
24 struct sAST_BlockInfo *Parent;
34 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node);
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);
40 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
41 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
44 // int giNextBlockIdent = 1;
47 int SpiderScript_BytecodeScript(tSpiderScript *Script)
49 tScript_Function *fcn;
50 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
52 if( Bytecode_ConvertFunction(fcn) == 0 )
59 * \brief Convert a function into bytecode
61 tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
64 tAST_BlockInfo bi = {0};
66 // TODO: Return BCFcn instead?
67 if(Fcn->BCFcn) return Fcn->BCFcn;
69 ret = Bytecode_CreateFunction(Fcn);
73 if( AST_ConvertNode(&bi, Fcn->ASTFcn) )
75 Bytecode_DeleteFunction(ret);
85 * \brief Convert a node into bytecode
86 * \param Block Execution context
87 * \param Node Node to execute
89 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
103 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
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;
113 node = node->NextSibling )
115 AST_ConvertNode(Block, node);
118 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
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");
128 ret = AST_ConvertNode(Block, Node->Assign.Value);
131 // Perform assignment operation
132 if( Node->Assign.Operation != NODETYPE_NOP )
135 ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
137 Bytecode_AppendBinOp(Block->Handle, Node->Assign.Operation);
140 // Set the variable value
141 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
144 // Post increment/decrement
145 case NODETYPE_POSTINC:
146 case NODETYPE_POSTDEC:
147 Bytecode_AppendConstInt(Block->Handle, 1);
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");
155 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
158 if( Node->Type == NODETYPE_POSTDEC )
159 Bytecode_AppendBinOp(Block->Handle, NODETYPE_SUBTRACT);
161 Bytecode_AppendBinOp(Block->Handle, NODETYPE_ADD);
164 ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
169 case NODETYPE_METHODCALL:
170 case NODETYPE_FUNCTIONCALL:
171 case NODETYPE_CREATEOBJECT:
173 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
175 ret = AST_ConvertNode(Block, node);
181 if( Node->Type == NODETYPE_CREATEOBJECT )
183 // TODO: Sanity check stack top
184 Bytecode_AppendCreateObj(Block->Handle, Node->FunctionCall.Name, i);
186 else if( Node->Type == NODETYPE_METHODCALL )
188 // TODO: Sanity check stack top
189 ret = AST_ConvertNode(Block, Node->FunctionCall.Object);
191 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, i);
195 Bytecode_AppendFunctionCall(Block->Handle, Node->FunctionCall.Name, i);
202 ret = AST_ConvertNode(Block, Node->If.Condition);
205 if_true = Bytecode_AllocateLabel(Block->Handle);
206 if_end = Bytecode_AllocateLabel(Block->Handle);
208 Bytecode_AppendCondJump(Block->Handle, if_true);
211 ret = AST_ConvertNode(Block, Node->If.False);
213 Bytecode_AppendJump(Block->Handle, if_end);
216 Bytecode_SetLabel(Block->Handle, if_true);
217 ret = AST_ConvertNode(Block, Node->If.True);
221 Bytecode_SetLabel(Block->Handle, if_end);
225 case NODETYPE_LOOP: {
226 int loop_start, loop_end;
227 int saved_break, saved_continue;
228 const char *saved_tag;
231 ret = AST_ConvertNode(Block, Node->For.Init);
234 loop_start = Bytecode_AllocateLabel(Block->Handle);
235 loop_end = Bytecode_AllocateLabel(Block->Handle);
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;
244 Bytecode_SetLabel(Block->Handle, loop_start);
246 // Check initial condition
247 if( !Node->For.bCheckAfter )
249 ret = AST_ConvertNode(Block, Node->For.Condition);
251 Bytecode_AppendUniOp(Block->Handle, NODETYPE_LOGICALNOT);
252 Bytecode_AppendCondJump(Block->Handle, loop_end);
256 ret = AST_ConvertNode(Block, Node->For.Code);
260 ret = AST_ConvertNode(Block, Node->For.Increment);
264 if( Node->For.bCheckAfter )
266 ret = AST_ConvertNode(Block, Node->For.Condition);
268 Bytecode_AppendCondJump(Block->Handle, loop_start);
271 Bytecode_SetLabel(Block->Handle, loop_end);
273 Block->BreakTarget = saved_break;
274 Block->ContinueTarget = saved_continue;
275 Block->Tag = saved_tag;
279 case NODETYPE_RETURN:
280 ret = AST_ConvertNode(Block, Node->UniOp.Value);
282 Bytecode_AppendReturn(Block->Handle);
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;
292 // TODO: Check if BreakTarget/ContinueTarget are valid
293 if( Node->Type == NODETYPE_BREAK )
294 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
296 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
300 case NODETYPE_DEFVAR:
301 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
304 if( Node->DefVar.InitialValue )
306 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue);
308 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
314 Bytecode_AppendSubNamespace(Block->Handle, Node->Scope.Name);
315 ret = AST_ConvertNode(Block, Node->Scope.Element);
319 case NODETYPE_VARIABLE:
320 ret = BC_Variable_GetValue( Block, Node );
323 // Element of an Object
324 case NODETYPE_ELEMENT:
325 ret = AST_ConvertNode( Block, Node->Scope.Element );
328 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
331 // Cast a value to another
333 ret = AST_ConvertNode(Block, Node->Cast.Value);
335 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
338 // Index into an array
340 ret = AST_ConvertNode(Block, Node->BinOp.Left); // Array
342 ret = AST_ConvertNode(Block, Node->BinOp.Right); // Offset
345 Bytecode_AppendIndex(Block->Handle);
348 // TODO: Implement runtime constants
349 case NODETYPE_CONSTANT:
350 // TODO: Scan namespace for constant name
351 AST_RuntimeError(Node, "TODO - Runtime Constants");
356 case NODETYPE_STRING:
357 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
359 case NODETYPE_INTEGER:
360 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
363 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Real);
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);
376 Bytecode_AppendUniOp(Block->Handle, op);
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;
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);
405 ret = AST_ConvertNode(Block, Node->BinOp.Right);
408 Bytecode_AppendBinOp(Block->Handle, op);
413 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
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);
422 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
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
436 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
439 tAST_Variable *var, *prev = NULL;
441 for( var = Block->FirstVar; var; prev = var, var = var->Next )
443 if( strcmp(var->Name, Name) == 0 ) {
444 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
449 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
452 strcpy(var->Name, Name);
454 if(prev) prev->Next = var;
455 else Block->FirstVar = var;
459 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
464 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
467 tAST_Variable *var = NULL;
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
482 for( bs = Block; bs; bs = bs->Parent )
484 for( var = bs->FirstVar; var; var = var->Next )
486 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
494 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
496 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
500 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
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);
511 VarNode->ValueCache = var;
512 VarNode->BlockState = Block;
513 VarNode->BlockIdent = Block->Ident;
523 * \brief Set the value of a variable
524 * \return Boolean Failure
526 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
530 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
535 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
540 * \brief Get the value of a variable
542 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
546 var = BC_Variable_Lookup(Block, VarNode, 0);
549 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
554 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
559 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
561 fprintf(stderr, "%s: ", Type);
562 va_start(args, Format);
563 vfprintf(stderr, Format, args);
565 fprintf(stderr, "\n");
567 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
572 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
574 fprintf(stderr, "error: ");
575 va_start(args, Format);
576 vfprintf(stderr, Format, args);
578 fprintf(stderr, "\n");