// Looping Construct (For loop node)
case NODETYPE_LOOP:
WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
-// printf("Node %p, Loop Tag %p\n", Node, Node->For.Tag);
WRITE_STR(Buffer, Offset, Node->For.Tag);
Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
#define TRACE_VAR_LOOKUPS 0
#define TRACE_NODE_RETURNS 0
+#define MAX_NAMESPACE_DEPTH 10
// === IMPORTS ===
extern tSpiderFunction *gpExports_First;
int BreakTarget;
int ContinueTarget;
+
+ const char *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
} tAST_BlockInfo;
// === PROTOTYPES ===
// Node Traversal
- int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node);
+ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
// Variables
int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
if(!ret) return NULL;
bi.Handle = ret;
- if( AST_ConvertNode(&bi, Fcn->ASTFcn) )
+ if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
{
Bytecode_DeleteFunction(ret);
return NULL;
* \param Block Execution context
* \param Node Node to execute
*/
-int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
+int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
{
tAST_Node *node;
int ret = 0;
case NODETYPE_BLOCK:
Bytecode_AppendEnterContext(Block->Handle); // Create a new block
{
- tAST_BlockInfo blockInfo;
+ tAST_BlockInfo blockInfo = {0};
blockInfo.Parent = Block;
blockInfo.Handle = Block->Handle;
- blockInfo.ContinueTarget = 0;
- blockInfo.BreakTarget = 0;
// Loop over all nodes, or until the return value is set
for(node = Node->Block.FirstChild;
node;
node = node->NextSibling )
{
- AST_ConvertNode(Block, node);
+ AST_ConvertNode(Block, node, 0);
}
}
Bytecode_AppendLeaveContext(Block->Handle); // Leave this context
AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
return -1;
}
- ret = AST_ConvertNode(Block, Node->Assign.Value);
+ ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
if(ret) return ret;
// Perform assignment operation
ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
if(ret) return ret;
- Bytecode_AppendBinOp(Block->Handle, Node->Assign.Operation);
+ switch(Node->Assign.Operation)
+ {
+ // General Binary Operations
+ case NODETYPE_ADD: op = BC_OP_ADD; break;
+ case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT; break;
+ case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY; break;
+ case NODETYPE_DIVIDE: op = BC_OP_DIVIDE; break;
+ case NODETYPE_MODULO: op = BC_OP_MODULO; break;
+ case NODETYPE_BWAND: op = BC_OP_BITAND; break;
+ case NODETYPE_BWOR: op = BC_OP_BITOR; break;
+ case NODETYPE_BWXOR: op = BC_OP_BITXOR; break;
+ case NODETYPE_BITSHIFTLEFT: op = BC_OP_BITSHIFTLEFT; break;
+ case NODETYPE_BITSHIFTRIGHT: op = BC_OP_BITSHIFTRIGHT; break;
+ case NODETYPE_BITROTATELEFT: op = BC_OP_BITROTATELEFT; break;
+
+ default:
+ AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
+ break;
+ }
+ printf("assign, op = %i\n", op);
+ Bytecode_AppendBinOp(Block->Handle, op);
}
+ if( bKeepValue )
+ Bytecode_AppendDuplicate(Block->Handle);
// Set the variable value
ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
break;
if(ret) return ret;
if( Node->Type == NODETYPE_POSTDEC )
- Bytecode_AppendBinOp(Block->Handle, NODETYPE_SUBTRACT);
+ Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
else
- Bytecode_AppendBinOp(Block->Handle, NODETYPE_ADD);
+ Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
if(ret) return ret;
ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
// Function Call
case NODETYPE_METHODCALL:
case NODETYPE_FUNCTIONCALL:
- case NODETYPE_CREATEOBJECT:
- i = 0;
+ case NODETYPE_CREATEOBJECT: {
+ int nargs = 0;
for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
{
- ret = AST_ConvertNode(Block, node);
+ ret = AST_ConvertNode(Block, node, 1);
if(ret) return ret;
- i ++;
+ nargs ++;
}
// Call the function
- if( Node->Type == NODETYPE_CREATEOBJECT )
- {
- // TODO: Sanity check stack top
- Bytecode_AppendCreateObj(Block->Handle, Node->FunctionCall.Name, i);
- }
- else if( Node->Type == NODETYPE_METHODCALL )
+ if( Node->Type == NODETYPE_METHODCALL )
{
// TODO: Sanity check stack top
- ret = AST_ConvertNode(Block, Node->FunctionCall.Object);
+ ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
if(ret) return ret;
- Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, i);
+ Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
}
else
{
- Bytecode_AppendFunctionCall(Block->Handle, Node->FunctionCall.Name, i);
+ int newnamelen = 0;
+ char *manglename;
+ for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
+ newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
+ newnamelen += strlen(Node->FunctionCall.Name) + 1;
+ manglename = alloca(newnamelen);
+ manglename[0] = 0;
+ for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
+ int pos;
+ strcat(manglename, Block->CurNamespaceStack[i]);
+ pos = strlen(manglename);
+ manglename[pos] = BC_NS_SEPARATOR;
+ manglename[pos+1] = '\0';
+ }
+ strcat(manglename, Node->FunctionCall.Name);
+
+ if( Node->Type == NODETYPE_CREATEOBJECT )
+ {
+ // TODO: Sanity check stack top
+ Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
+ }
+ else
+ {
+ Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
+ }
}
- break;
+ } break;
// Conditional
case NODETYPE_IF: {
- int if_true, if_end;
- ret = AST_ConvertNode(Block, Node->If.Condition);
+ int if_end;
+ ret = AST_ConvertNode(Block, Node->If.Condition, 1);
if(ret) return ret;
- if_true = Bytecode_AllocateLabel(Block->Handle);
if_end = Bytecode_AllocateLabel(Block->Handle);
-
- Bytecode_AppendCondJump(Block->Handle, if_true);
- // False
- ret = AST_ConvertNode(Block, Node->If.False);
- if(ret) return ret;
- Bytecode_AppendJump(Block->Handle, if_end);
+ if( Node->If.False->Type != NODETYPE_NOP )
+ {
+ int if_true = Bytecode_AllocateLabel(Block->Handle);
+
+ Bytecode_AppendCondJump(Block->Handle, if_true);
+
+ // False
+ ret = AST_ConvertNode(Block, Node->If.False, 0);
+ if(ret) return ret;
+ Bytecode_AppendJump(Block->Handle, if_end);
+ Bytecode_SetLabel(Block->Handle, if_true);
+ }
+ else
+ {
+ Bytecode_AppendCondJumpNot(Block->Handle, if_end);
+ }
// True
- Bytecode_SetLabel(Block->Handle, if_true);
- ret = AST_ConvertNode(Block, Node->If.True);
+ ret = AST_ConvertNode(Block, Node->If.True, 0);
if(ret) return ret;
// End
const char *saved_tag;
// Initialise
- ret = AST_ConvertNode(Block, Node->For.Init);
+ ret = AST_ConvertNode(Block, Node->For.Init, 0);
if(ret) return ret;
loop_start = Bytecode_AllocateLabel(Block->Handle);
// Check initial condition
if( !Node->For.bCheckAfter )
{
- ret = AST_ConvertNode(Block, Node->For.Condition);
+ ret = AST_ConvertNode(Block, Node->For.Condition, 1);
if(ret) return ret;
- Bytecode_AppendUniOp(Block->Handle, NODETYPE_LOGICALNOT);
+ Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
Bytecode_AppendCondJump(Block->Handle, loop_end);
}
// Code
- ret = AST_ConvertNode(Block, Node->For.Code);
+ ret = AST_ConvertNode(Block, Node->For.Code, 0);
if(ret) return ret;
// Increment
- ret = AST_ConvertNode(Block, Node->For.Increment);
+ ret = AST_ConvertNode(Block, Node->For.Increment, 0);
if(ret) return ret;
// Tail check
if( Node->For.bCheckAfter )
{
- ret = AST_ConvertNode(Block, Node->For.Condition);
+ ret = AST_ConvertNode(Block, Node->For.Condition, 1);
if(ret) return ret;
Bytecode_AppendCondJump(Block->Handle, loop_start);
}
+ else
+ {
+ Bytecode_AppendJump(Block->Handle, loop_start);
+ }
Bytecode_SetLabel(Block->Handle, loop_end);
// Return
case NODETYPE_RETURN:
- ret = AST_ConvertNode(Block, Node->UniOp.Value);
+ ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
if(ret) return ret;
Bytecode_AppendReturn(Block->Handle);
break;
if( Node->DefVar.InitialValue )
{
- ret = AST_ConvertNode(Block, Node->DefVar.InitialValue);
+ ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
if(ret) return ret;
Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
}
// Scope
case NODETYPE_SCOPE:
- Bytecode_AppendSubNamespace(Block->Handle, Node->Scope.Name);
- ret = AST_ConvertNode(Block, Node->Scope.Element);
+ for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
+ if( i == MAX_NAMESPACE_DEPTH ) {
+ AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
+ return 2;
+ }
+ Block->CurNamespaceStack[i] = Node->Scope.Name;
+ ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
+ Block->CurNamespaceStack[i] = NULL;
break;
// Variable
// Element of an Object
case NODETYPE_ELEMENT:
- ret = AST_ConvertNode( Block, Node->Scope.Element );
+ ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
if(ret) return ret;
Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
// Cast a value to another
case NODETYPE_CAST:
- ret = AST_ConvertNode(Block, Node->Cast.Value);
+ ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
if(ret) return ret;
Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
break;
// Index into an array
case NODETYPE_INDEX:
- ret = AST_ConvertNode(Block, Node->BinOp.Left); // Array
+ ret = AST_ConvertNode(Block, Node->BinOp.Left, 1); // Array
if(ret) return ret;
- ret = AST_ConvertNode(Block, Node->BinOp.Right); // Offset
+ ret = AST_ConvertNode(Block, Node->BinOp.Right, 1); // Offset
if(ret) return ret;
Bytecode_AppendIndex(Block->Handle);
Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
break;
case NODETYPE_REAL:
- Bytecode_AppendConstInt(Block->Handle, Node->Constant.Real);
+ Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
break;
// --- Operations ---
if(!op) op = BC_OP_BITNOT;
case NODETYPE_NEGATE: // Negation (-)
if(!op) op = BC_OP_NEG;
- ret = AST_ConvertNode(Block, Node->UniOp.Value);
+ ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
if(ret) return ret;
Bytecode_AppendUniOp(Block->Handle, op);
break;
- case NODETYPE_LOGICALAND: // Logical AND (&&)
- if(!op) op = BC_OP_LOGICAND;
- case NODETYPE_LOGICALOR: // Logical OR (||)
- if(!op) op = BC_OP_LOGICOR;
- case NODETYPE_LOGICALXOR: // Logical XOR (^^)
- if(!op) op = BC_OP_LOGICXOR;
+ // Logic
+ case NODETYPE_LOGICALAND: if(!op) op = BC_OP_LOGICAND;
+ case NODETYPE_LOGICALOR: if(!op) op = BC_OP_LOGICOR;
+ case NODETYPE_LOGICALXOR: if(!op) op = BC_OP_LOGICXOR;
// Comparisons
case NODETYPE_EQUALS: if(!op) op = BC_OP_EQUALS;
case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
case NODETYPE_BITSHIFTLEFT: if(!op) op = BC_OP_BITSHIFTLEFT;
case NODETYPE_BITSHIFTRIGHT: if(!op) op = BC_OP_BITSHIFTRIGHT;
case NODETYPE_BITROTATELEFT: if(!op) op = BC_OP_BITROTATELEFT;
- ret = AST_ConvertNode(Block, Node->BinOp.Left);
+ ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
if(ret) return ret;
- ret = AST_ConvertNode(Block, Node->BinOp.Right);
+ ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
if(ret) return ret;
-
+
Bytecode_AppendBinOp(Block->Handle, op);
break;
#include "bytecode_ops.h"
+#define BC_NS_SEPARATOR '@'
+
typedef struct sBC_Op tBC_Op;
typedef struct sBC_Function tBC_Function;
{
tBC_Op *Next;
int Operation;
- int bUseInteger; // Used for serialisation
+ char bUseInteger; // Used for serialisation
+ char bUseString; // Used for serialisation
union {
struct {
- const char *String;
int Integer;
+ char String[];
} StringInt;
uint64_t Integer;
// === STRUCTURES ===
// === PROTOTYPES ===
-tBC_Op *Bytecode_int_AllocateOp(int Operation);
+tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes);
int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
// === GLOBALS ===
// === CODE ===
-tBC_Op *Bytecode_int_AllocateOp(int Operation)
+tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes)
{
tBC_Op *ret;
- ret = malloc(sizeof(tBC_Op));
+ ret = malloc(sizeof(tBC_Op) + ExtraBytes);
if(!ret) return NULL;
ret->Next = NULL;
ret->Operation = Operation;
ret->bUseInteger = 0;
+ ret->bUseString = (ExtraBytes > 0);
return ret;
}
break;
// Everthing else just gets handled nicely
default:
- if( op->Content.StringInt.String )
+ if( op->bUseString )
_put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
if( op->bUseInteger )
_put_dword(op->Content.StringInt.Integer);
// Get max count (used when executing to get the frame size)
if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
- return Handle->VariableCount - 1;
+// printf("_AddVariable: %s given %i\n", Name, Handle->VariableCount - Handle->CurContextDepth - 1);
+ return Handle->VariableCount - Handle->CurContextDepth - 1;
}
int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
{
- int i;
+ int i, context_depth = Handle->CurContextDepth;
// Get the start of this context
for( i = Handle->VariableCount; i --; )
{
- if( Handle->VariableNames[i] && strcmp(Name, Handle->VariableNames[i]) == 0 )
- return i;
+ if( !Handle->VariableNames[i] ) {
+ context_depth --;
+ continue ;
+ }
+ if( strcmp(Name, Handle->VariableNames[i]) == 0 )
+ return i - context_depth;
}
return -1;
}
#define DEF_BC_NONE(_op) { \
- tBC_Op *op = Bytecode_int_AllocateOp(_op); \
+ tBC_Op *op = Bytecode_int_AllocateOp(_op, 0); \
op->Content.Integer = 0; \
op->bUseInteger = 0; \
Bytecode_int_AppendOp(Handle, op);\
}
+#define DEF_BC_INT(_op, _int) {\
+ tBC_Op *op = Bytecode_int_AllocateOp(_op, 0);\
+ op->Content.StringInt.Integer = _int;\
+ op->bUseInteger = 1;\
+ op->bUseString = 0;\
+ Bytecode_int_AppendOp(Handle, op);\
+}
+
#define DEF_BC_STRINT(_op, _str, _int) { \
- tBC_Op *op = Bytecode_int_AllocateOp(_op);\
+ tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
op->Content.StringInt.Integer = _int;\
- op->Content.StringInt.String = _str;\
+ strcpy(op->Content.StringInt.String, _str);\
op->bUseInteger = 1;\
+ op->bUseString = 1;\
Bytecode_int_AppendOp(Handle, op);\
}
#define DEF_BC_STR(_op, _str) {\
- tBC_Op *op = Bytecode_int_AllocateOp(_op);\
- op->Content.StringInt.String = _str;\
+ tBC_Op *op = Bytecode_int_AllocateOp(_op, strlen(_str));\
+ strcpy(op->Content.StringInt.String, _str);\
op->bUseInteger = 0;\
Bytecode_int_AppendOp(Handle, op);\
}
// --- Flow Control
void Bytecode_AppendJump(tBC_Function *Handle, int Label)
- DEF_BC_STRINT(BC_OP_JUMP, NULL, Label)
+ DEF_BC_INT(BC_OP_JUMP, Label)
void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
- DEF_BC_STRINT(BC_OP_JUMPIF, NULL, Label)
+ DEF_BC_INT(BC_OP_JUMPIF, Label)
+void Bytecode_AppendCondJumpNot(tBC_Function *Handle, int Label)
+ DEF_BC_INT(BC_OP_JUMPIFNOT, Label)
void Bytecode_AppendReturn(tBC_Function *Handle)
DEF_BC_NONE(BC_OP_RETURN);
// --- Variables
void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
- DEF_BC_STRINT(BC_OP_LOADVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
+ DEF_BC_INT(BC_OP_LOADVAR, Bytecode_int_GetVarIndex(Handle, Name))
// DEF_BC_STR(BC_OP_LOADVAR, Name)
void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name) // (Obj->)?var =
- DEF_BC_STRINT(BC_OP_SAVEVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
+ DEF_BC_INT(BC_OP_SAVEVAR, Bytecode_int_GetVarIndex(Handle, Name))
// DEF_BC_STR(BC_OP_SAVEVAR, Name)
// --- Constants
void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
{
- tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
+ tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT, 0);
op->Content.Integer = Value;
Bytecode_int_AppendOp(Handle, op);
}
void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
{
- tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL);
+ tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL, 0);
op->Content.Real = Value;
Bytecode_int_AppendOp(Handle, op);
}
void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
- DEF_BC_STRINT(BC_OP_LOADSTR, Data, Length)
+{
+ tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADSTR, Length+1);
+ op->Content.StringInt.Integer = Length;
+ memcpy(op->Content.StringInt.String, Data, Length);
+ op->Content.StringInt.String[Length] = 0;
+ Bytecode_int_AppendOp(Handle, op);
+}
// --- Indexing / Scoping
-void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name)
- DEF_BC_STR(BC_OP_SCOPE, Name)
void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
DEF_BC_STR(BC_OP_ELEMENT, Name)
void Bytecode_AppendIndex(tBC_Function *Handle)
void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
DEF_BC_NONE(Operation)
void Bytecode_AppendCast(tBC_Function *Handle, int Type)
- DEF_BC_STRINT(BC_OP_CAST, NULL, Type)
+ DEF_BC_INT(BC_OP_CAST, Type)
+void Bytecode_AppendDuplicate(tBC_Function *Handle)
+ DEF_BC_NONE(BC_OP_DUPSTACK);
// Does some bookeeping to allocate variable slots at compile time
void Bytecode_AppendEnterContext(tBC_Function *Handle)
#endif
i = Bytecode_int_AddVariable(Handle, Name);
-
+// printf("Variable %s given slot %i\n", Name, i);
+
DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))
}
// - Flow Control
extern void Bytecode_AppendJump(tBC_Function *Handle, int Label);
extern void Bytecode_AppendCondJump(tBC_Function *Handle, int Label);
+extern void Bytecode_AppendCondJumpNot(tBC_Function *Handle, int Label);
extern void Bytecode_AppendReturn(tBC_Function *Handle);
// - Operation Stack
// > Load/Store
extern void Bytecode_AppendConstReal(tBC_Function *Handle, double Value);
extern void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length);
// > Scoping
-extern void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name); // Pop NS from stack, go to child, push ("" = root)
extern void Bytecode_AppendElement(tBC_Function *Handle, const char *Name); // Obj->SubObj
extern void Bytecode_AppendIndex(tBC_Function *Handle); // Index into an array
// > Function Calls
extern void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation);
extern void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation);
extern void Bytecode_AppendCast(tBC_Function *Handlde, int Type);
+extern void Bytecode_AppendDuplicate(tBC_Function *Handlde);
// - Context
// TODO: Are contexts needed? Should variables be allocated like labels?
extern void Bytecode_AppendEnterContext(tBC_Function *Handle);
BC_OP_JUMPIF,
BC_OP_JUMPIFNOT,
- BC_OP_RETURN,
+ BC_OP_RETURN, // = 4
BC_OP_CALLFUNCTION,
BC_OP_CALLMETHOD,
BC_OP_CREATEOBJ,
- BC_OP_LOADVAR,
+ BC_OP_LOADVAR, // = 8
BC_OP_SAVEVAR,
- BC_OP_LOADINT,
+ BC_OP_LOADINT, // = 10
BC_OP_LOADREAL,
BC_OP_LOADSTR,
- BC_OP_CAST,
+ BC_OP_DUPSTACK, // = 13
+ BC_OP_CAST, //
- BC_OP_SCOPE,
- BC_OP_ELEMENT,
+ BC_OP_ELEMENT, // = 15
BC_OP_INDEX,
- BC_OP_ENTERCONTEXT,
+ BC_OP_ENTERCONTEXT, // = 17
BC_OP_LEAVECONTEXT,
BC_OP_DEFINEVAR,
// Operations
- BC_OP_LOGICNOT,
+ BC_OP_LOGICNOT, // 20
BC_OP_LOGICAND,
BC_OP_LOGICOR,
BC_OP_LOGICXOR,
- BC_OP_BITNOT,
+ BC_OP_BITNOT, // 24
BC_OP_BITAND,
BC_OP_BITOR,
BC_OP_BITXOR,
- BC_OP_BITSHIFTLEFT,
+ BC_OP_BITSHIFTLEFT, // 28
BC_OP_BITSHIFTRIGHT,
BC_OP_BITROTATELEFT,
- BC_OP_NEG,
+ BC_OP_NEG, // 31
BC_OP_ADD,
BC_OP_SUBTRACT,
BC_OP_MULTIPLY,
BC_OP_DIVIDE,
BC_OP_MODULO,
- BC_OP_EQUALS,
+ BC_OP_EQUALS, // 37
BC_OP_NOTEQUALS,
BC_OP_LESSTHAN,
BC_OP_LESSTHANOREQUAL,
tAST_Node *node;
tSpiderValue *ret = NULL, *tmpobj;
tSpiderValue *op1, *op2; // Binary operations
- int cmp; // Used in comparisons
int i;
switch(Node->Type)
SpiderScript_DereferenceValue(op2);
break;
- // Comparisons
- case NODETYPE_EQUALS:
- case NODETYPE_LESSTHAN:
- case NODETYPE_GREATERTHAN:
- case NODETYPE_LESSTHANEQUAL:
- case NODETYPE_GREATERTHANEQUAL:
- op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
- if(op1 == ERRPTR) return ERRPTR;
- op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
- if(op2 == ERRPTR) {
- SpiderScript_DereferenceValue(op1);
- ret = ERRPTR;
- break;
- }
-
- if( !op1 || !op2 ) {
- AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
- if(op1) SpiderScript_DereferenceValue(op1);
- if(op2) SpiderScript_DereferenceValue(op2);
- ret = SpiderScript_CreateInteger( !op1 && !op2 );
- break;
- }
-
- // Convert types
- if( op1->Type != op2->Type ) {
- // If dynamically typed, convert op2 to op1's type
- if(Block->Script->Variant->bImplicitCasts)
- {
- tmpobj = op2;
- op2 = SpiderScript_CastValueTo(op1->Type, op2);
- SpiderScript_DereferenceValue(tmpobj);
- if(op2 == ERRPTR) {
- SpiderScript_DereferenceValue(op1);
- return ERRPTR;
- }
- }
- // If statically typed, this should never happen, but catch it anyway
- else {
- AST_RuntimeError(Node, "Statically typed implicit cast %i <op> %i",
- op1->Type, op2->Type);
- ret = ERRPTR;
- break;
- }
- }
- // Do operation
- switch(op1->Type)
- {
- // - String Compare (does a strcmp, well memcmp)
- case SS_DATATYPE_STRING:
- // Call memcmp to do most of the work
- cmp = memcmp(
- op1->String.Data, op2->String.Data,
- (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
- );
- // Handle reaching the end of the string
- if( cmp == 0 ) {
- if( op1->String.Length == op2->String.Length )
- cmp = 0;
- else if( op1->String.Length < op2->String.Length )
- cmp = 1;
- else
- cmp = -1;
- }
- break;
-
- // - Integer Comparisons
- case SS_DATATYPE_INTEGER:
- if( op1->Integer == op2->Integer )
- cmp = 0;
- else if( op1->Integer < op2->Integer )
- cmp = -1;
- else
- cmp = 1;
- break;
- // - Real Number Comparisons
- case SS_DATATYPE_REAL:
- cmp = (op1->Real - op2->Real) / op2->Real * 10000; // < 0.1% difference is equality
- break;
- default:
- AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type);
- ret = ERRPTR;
- break;
- }
-
- // Free intermediate objects
- SpiderScript_DereferenceValue(op1);
- SpiderScript_DereferenceValue(op2);
-
- // Error check
- if( ret == ERRPTR )
- break;
-
- // Create return
- switch(Node->Type)
- {
- case NODETYPE_EQUALS: ret = SpiderScript_CreateInteger(cmp == 0); break;
- case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break;
- case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break;
- case NODETYPE_LESSTHANEQUAL: ret = SpiderScript_CreateInteger(cmp <= 0); break;
- case NODETYPE_GREATERTHANEQUAL: ret = SpiderScript_CreateInteger(cmp >= 0); break;
- default:
- AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type);
- ret = ERRPTR;
- break;
- }
- break;
-
// General Unary Operations
case NODETYPE_BWNOT: // Bitwise NOT (~)
case NODETYPE_NEGATE: // Negation (-)
case NODETYPE_BITSHIFTLEFT:
case NODETYPE_BITSHIFTRIGHT:
case NODETYPE_BITROTATELEFT:
+ case NODETYPE_EQUALS:
+ case NODETYPE_LESSTHAN:
+ case NODETYPE_GREATERTHAN:
+ case NODETYPE_LESSTHANEQUAL:
+ case NODETYPE_GREATERTHANEQUAL:
// Get operands
op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
if(op1 == ERRPTR) return ERRPTR;
if(Right && Right != preCastValue) free(Right);
return NULL;
}
+
+ // Catch comparisons
+ switch(Operation)
+ {
+ case NODETYPE_EQUALS:
+ case NODETYPE_LESSTHAN:
+ case NODETYPE_GREATERTHAN:
+ case NODETYPE_LESSTHANEQUAL:
+ case NODETYPE_GREATERTHANEQUAL: {
+ int cmp;
+ ret = NULL;
+ // Do operation
+ switch(Left->Type)
+ {
+ // - String Compare (does a strcmp, well memcmp)
+ case SS_DATATYPE_STRING:
+ // Call memcmp to do most of the work
+ cmp = memcmp(
+ Left->String.Data, Right->String.Data,
+ (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length
+ );
+ // Handle reaching the end of the string
+ if( cmp == 0 ) {
+ if( Left->String.Length == Right->String.Length )
+ cmp = 0;
+ else if( Left->String.Length < Right->String.Length )
+ cmp = 1;
+ else
+ cmp = -1;
+ }
+ break;
+
+ // - Integer Comparisons
+ case SS_DATATYPE_INTEGER:
+ if( Left->Integer == Right->Integer )
+ cmp = 0;
+ else if( Left->Integer < Right->Integer )
+ cmp = -1;
+ else
+ cmp = 1;
+ break;
+ // - Real Number Comparisons
+ case SS_DATATYPE_REAL:
+ cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality
+ break;
+ default:
+ AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type);
+ ret = ERRPTR;
+ break;
+ }
+
+ // Error check
+ if( ret != ERRPTR )
+ {
+ if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING)
+ SpiderScript_ReferenceValue(ret = Left);
+ else
+ ret = SpiderScript_CreateInteger(0);
+
+ // Create return
+ switch(Operation)
+ {
+ case NODETYPE_EQUALS: ret->Integer = (cmp == 0); break;
+ case NODETYPE_LESSTHAN: ret->Integer = (cmp < 0); break;
+ case NODETYPE_GREATERTHAN: ret->Integer = (cmp > 0); break;
+ case NODETYPE_LESSTHANEQUAL: ret->Integer = (cmp <= 0); break;
+ case NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0); break;
+ default:
+ AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation);
+ SpiderScript_DereferenceValue(ret);
+ ret = ERRPTR;
+ break;
+ }
+ }
+ if(Right && Right != preCastValue) free(Right);
+ return ret;
+ }
+
+ // Fall through and sort by type instead
+ default:
+ break;
+ }
// Do operation
switch(Left->Type)
#include <string.h>
#include "ast.h"
+//#define DEBUG_F(v...) printf(v)
+#define DEBUG_F(v...)
+
+// === IMPORTS ===
+extern void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
+
+// === TYPES ===
typedef struct sBC_StackEnt tBC_StackEnt;
typedef struct sBC_Stack tBC_Stack;
double Real;
tSpiderValue *Reference; // Used for everything else
tSpiderObject *Object;
+ tSpiderNamespace *Namespace;
};
};
tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
{
+ switch(Ent->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ case SS_DATATYPE_REAL:
+ case SS_DATATYPE_OBJECT:
+ if(!tmp) {
+ tmp = malloc(sizeof(tSpiderValue));
+ tmp->ReferenceCount = 1;
+ } else {
+ tmp->ReferenceCount = 2;
+ }
+ break;
+ default:
+ break;
+ }
switch(Ent->Type)
{
case SS_DATATYPE_INTEGER:
tmp->Type = SS_DATATYPE_INTEGER;
- tmp->ReferenceCount = 2; // Stops it being freed
tmp->Integer = Ent->Integer;
return tmp;
case SS_DATATYPE_REAL:
tmp->Type = SS_DATATYPE_REAL;
- tmp->ReferenceCount = 2; // Stops it being freed
tmp->Real = Ent->Real;
return tmp;
case SS_DATATYPE_OBJECT:
tmp->Type = SS_DATATYPE_OBJECT;
- tmp->ReferenceCount = 2;
tmp->Object = Ent->Object;
return tmp;
case ET_FUNCTION_START:
+ AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
return NULL;
default:
return Ent->Reference;
void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
{
+ if(!Value) {
+ Ent->Type = ET_REFERENCE;
+ Ent->Reference = NULL;
+ return ;
+ }
switch(Value->Type)
{
case SS_DATATYPE_INTEGER:
break;
default:
SpiderScript_ReferenceValue(Value);
+ Ent->Type = ET_REFERENCE;
Ent->Reference = Value;
break;
}
}
-#define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) return ret;
+void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
+{
+ switch(Ent->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ case SS_DATATYPE_REAL:
+ case SS_DATATYPE_OBJECT:
+ break;
+ default:
+ SpiderScript_DereferenceValue(Ent->Reference);
+ break;
+ }
+}
+
+#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");\
+ return ret; \
+}
#define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
#define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
// Get return value
- Bytecode_int_StackPop(stack, &val);
+ if( Bytecode_int_StackPop(stack, &val) ) {
+ free(stack);
+ return NULL;
+ }
free(stack);
ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
// Ensure it's a heap value
memcpy(ret, &tmpsval, sizeof(tSpiderValue));
}
-
return ret;
}
+tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
+{
+ char *pos;
+ tSpiderNamespace *ns = Start;
+ while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
+ {
+ int len = pos - Name;
+ for( ns = ns->FirstChild; ns; ns = ns->Next )
+ {
+ if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
+ break;
+ }
+ if(!ns) {
+ return NULL;
+ }
+ Name += len + 1;
+ }
+ if(FinalName) *FinalName = Name;
+ return ns;
+}
+
+#define STATE_HDR() DEBUG_F("%p %2i ", op, Stack->EntryCount)
+
/**
* \brief Execute a bytecode function with a stack
*/
int ret, ast_op, i;
tBC_Op *op;
tBC_StackEnt val1, val2;
- tBC_StackEnt local_vars[Fcn->BCFcn->MaxVariableCount]; // Includes arguments
+ int local_var_count = Fcn->BCFcn->MaxVariableCount;
+ tBC_StackEnt local_vars[local_var_count]; // Includes arguments
tSpiderValue tmpVal1, tmpVal2; // temp storage
tSpiderValue *pval1, *pval2, *ret_val;
+ tSpiderNamespace *default_namespace = &Script->Variant->RootNamespace;
// Pop off arguments
if( ArgCount > Fcn->ArgumentCount ) return -1;
- printf("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
+ DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
for( i = Fcn->ArgumentCount; i > ArgCount; )
{
i --;
// Mark the start
memset(&val1, 0, sizeof(val1));
val1.Type = ET_FUNCTION_START;
- Bytecode_int_StackPush(Stack, &val1);
+ PUT_STACKVAL(val1);
// Execute!
op = Fcn->BCFcn->Operations;
while(op)
{
- tBC_Op *nextop = op->Next;
+ const char *opstr = "";
+ tBC_Op *nextop = op->Next, *jmp_target;
ast_op = 0;
switch(op->Operation)
{
+ case BC_OP_NOP:
+ break;
// Jumps
case BC_OP_JUMP:
- nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
+ STATE_HDR();
+ // NOTE: Evil, all jumps are off by -1, so fix that
+ jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
+ DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
+ nextop = jmp_target;
break;
case BC_OP_JUMPIF:
+ STATE_HDR();
+ jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
+ DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
GET_STACKVAL(val1);
if( Bytecode_int_IsStackEntTrue(&val1) )
- nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
+ nextop = jmp_target;
break;
case BC_OP_JUMPIFNOT:
+ STATE_HDR();
+ jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
+ DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
GET_STACKVAL(val1);
if( !Bytecode_int_IsStackEntTrue(&val1) )
- nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
+ nextop = jmp_target;
break;
// Define variables
int type, slot;
type = OP_INDX(op) & 0xFFFF;
slot = OP_INDX(op) >> 16;
- if(slot < 0 || slot >= sizeof(local_vars)/sizeof(local_vars[0])) return -1;
+ if(slot < 0 || slot >= local_var_count) {
+ DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
+ return -1;
+ }
+ STATE_HDR();
+ DEBUG_F("DEFVAR %i of type %i\n", slot, type);
memset(&local_vars[slot], 0, sizeof(local_vars[0]));
local_vars[slot].Type = type;
} break;
-
- // Operations
+
+ // Enter/Leave context
+ // - NOP now
+ case BC_OP_ENTERCONTEXT:
+ STATE_HDR();
+ DEBUG_F("ENTERCONTEXT\n");
+ break;
+ case BC_OP_LEAVECONTEXT:
+ STATE_HDR();
+ DEBUG_F("LEAVECONTEXT\n");
+ break;
+
+ // Variables
+ case BC_OP_LOADVAR:
+ 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));
+ return -1;
+ }
+ PUT_STACKVAL(local_vars[OP_INDX(op)]);
+// DUMP_STACKVAL(local_vars[OP_INDX(op)]);
+ break;
+ case BC_OP_SAVEVAR:
+ 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));
+ return -1;
+ }
+ GET_STACKVAL(local_vars[OP_INDX(op)]);
+ break;
+
+ // Constants:
+ case BC_OP_LOADINT:
+ STATE_HDR();
+ DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
+ val1.Type = SS_DATATYPE_INTEGER;
+ val1.Integer = op->Content.Integer;
+ PUT_STACKVAL(val1);
+ break;
+ case BC_OP_LOADREAL:
+ STATE_HDR();
+ DEBUG_F("LOADREAL %lf\n", op->Content.Real);
+ val1.Type = SS_DATATYPE_REAL;
+ val1.Real = op->Content.Real;
+ PUT_STACKVAL(val1);
+ break;
+ case BC_OP_LOADSTR:
+ STATE_HDR();
+ DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
+ val1.Type = SS_DATATYPE_STRING;
+ val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
+ PUT_STACKVAL(val1);
+ break;
+
+ case BC_OP_CAST:
+ STATE_HDR();
+ val2.Type = OP_INDX(op);
+ DEBUG_F("CAST to %i\n", val2.Type);
+ GET_STACKVAL(val1);
+ if(val1.Type == val2.Type) {
+ PUT_STACKVAL(val1);
+ break;
+ }
+ switch(val2.Type * 100 + val1.Type )
+ {
+ case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
+ val2.Integer = val1.Real;
+ PUT_STACKVAL(val2);
+ break;
+ case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
+ val2.Integer = val1.Real;
+ PUT_STACKVAL(val2);
+ break;
+ default: {
+ pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
+ pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
+ if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
+ Bytecode_int_SetSpiderValue(&val2, pval2);
+ SpiderScript_DereferenceValue(pval2);
+ PUT_STACKVAL(val2);
+ } break;
+ }
+ break;
+
+ case BC_OP_DUPSTACK:
+ STATE_HDR();
+ DEBUG_F("DUPSTACK\n");
+ GET_STACKVAL(val1);
+ PUT_STACKVAL(val1);
+ PUT_STACKVAL(val1);
+ break;
+
+ // Unary Operations
+ case BC_OP_LOGICNOT:
+ STATE_HDR();
+ DEBUG_F("LOGICNOT\n");
+
+ GET_STACKVAL(val1);
+ val2.Type = SS_DATATYPE_INTEGER;
+ val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
+ Bytecode_int_StackPush(Stack, &val2);
+ Bytecode_int_DerefStackValue(&val1);
+ break;
+ case BC_OP_BITNOT:
+ if(!ast_op) ast_op = NODETYPE_BWNOT;
+
+ STATE_HDR();
+ DEBUG_F("UNIOP %i\n", ast_op);
+
+ GET_STACKVAL(val1);
+ pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
+ ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
+ if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
+ Bytecode_int_SetSpiderValue(&val1, ret_val);
+ if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
+ Bytecode_int_StackPush(Stack, &val1);
+
+ break;
+
+ // Binary Operations
+ case BC_OP_LOGICAND:
+ if(!ast_op) ast_op = NODETYPE_LOGICALAND, opstr = "LOGICAND";
+ case BC_OP_LOGICOR:
+ if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR";
+ case BC_OP_LOGICXOR:
+ if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR";
+
+ case BC_OP_BITAND:
+ if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND";
+ case BC_OP_BITOR:
+ if(!ast_op) ast_op = NODETYPE_BWOR, opstr = "BITOR";
+ case BC_OP_BITXOR:
+ if(!ast_op) ast_op = NODETYPE_BWXOR, opstr = "BITXOR";
+
+ case BC_OP_BITSHIFTLEFT:
+ if(!ast_op) ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
+ case BC_OP_BITSHIFTRIGHT:
+ if(!ast_op) ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
+ case BC_OP_BITROTATELEFT:
+ if(!ast_op) ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
+
case BC_OP_ADD:
- ast_op = NODETYPE_ADD;
+ if(!ast_op) ast_op = NODETYPE_ADD, opstr = "ADD";
case BC_OP_SUBTRACT:
- if(!ast_op) ast_op = NODETYPE_SUBTRACT;
-
+ if(!ast_op) ast_op = NODETYPE_SUBTRACT, opstr = "SUBTRACT";
+ case BC_OP_MULTIPLY:
+ if(!ast_op) ast_op = NODETYPE_MULTIPLY, opstr = "MULTIPLY";
+ case BC_OP_DIVIDE:
+ if(!ast_op) ast_op = NODETYPE_DIVIDE, opstr = "DIVIDE";
+ case BC_OP_MODULO:
+ if(!ast_op) ast_op = NODETYPE_MODULO, opstr = "MODULO";
+
+ case BC_OP_EQUALS:
+ if(!ast_op) ast_op = NODETYPE_EQUALS, opstr = "EQUALS";
+ case BC_OP_LESSTHAN:
+ if(!ast_op) ast_op = NODETYPE_LESSTHAN, opstr = "LESSTHAN";
+ case BC_OP_LESSTHANOREQUAL:
+ if(!ast_op) ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
+ case BC_OP_GREATERTHAN:
+ if(!ast_op) ast_op = NODETYPE_GREATERTHAN, opstr = "GREATERTHAN";
+ case BC_OP_GREATERTHANOREQUAL:
+ if(!ast_op) ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
+
+ STATE_HDR();
+ DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
+
GET_STACKVAL(val2);
GET_STACKVAL(val1);
pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
Bytecode_int_SetSpiderValue(&val1, ret_val);
if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
+ Bytecode_int_StackPush(Stack, &val1);
+ break;
+
+ // Functions etc
+ case BC_OP_CALLFUNCTION: {
+ tScript_Function *fcn;
+ 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(strcmp(name, fcn->Name) == 0) {
+ 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 ++ )
+ for( i = arg_count; i --; )
+ {
+ GET_STACKVAL(val1);
+ args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
+ }
+
+ 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);
+ if(rv == ERRPTR) {
+ AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
+ nextop = NULL;
+ break;
+ }
+ // Clean up args
+ for( i = arg_count; i --; )
+ SpiderScript_DereferenceValue(args[i]);
+ // Get and push return
+ Bytecode_int_SetSpiderValue(&val1, rv);
+ PUT_STACKVAL(val1);
+ // Deref return
+ SpiderScript_DereferenceValue(rv);
+ }
+ } break;
+
+ case BC_OP_RETURN:
+ STATE_HDR();
+ DEBUG_F("RETURN\n");
+ nextop = NULL;
break;
default:
// TODO:
+ STATE_HDR();
printf("Unknown operation %i\n", op->Operation);
+ nextop = NULL;
break;
}
op = nextop;
// Clean up
// - Delete local vars
-
+ printf("TODO: Clean up local vars\n");
// - 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] );
+// }
return 0;
tSpiderNamespace *Namespace, const char *Function,
int NArguments, tSpiderValue **Arguments
);
+/**
+ * \brief Execute an object method
+ */
+extern tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
+ tSpiderObject *Object, const char *MethodName,
+ int NArguments, tSpiderValue **Arguments
+ );
+/**
+ * \brief Creates an object instance
+ */
+extern tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
+ tSpiderNamespace *Namespace, const char *ClassName,
+ int NArguments, tSpiderValue **Arguments
+ );
/**
* \brief Convert a script to bytecode and save to a file
*/
extern int SpiderScript_SaveBytecode(tSpiderScript *Script, const char *DestFile);
+/**
+ * \brief Save the AST of a script to a file
+ */
+extern int SpiderScript_SaveAST(tSpiderScript *Script, const char *Filename);
/**
* \brief Free a script