return NULL;
}
+ Bytecode_AppendConstInt(ret, 0); // TODO: NULL
+ Bytecode_AppendReturn(ret);
Fcn->BCFcn = ret;
return ret;
}
+// Indepotent operation
+#define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
+ if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
+ Bytecode_AppendDelete(Block->Handle);\
+} } while(0)
+
/**
* \brief Convert a node into bytecode
* \param Block Execution context
tAST_Node *node;
int ret = 0;
int i, op = 0;
- int bAddedValue = 1;
+ int bAddedValue = 1; // Used to tell if the value needs to be deleted
switch(Node->Type)
{
}
}
Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
- bAddedValue = 0;
break;
// Assignment
Bytecode_AppendDuplicate(Block->Handle);
// Set the variable value
ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
- bAddedValue = 0;
break;
// Post increment/decrement
case NODETYPE_POSTINC:
case NODETYPE_POSTDEC:
- Bytecode_AppendConstInt(Block->Handle, 1);
-
// TODO: Support assigning to object attributes
if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
return -1;
}
+ // Save original value if requested
+ if(bKeepValue) {
+ ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
+ if(ret) return ret;
+ }
+
+ Bytecode_AppendConstInt(Block->Handle, 1);
+
ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
if(ret) return ret;
Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
if(ret) return ret;
+
ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
if(ret) return ret;
+ // Doesn't push unless needed
break;
// Function Call
case NODETYPE_FUNCTIONCALL:
case NODETYPE_CREATEOBJECT: {
int nargs = 0;
+
+ // Put the object earlier on the stack to the arguments (for exec)
+ if( Node->Type == NODETYPE_METHODCALL ) {
+ ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
+ if(ret) return ret;
+ }
+
for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
{
ret = AST_ConvertNode(Block, node, 1);
if( Node->Type == NODETYPE_METHODCALL )
{
// TODO: Sanity check stack top
- ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
- if(ret) return ret;
Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
}
else
Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
}
}
+ CHECK_IF_NEEDED(0); // Don't warn
+ // TODO: Implement warn_unused_ret
} break;
// Conditional
// End
Bytecode_SetLabel(Block->Handle, if_end);
- bAddedValue = 0;
} break;
// Loop
Block->BreakTarget = saved_break;
Block->ContinueTarget = saved_continue;
Block->Tag = saved_tag;
- bAddedValue = 0;
} break;
// Return
ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
if(ret) return ret;
Bytecode_AppendReturn(Block->Handle);
- bAddedValue = 0;
break;
case NODETYPE_BREAK:
Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
else
Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
- bAddedValue = 0;
} break;
// Define a variable
if(ret) return ret;
Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
}
- bAddedValue = 0;
break;
// Scope
Block->CurNamespaceStack[i] = Node->Scope.Name;
ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
Block->CurNamespaceStack[i] = NULL;
+ CHECK_IF_NEEDED(0); // No warning?
+ // TODO: Will this collide with _CALLFUNCTION etc?
break;
// Variable
case NODETYPE_VARIABLE:
ret = BC_Variable_GetValue( Block, Node );
+ CHECK_IF_NEEDED(1);
break;
// Element of an Object
if(ret) return ret;
Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
+ CHECK_IF_NEEDED(1);
break;
// Cast a value to another
ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
if(ret) return ret;
Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
+ CHECK_IF_NEEDED(1);
break;
// Index into an array
if(ret) return ret;
Bytecode_AppendIndex(Block->Handle);
+ CHECK_IF_NEEDED(1);
break;
// TODO: Implement runtime constants
// Constant Values
case NODETYPE_STRING:
Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
+ CHECK_IF_NEEDED(1);
break;
case NODETYPE_INTEGER:
Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
+ CHECK_IF_NEEDED(1);
break;
case NODETYPE_REAL:
Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
+ CHECK_IF_NEEDED(1);
break;
// --- Operations ---
ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
if(ret) return ret;
Bytecode_AppendUniOp(Block->Handle, op);
+ CHECK_IF_NEEDED(1);
break;
// Logic
if(ret) return ret;
Bytecode_AppendBinOp(Block->Handle, op);
+ CHECK_IF_NEEDED(1);
break;
default:
}
#endif
- if( !bKeepValue && bAddedValue )
- Bytecode_AppendDelete(Block->Handle);
-
return ret;
}