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)
106 Bytecode_AppendEnterContext(Block->Handle); // Create a new block
108 tAST_BlockInfo blockInfo = {0};
109 blockInfo.Parent = Block;
110 blockInfo.Handle = Block->Handle;
111 // Loop over all nodes, or until the return value is set
112 for(node = Node->Block.FirstChild;
114 node = node->NextSibling )
116 AST_ConvertNode(Block, node, 0);
119 Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
123 case NODETYPE_ASSIGN:
124 // TODO: Support assigning to object attributes
125 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
126 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
129 ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
132 // Perform assignment operation
133 if( Node->Assign.Operation != NODETYPE_NOP )
136 ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
138 switch(Node->Assign.Operation)
140 // General Binary Operations
141 case NODETYPE_ADD: op = BC_OP_ADD; break;
142 case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
143 case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
144 case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
145 case NODETYPE_MODULO: op = BC_OP_MODULO; break;
146 case NODETYPE_BWAND: op = BC_OP_BITAND; break;
147 case NODETYPE_BWOR: op = BC_OP_BITOR; break;
148 case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
149 case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
150 case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
151 case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
154 AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
157 printf("assign, op = %i\n", op);
158 Bytecode_AppendBinOp(Block->Handle, op);
162 Bytecode_AppendDuplicate(Block->Handle);
163 // Set the variable value
164 ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
167 // Post increment/decrement
168 case NODETYPE_POSTINC:
169 case NODETYPE_POSTDEC:
170 Bytecode_AppendConstInt(Block->Handle, 1);
172 // TODO: Support assigning to object attributes
173 if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
174 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
178 ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
181 if( Node->Type == NODETYPE_POSTDEC )
182 Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
184 Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
187 ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
192 case NODETYPE_METHODCALL:
193 case NODETYPE_FUNCTIONCALL:
194 case NODETYPE_CREATEOBJECT: {
196 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
198 ret = AST_ConvertNode(Block, node, 1);
204 if( Node->Type == NODETYPE_METHODCALL )
206 // TODO: Sanity check stack top
207 ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
209 Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
215 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
216 newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
217 newnamelen += strlen(Node->FunctionCall.Name) + 1;
218 manglename = alloca(newnamelen);
220 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
222 strcat(manglename, Block->CurNamespaceStack[i]);
223 pos = strlen(manglename);
224 manglename[pos] = BC_NS_SEPARATOR;
225 manglename[pos+1] = '\0';
227 strcat(manglename, Node->FunctionCall.Name);
229 if( Node->Type == NODETYPE_CREATEOBJECT )
231 // TODO: Sanity check stack top
232 Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
236 Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
244 ret = AST_ConvertNode(Block, Node->If.Condition, 1);
247 if_end = Bytecode_AllocateLabel(Block->Handle);
249 if( Node->If.False->Type != NODETYPE_NOP )
251 int if_true = Bytecode_AllocateLabel(Block->Handle);
253 Bytecode_AppendCondJump(Block->Handle, if_true);
256 ret = AST_ConvertNode(Block, Node->If.False, 0);
258 Bytecode_AppendJump(Block->Handle, if_end);
259 Bytecode_SetLabel(Block->Handle, if_true);
263 Bytecode_AppendCondJumpNot(Block->Handle, if_end);
267 ret = AST_ConvertNode(Block, Node->If.True, 0);
271 Bytecode_SetLabel(Block->Handle, if_end);
275 case NODETYPE_LOOP: {
276 int loop_start, loop_end;
277 int saved_break, saved_continue;
278 const char *saved_tag;
281 ret = AST_ConvertNode(Block, Node->For.Init, 0);
284 loop_start = Bytecode_AllocateLabel(Block->Handle);
285 loop_end = Bytecode_AllocateLabel(Block->Handle);
287 saved_break = Block->BreakTarget;
288 saved_continue = Block->ContinueTarget;
289 saved_tag = Block->Tag;
290 Block->BreakTarget = loop_end;
291 Block->ContinueTarget = loop_end;
292 Block->Tag = Node->For.Tag;
294 Bytecode_SetLabel(Block->Handle, loop_start);
296 // Check initial condition
297 if( !Node->For.bCheckAfter )
299 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
301 Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
302 Bytecode_AppendCondJump(Block->Handle, loop_end);
306 ret = AST_ConvertNode(Block, Node->For.Code, 0);
310 ret = AST_ConvertNode(Block, Node->For.Increment, 0);
314 if( Node->For.bCheckAfter )
316 ret = AST_ConvertNode(Block, Node->For.Condition, 1);
318 Bytecode_AppendCondJump(Block->Handle, loop_start);
322 Bytecode_AppendJump(Block->Handle, loop_start);
325 Bytecode_SetLabel(Block->Handle, loop_end);
327 Block->BreakTarget = saved_break;
328 Block->ContinueTarget = saved_continue;
329 Block->Tag = saved_tag;
333 case NODETYPE_RETURN:
334 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
336 Bytecode_AppendReturn(Block->Handle);
340 case NODETYPE_CONTINUE: {
341 tAST_BlockInfo *bi = Block;
342 if( Node->Variable.Name[0] ) {
343 while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0) bi = bi->Parent;
346 // TODO: Check if BreakTarget/ContinueTarget are valid
347 if( Node->Type == NODETYPE_BREAK )
348 Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
350 Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
354 case NODETYPE_DEFVAR:
355 ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
358 if( Node->DefVar.InitialValue )
360 ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
362 Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
368 for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
369 if( i == MAX_NAMESPACE_DEPTH ) {
370 AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
373 Block->CurNamespaceStack[i] = Node->Scope.Name;
374 ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
375 Block->CurNamespaceStack[i] = NULL;
379 case NODETYPE_VARIABLE:
380 ret = BC_Variable_GetValue( Block, Node );
383 // Element of an Object
384 case NODETYPE_ELEMENT:
385 ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
388 Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
391 // Cast a value to another
393 ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
395 Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
398 // Index into an array
400 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array
402 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset
405 Bytecode_AppendIndex(Block->Handle);
408 // TODO: Implement runtime constants
409 case NODETYPE_CONSTANT:
410 // TODO: Scan namespace for constant name
411 AST_RuntimeError(Node, "TODO - Runtime Constants");
416 case NODETYPE_STRING:
417 Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
419 case NODETYPE_INTEGER:
420 Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
423 Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
426 // --- Operations ---
427 // Boolean Operations
428 case NODETYPE_LOGICALNOT: // Logical NOT (!)
429 if(!op) op = BC_OP_LOGICNOT;
430 case NODETYPE_BWNOT: // Bitwise NOT (~)
431 if(!op) op = BC_OP_BITNOT;
432 case NODETYPE_NEGATE: // Negation (-)
433 if(!op) op = BC_OP_NEG;
434 ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
436 Bytecode_AppendUniOp(Block->Handle, op);
440 case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
441 case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR;
442 case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR;
444 case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
445 case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
446 case NODETYPE_GREATERTHAN: if(!op) op = BC_OP_GREATERTHAN;
447 case NODETYPE_LESSTHANEQUAL: if(!op) op = BC_OP_LESSTHANOREQUAL;
448 case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
449 // General Binary Operations
450 case NODETYPE_ADD: if(!op) op = BC_OP_ADD;
451 case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
452 case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
453 case NODETYPE_DIVIDE: if(!op) op = BC_OP_DIVIDE;
454 case NODETYPE_MODULO: if(!op) op = BC_OP_MODULO;
455 case NODETYPE_BWAND: if(!op) op = BC_OP_BITAND;
456 case NODETYPE_BWOR: if(!op) op = BC_OP_BITOR;
457 case NODETYPE_BWXOR: if(!op) op = BC_OP_BITXOR;
458 case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
459 case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
460 case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
461 ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
463 ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
466 Bytecode_AppendBinOp(Block->Handle, op);
471 // AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
475 #if TRACE_NODE_RETURNS
476 if(ret && ret != ERRPTR) {
477 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
480 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
488 * \brief Define a variable
489 * \param Block Current block state
490 * \param Type Type of the variable
491 * \param Name Name of the variable
492 * \return Boolean Failure
494 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
497 tAST_Variable *var, *prev = NULL;
499 for( var = Block->FirstVar; var; prev = var, var = var->Next )
501 if( strcmp(var->Name, Name) == 0 ) {
502 AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
507 var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
510 strcpy(var->Name, Name);
512 if(prev) prev->Next = var;
513 else Block->FirstVar = var;
517 Bytecode_AppendDefineVar(Block->Handle, Name, Type);
522 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
525 tAST_Variable *var = NULL;
528 if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
529 var = VarNode->ValueCache;
530 #if TRACE_VAR_LOOKUPS
531 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
532 VarNode->Variable.Name, var,
533 VarNode->BlockState, VarNode->BlockIdent
540 for( bs = Block; bs; bs = bs->Parent )
542 for( var = bs->FirstVar; var; var = var->Next )
544 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
552 if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
554 var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
558 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
563 #if TRACE_VAR_LOOKUPS
564 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
565 VarNode->Variable.Name, var,
566 Block, Block->Ident);
569 VarNode->ValueCache = var;
570 VarNode->BlockState = Block;
571 VarNode->BlockIdent = Block->Ident;
581 * \brief Set the value of a variable
582 * \return Boolean Failure
584 int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
588 var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
593 Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
598 * \brief Get the value of a variable
600 int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
604 var = BC_Variable_Lookup(Block, VarNode, 0);
607 Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
612 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
617 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
619 fprintf(stderr, "%s: ", Type);
620 va_start(args, Format);
621 vfprintf(stderr, Format, args);
623 fprintf(stderr, "\n");
625 void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
630 fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
632 fprintf(stderr, "error: ");
633 va_start(args, Format);
634 vfprintf(stderr, Format, args);
636 fprintf(stderr, "\n");