#include <stdio.h>
#include <string.h>
#include "ast.h"
+#include <inttypes.h>
-//#define DEBUG_F(v...) printf(v)
-#define DEBUG_F(v...)
+#define TRACE 0
+
+#if TRACE
+# define DEBUG_F(v...) printf(v)
+#else
+# define DEBUG_F(v...)
+#endif
// === IMPORTS ===
extern void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
{
uint8_t Type;
union {
- uint64_t Integer;
- double Real;
+ int64_t Integer;
+ double Real;
tSpiderValue *Reference; // Used for everything else
tSpiderObject *Object;
tSpiderNamespace *Namespace;
AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
return NULL;
default:
+ SpiderScript_ReferenceValue(Ent->Reference);
return Ent->Reference;
}
}
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:
+ if(Ent->Reference)
+ SpiderScript_DereferenceValue(Ent->Reference);
+ Ent->Reference = NULL;
+ break;
+ }
+}
+void Bytecode_int_RefStackValue(tBC_StackEnt *Ent)
+{
+ switch(Ent->Type)
+ {
+ 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:
+ if(Ent->Reference)
+ SpiderScript_ReferenceValue(Ent->Reference);
+ break;
+ }
+}
+
+void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
+{
+ switch(Ent->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ printf("0x%"PRIx64, Ent->Integer);
+ break;
+ case SS_DATATYPE_REAL:
+ printf("%lf", Ent->Real);
+ break;
case SS_DATATYPE_OBJECT:
+ printf("Obj %p", Ent->Object);
break;
default:
- SpiderScript_DereferenceValue(Ent->Reference);
+ printf("*%p", Ent->Reference);
break;
}
}
+#if TRACE
+# define PRINT_STACKVAL(val) Bytecode_int_PrintStackValue(&val)
+#else
+# define PRINT_STACKVAL(val)
+#endif
+
#define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
return ret; \
}
#define PUT_STACKVAL(src) if((ret = Bytecode_int_StackPush(Stack, &src))) { \
- AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
+ AST_RuntimeError(NULL, "Stack push failed, full stack");\
return ret; \
}
#define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
tSpiderValue tmpVal1, tmpVal2; // temp storage
tSpiderValue *pval1, *pval2, *ret_val;
tSpiderNamespace *default_namespace = &Script->Variant->RootNamespace;
+
+ // Initialise local vars
+ for( i = 0; i < local_var_count; i ++ )
+ local_vars[i].Type = ET_NULL;
// Pop off arguments
if( ArgCount > Fcn->ArgumentCount ) return -1;
switch(op->Operation)
{
case BC_OP_NOP:
+ STATE_HDR();
+ DEBUG_F("NOP\n");
break;
// Jumps
case BC_OP_JUMP:
}
STATE_HDR();
DEBUG_F("DEFVAR %i of type %i\n", slot, type);
+ if( local_vars[slot].Type != ET_NULL ) {
+ Bytecode_int_DerefStackValue( &local_vars[slot] );
+ local_vars[slot].Type = ET_NULL;
+ }
memset(&local_vars[slot], 0, sizeof(local_vars[0]));
local_vars[slot].Type = type;
} break;
break;
// Variables
- case BC_OP_LOADVAR:
+ case BC_OP_LOADVAR: {
+ int slot = OP_INDX(op);
STATE_HDR();
- DEBUG_F("LOADVAR %i\n", OP_INDX(op));
- if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
- AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
+ DEBUG_F("LOADVAR %i ", slot);
+ if( slot < 0 || slot >= local_var_count ) {
+ AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
return -1;
}
- PUT_STACKVAL(local_vars[OP_INDX(op)]);
-// DUMP_STACKVAL(local_vars[OP_INDX(op)]);
- break;
- case BC_OP_SAVEVAR:
+ DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
+ PUT_STACKVAL(local_vars[slot]);
+ Bytecode_int_RefStackValue( &local_vars[slot] );
+ } break;
+ case BC_OP_SAVEVAR: {
+ int slot = OP_INDX(op);
STATE_HDR();
- DEBUG_F("SAVEVAR %i\n", OP_INDX(op));
- if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
- AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
+ DEBUG_F("SAVEVAR %i = ", slot);
+ if( slot < 0 || slot >= local_var_count ) {
+ AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
return -1;
}
- GET_STACKVAL(local_vars[OP_INDX(op)]);
- break;
+ DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] ");
+ Bytecode_int_DerefStackValue( &local_vars[slot] );
+ GET_STACKVAL(local_vars[slot]);
+ PRINT_STACKVAL(local_vars[slot]);
+ DEBUG_F("\n");
+ } break;
// Constants:
case BC_OP_LOADINT:
PUT_STACKVAL(val2);
break;
case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
- val2.Integer = val1.Real;
+ val2.Real = val1.Integer;
PUT_STACKVAL(val2);
break;
default: {
case BC_OP_DUPSTACK:
STATE_HDR();
- DEBUG_F("DUPSTACK\n");
+ DEBUG_F("DUPSTACK ");
GET_STACKVAL(val1);
+ PRINT_STACKVAL(val1);
+ DEBUG_F("\n");
PUT_STACKVAL(val1);
PUT_STACKVAL(val1);
+ Bytecode_int_RefStackValue(&val1);
+ break;
+
+ // Discard the top item from the stack
+ case BC_OP_DELSTACK:
+ STATE_HDR();
+ DEBUG_F("DELSTACK\n");
+ GET_STACKVAL(val1);
break;
// Unary Operations
GET_STACKVAL(val1);
pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
+ Bytecode_int_DerefStackValue(&val1);
+
ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
Bytecode_int_SetSpiderValue(&val1, ret_val);
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";
STATE_HDR();
DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
- GET_STACKVAL(val2);
- GET_STACKVAL(val1);
+ GET_STACKVAL(val2); // Right
+ GET_STACKVAL(val1); // Left
+
+ #define PERFORM_NUM_OP(_type, _field) if(val1.Type == _type && val1.Type == val2.Type) { \
+ switch(op->Operation) { \
+ case BC_OP_ADD: val1._field = val1._field + val2._field; break; \
+ case BC_OP_SUBTRACT: val1._field = val1._field - val2._field; break; \
+ case BC_OP_MULTIPLY: val1._field = val1._field * val2._field; break; \
+ case BC_OP_DIVIDE: val1._field = val1._field / val2._field; break; \
+ case BC_OP_EQUALS: val1._field = val1._field == val2._field; break; \
+ case BC_OP_LESSTHAN: val1._field = val1._field < val2._field; break; \
+ case BC_OP_LESSTHANOREQUAL: val1._field = val1._field <= val2._field; break; \
+ case BC_OP_GREATERTHAN: val1._field = val1._field > val2._field; break; \
+ case BC_OP_GREATERTHANOREQUAL: val1._field = val1._field >= val2._field; break; \
+ \
+ case BC_OP_BITAND: val1._field = (int64_t)val1._field & (int64_t)val2._field; break; \
+ case BC_OP_BITOR: val1._field = (int64_t)val1._field | (int64_t)val2._field; break; \
+ case BC_OP_BITXOR: val1._field = (int64_t)val1._field ^ (int64_t)val2._field; break; \
+ case BC_OP_MODULO: val1._field = (int64_t)val1._field % (int64_t)val2._field; break; \
+ default: AST_RuntimeError(NULL, "Invalid operation on datatype %i", _type); nextop = NULL; break;\
+ }\
+ PUT_STACKVAL(val1);\
+ break;\
+ }
+
+ PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer);
+ PERFORM_NUM_OP(SS_DATATYPE_REAL, Real);
+
pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
+ Bytecode_int_DerefStackValue(&val1);
+ Bytecode_int_DerefStackValue(&val2);
+
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);
- Bytecode_int_StackPush(Stack, &val1);
+ 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);
args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
+ 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;
}
// Clean up
// - Delete local vars
- printf("TODO: Clean up local vars\n");
+ for( i = 0; i < local_var_count; i ++ )
+ {
+ if( local_vars[i].Type != ET_NULL )
+ {
+ Bytecode_int_DerefStackValue(&local_vars[i]);
+ }
+ }
// - Restore stack
// printf("TODO: Roll back stack\n");
-// while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
-// {
-// Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
-// }
+ if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
+ Stack->EntryCount --;
+ else
+ {
+ GET_STACKVAL(val1);
+ while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
+ {
+ Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
+ }
+ PUT_STACKVAL(val1);
+ }
return 0;