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;
}
case SS_DATATYPE_OBJECT:
Ent->Type = SS_DATATYPE_OBJECT;
Ent->Object = Value->Object;
+ Ent->Object->ReferenceCount ++;
break;
default:
SpiderScript_ReferenceValue(Value);
{
case SS_DATATYPE_INTEGER:
case SS_DATATYPE_REAL:
+ break;
case SS_DATATYPE_OBJECT:
+ if(Ent->Object) {
+ Ent->Object->ReferenceCount --;
+ if(Ent->Object->ReferenceCount == 0) {
+ Ent->Object->Type->Destructor( Ent->Object );
+ }
+// printf("Object %p derefed (obj refcount = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
+ }
+ Ent->Object = NULL;
break;
default:
- SpiderScript_DereferenceValue(Ent->Reference);
+ if(Ent->Reference)
+ SpiderScript_DereferenceValue(Ent->Reference);
+ Ent->Reference = NULL;
break;
}
}
{
case SS_DATATYPE_INTEGER:
case SS_DATATYPE_REAL:
+ break;
case SS_DATATYPE_OBJECT:
+ if(Ent->Object) {
+ Ent->Object->ReferenceCount ++;
+// printf("Object %p referenced (count = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
+ }
break;
default:
- SpiderScript_ReferenceValue(Ent->Reference);
+ if(Ent->Reference)
+ SpiderScript_ReferenceValue(Ent->Reference);
break;
}
}
switch(op->Operation)
{
case BC_OP_NOP:
+ STATE_HDR();
+ DEBUG_F("NOP\n");
break;
// Jumps
case BC_OP_JUMP:
AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
return -1;
}
+ DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[OP_INDX(op)]); DEBUG_F("] ");
+ Bytecode_int_DerefStackValue( &local_vars[OP_INDX(op)] );
+ GET_STACKVAL(local_vars[OP_INDX(op)]);
PRINT_STACKVAL(local_vars[OP_INDX(op)]);
DEBUG_F("\n");
- GET_STACKVAL(local_vars[OP_INDX(op)]);
break;
// Constants:
if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR";
case BC_OP_LOGICXOR:
if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR";
+
+ STATE_HDR();
+ DEBUG_F("%s\n", opstr);
+
+ GET_STACKVAL(val1);
+ GET_STACKVAL(val2);
+
+ switch(op->Operation)
+ {
+ case BC_OP_LOGICAND:
+ i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
+ break;
+ case BC_OP_LOGICOR:
+ i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
+ break;
+ case BC_OP_LOGICXOR:
+ i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
+ break;
+ }
+ Bytecode_int_DerefStackValue(&val1);
+ Bytecode_int_DerefStackValue(&val2);
+
+ val1.Type = SS_DATATYPE_INTEGER;
+ val1.Integer = i;
+ Bytecode_int_StackPush(Stack, &val1);
+ break;
case BC_OP_BITAND:
if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND";
ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
+
+ if(ret_val == ERRPTR) {
+ AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
+ nextop = NULL;
+ break;
+ }
Bytecode_int_SetSpiderValue(&val1, ret_val);
if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
PUT_STACKVAL(val1);
break;
// Functions etc
- case BC_OP_CALLFUNCTION: {
- tScript_Function *fcn;
+ case BC_OP_CREATEOBJ:
+ case BC_OP_CALLFUNCTION:
+ case BC_OP_CALLMETHOD: {
+ tScript_Function *fcn = NULL;
const char *name = OP_STRING(op);
int arg_count = OP_INDX(op);
STATE_HDR();
DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
- // Check current script functions (for fast call)
- for(fcn = Script->Functions; fcn; fcn = fcn->Next)
+ if( op->Operation == BC_OP_CALLFUNCTION )
{
- if(strcmp(name, fcn->Name) == 0) {
+ // Check current script functions (for fast call)
+ for(fcn = Script->Functions; fcn; fcn = fcn->Next)
+ {
+ if(strcmp(name, fcn->Name) == 0) {
+ break;
+ }
+ }
+ if(fcn && fcn->BCFcn)
+ {
+ DEBUG_F(" - Fast call\n");
+ Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
break;
}
}
- if(fcn && fcn->BCFcn)
- {
- DEBUG_F(" - Fast call\n");
- Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
- break;
- }
// Slower call
{
tSpiderNamespace *ns = NULL;
tSpiderValue *args[arg_count];
tSpiderValue *rv;
-// for( i = 0; i < arg_count; i ++ )
+ // Read arguments
for( i = arg_count; i --; )
{
GET_STACKVAL(val1);
Bytecode_int_DerefStackValue(&val1);
}
- if( name[0] == BC_NS_SEPARATOR ) {
- name ++;
- ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
- }
- else {
- // TODO: Support multiple default namespaces
- ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
+ // Resolve namespace into pointer
+ if( op->Operation != BC_OP_CALLMETHOD ) {
+ if( name[0] == BC_NS_SEPARATOR ) {
+ name ++;
+ ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
+ }
+ else {
+ // TODO: Support multiple default namespaces
+ ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
+ }
}
- rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
+ // Call the function etc.
+ if( op->Operation == BC_OP_CALLFUNCTION )
+ {
+ rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
+ }
+ else if( op->Operation == BC_OP_CREATEOBJ )
+ {
+ rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
+ }
+ else if( op->Operation == BC_OP_CALLMETHOD )
+ {
+ tSpiderObject *obj;
+ GET_STACKVAL(val1);
+
+ if(val1.Type == SS_DATATYPE_OBJECT)
+ obj = val1.Object;
+ else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT)
+ obj = val1.Reference->Object;
+ else {
+ // Error
+ AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
+ nextop = NULL;
+ break;
+ }
+ rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
+ Bytecode_int_DerefStackValue(&val1);
+ }
+ else
+ {
+ AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
+ rv = ERRPTR;
+ }
if(rv == ERRPTR) {
AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
nextop = NULL;
default:
// TODO:
STATE_HDR();
- printf("Unknown operation %i\n", op->Operation);
+ AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
nextop = NULL;
break;
}