4 * AST to Bytecode Conversion
11 #include "bytecode_gen.h"
12 #include "bytecode_ops.h"
14 #define TRACE_VAR_LOOKUPS 0
15 #define TRACE_NODE_RETURNS 0
18 extern tSpiderFunction *gpExports_First;
21 typedef struct sAST_BlockInfo
23 struct sAST_BlockInfo *Parent;
33 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node);
35 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
36 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
37 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
39 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
40 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
43 // int giNextBlockIdent = 1;
47 * \brief Convert a function into bytecode
49 tBC_Function *Bytecode_ConvertFunction(tAST_Function *ASTFcn)
52 tAST_BlockInfo bi = {0};
57 char *arg_names[ASTFcn->ArgumentCount];
58 int arg_types[ASTFcn->ArgumentCount];
60 for(arg = ASTFcn->Arguments; arg; arg = arg->NextSibling)
62 arg_names[i] = arg->DefVar.Name;
63 arg_types[i] = arg->DefVar.DataType;
66 ret = Bytecode_CreateFunction(ASTFcn->Name, ASTFcn->ArgumentCount, arg_names, arg_types);
71 if( AST_ConvertNode(&bi, ASTFcn->Code) )
73 Bytecode_DeleteFunction(ret);
80 * \brief Convert a node into bytecode
81 * \param Block Execution context
82 * \param Node Node to execute
84 int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
98 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
100 tAST_BlockInfo blockInfo;
101 blockInfo.Parent = Block;
102 blockInfo.Handle = Block->Handle;
103 blockInfo.ContinueTarget = 0;
104 blockInfo.BreakTarget = 0;
105 // Loop over all nodes, or until the return value is set
106 for(node = Node->Block.FirstChild;
108 node = node->NextSibling )
110 AST_ConvertNode(Block, node);
113 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
117 case NODETYPE_ASSIGN:
118 // TODO: Support assigning to object attributes
119 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
120 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
123 ret = AST_ConvertNode(Block, Node->Assign.Value);
126 // Perform assignment operation
127 if( Node->Assign.Operation != NODETYPE_NOP )
130 ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
132 Bytecode_AppendBinOp(Block->Handle, Node->Assign.Operation);
135 // Set the variable value
136 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
139 // Post increment/decrement
140 case NODETYPE_POSTINC:
141 case NODETYPE_POSTDEC:
142 Bytecode_AppendConstInt(Block->Handle, 1);
144 // TODO: Support assigning to object attributes
145 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
146 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
150 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
153 if( Node->Type == NODETYPE_POSTDEC )
154 Bytecode_AppendBinOp(Block->Handle, NODETYPE_SUBTRACT);
156 Bytecode_AppendBinOp(Block->Handle, NODETYPE_ADD);
159 ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
164 case NODETYPE_METHODCALL:
165 case NODETYPE_FUNCTIONCALL:
166 case NODETYPE_CREATEOBJECT:
168 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
170 ret = AST_ConvertNode(Block, node);
176 if( Node->Type == NODETYPE_CREATEOBJECT )
178 // TODO: Sanity check stack top
179 Bytecode_AppendCreateObj(Block->Handle, Node->FunctionCall.Name, i);
181 else if( Node->Type == NODETYPE_METHODCALL )
183 // TODO: Sanity check stack top
184 ret = AST_ConvertNode(Block, Node->FunctionCall.Object);
186 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, i);
190 Bytecode_AppendFunctionCall(Block->Handle, Node->FunctionCall.Name, i);
197 ret = AST_ConvertNode(Block, Node->If.Condition);
200 if_true = Bytecode_AllocateLabel(Block->Handle);
201 if_end = Bytecode_AllocateLabel(Block->Handle);
203 Bytecode_AppendCondJump(Block->Handle, if_true);
206 ret = AST_ConvertNode(Block, Node->If.False);
208 Bytecode_AppendJump(Block->Handle, if_end);
211 Bytecode_SetLabel(Block->Handle, if_true);
212 ret = AST_ConvertNode(Block, Node->If.True);
216 Bytecode_SetLabel(Block->Handle, if_end);
220 case NODETYPE_LOOP: {
221 int loop_start, loop_end;
222 int saved_break, saved_continue;
223 const char *saved_tag;
226 ret = AST_ConvertNode(Block, Node->For.Init);
229 loop_start = Bytecode_AllocateLabel(Block->Handle);
230 loop_end = Bytecode_AllocateLabel(Block->Handle);
232 saved_break = Block->BreakTarget;
233 saved_continue = Block->ContinueTarget;
234 saved_tag = Block->Tag;
235 Block->BreakTarget = loop_end;
236 Block->ContinueTarget = loop_end;
237 Block->Tag = Node->For.Tag;
239 Bytecode_SetLabel(Block->Handle, loop_start);
241 // Check initial condition
242 if( !Node->For.bCheckAfter )
244 ret = AST_ConvertNode(Block, Node->For.Condition);
246 Bytecode_AppendUniOp(Block->Handle, NODETYPE_LOGICALNOT);
247 Bytecode_AppendCondJump(Block->Handle, loop_end);
251 ret = AST_ConvertNode(Block, Node->For.Code);
255 ret = AST_ConvertNode(Block, Node->For.Increment);
259 if( Node->For.bCheckAfter )
261 ret = AST_ConvertNode(Block, Node->For.Condition);
263 Bytecode_AppendCondJump(Block->Handle, loop_start);
266 Bytecode_SetLabel(Block->Handle, loop_end);
268 Block->BreakTarget = saved_break;
269 Block->ContinueTarget = saved_continue;
270 Block->Tag = saved_tag;
274 case NODETYPE_RETURN:
275 ret = AST_ConvertNode(Block, Node->UniOp.Value);
277 Bytecode_AppendReturn(Block->Handle);
281 case NODETYPE_CONTINUE: {
282 tAST_BlockInfo *bi = Block;
283 if( Node->Variable.Name[0] ) {
284 while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent;
287 // TODO: Check if BreakTarget/ContinueTarget are valid
288 if( Node->Type == NODETYPE_BREAK )
289 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
291 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
295 case NODETYPE_DEFVAR:
296 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
299 if( Node->DefVar.InitialValue )
301 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue);
303 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
309 Bytecode_AppendSubNamespace(Block->Handle, Node->Scope.Name);
310 ret = AST_ConvertNode(Block, Node->Scope.Element);
314 case NODETYPE_VARIABLE:
315 ret = BC_Variable_GetValue( Block, Node );
318 // Element of an Object
319 case NODETYPE_ELEMENT:
320 ret = AST_ConvertNode( Block, Node->Scope.Element );
323 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
326 // Cast a value to another
328 ret = AST_ConvertNode(Block, Node->Cast.Value);
330 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
333 // Index into an array
335 ret = AST_ConvertNode(Block, Node->BinOp.Left); // Array
337 ret = AST_ConvertNode(Block, Node->BinOp.Right); // Offset
340 Bytecode_AppendIndex(Block->Handle);
343 // TODO: Implement runtime constants
344 case NODETYPE_CONSTANT:
345 // TODO: Scan namespace for constant name
346 AST_RuntimeError(Node, "TODO - Runtime Constants");
351 case NODETYPE_STRING:
352 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
354 case NODETYPE_INTEGER:
355 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
358 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Real);
361 // --- Operations ---
362 // Boolean Operations
363 case NODETYPE_LOGICALNOT: // Logical NOT (!)
364 if(!op) op = BC_OP_LOGICNOT;
365 case NODETYPE_BWNOT: // Bitwise NOT (~)
366 if(!op) op = BC_OP_BITNOT;
367 case NODETYPE_NEGATE: // Negation (-)
368 if(!op) op = BC_OP_NEG;
369 ret = AST_ConvertNode(Block, Node->UniOp.Value);
371 Bytecode_AppendUniOp(Block->Handle, op);
374 case NODETYPE_LOGICALAND: // Logical AND (&&)
375 if(!op) op = BC_OP_LOGICAND;
376 case NODETYPE_LOGICALOR: // Logical OR (||)
377 if(!op) op = BC_OP_LOGICOR;
378 case NODETYPE_LOGICALXOR: // Logical XOR (^^)
379 if(!op) op = BC_OP_LOGICXOR;
381 case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
382 case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
383 case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN;
384 case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL;
385 case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
386 // General Binary Operations
387 case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
388 case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
389 case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
390 case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
391 case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
392 case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
393 case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
394 case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
395 case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
396 case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
397 case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
398 ret = AST_ConvertNode(Block, Node->BinOp.Left);
400 ret = AST_ConvertNode(Block, Node->BinOp.Right);
403 Bytecode_AppendBinOp(Block->Handle, op);
408 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
412 #if TRACE_NODE_RETURNS
413 if(ret && ret != ERRPTR) {
414 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
417 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
425 * \brief Define a variable
426 * \param Block Current block state
427 * \param Type Type of the variable
428 * \param Name Name of the variable
429 * \return Boolean Failure
431 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
434 tAST_Variable *var, *prev = NULL;
436 for( var = Block->FirstVar; var; prev = var, var = var->Next )
438 if( strcmp(var->Name, Name) == 0 ) {
439 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
444 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
447 strcpy(var->Name, Name);
449 if(prev) prev->Next = var;
450 else Block->FirstVar = var;
454 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
459 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
462 tAST_Variable *var = NULL;
465 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
466 var = VarNode->ValueCache;
467 #if TRACE_VAR_LOOKUPS
468 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
469 VarNode->Variable.Name, var,
470 VarNode->BlockState, VarNode->BlockIdent
477 for( bs = Block; bs; bs = bs->Parent )
479 for( var = bs->FirstVar; var; var = var->Next )
481 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
489 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
491 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
495 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
500 #if TRACE_VAR_LOOKUPS
501 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
502 VarNode->Variable.Name, var,
503 Block, Block->Ident);
506 VarNode->ValueCache = var;
507 VarNode->BlockState = Block;
508 VarNode->BlockIdent = Block->Ident;
518 * \brief Set the value of a variable
519 * \return Boolean Failure
521 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
525 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
530 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
535 * \brief Get the value of a variable
537 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
541 var = BC_Variable_Lookup(Block, VarNode, 0);
544 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
549 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
554 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
556 fprintf(stderr, "%s: ", Type);
557 va_start(args, Format);
558 vfprintf(stderr, Format, args);
560 fprintf(stderr, "\n");
562 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
567 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
569 fprintf(stderr, "error: ");
570 va_start(args, Format);
571 vfprintf(stderr, Format, args);
573 fprintf(stderr, "\n");