From: John Hodge Date: Tue, 20 Sep 2011 14:20:50 +0000 (+0800) Subject: SpiderScript - Bytecode now _runs_ still buggy X-Git-Tag: rel0.11~89 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=d5540392ca476276630775b5bfd6e4b4b198239e;p=tpg%2Facess2.git SpiderScript - Bytecode now _runs_ still buggy --- diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.c b/Usermode/Libraries/libspiderscript.so_src/ast.c index 78a54bed..12f9f775 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast.c @@ -194,7 +194,6 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node) // 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); diff --git a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c index ab294705..6b7e038a 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c @@ -14,6 +14,7 @@ #define TRACE_VAR_LOOKUPS 0 #define TRACE_NODE_RETURNS 0 +#define MAX_NAMESPACE_DEPTH 10 // === IMPORTS === extern tSpiderFunction *gpExports_First; @@ -27,11 +28,13 @@ typedef struct sAST_BlockInfo 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); @@ -70,7 +73,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn) 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; @@ -86,7 +89,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn) * \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; @@ -102,17 +105,15 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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 @@ -125,7 +126,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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 @@ -134,9 +135,31 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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; @@ -156,9 +179,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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); @@ -168,53 +191,80 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) // 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 @@ -228,7 +278,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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); @@ -246,27 +296,31 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) // 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); @@ -277,7 +331,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) // 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; @@ -303,7 +357,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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); } @@ -311,8 +365,14 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) // 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 @@ -322,7 +382,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) // 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); @@ -330,16 +390,16 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) // 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); @@ -360,7 +420,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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 --- @@ -371,17 +431,15 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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; @@ -400,11 +458,11 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node) 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; diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode.h b/Usermode/Libraries/libspiderscript.so_src/bytecode.h index e00e2401..bc3c91cd 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode.h +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode.h @@ -7,6 +7,8 @@ #include "bytecode_ops.h" +#define BC_NS_SEPARATOR '@' + typedef struct sBC_Op tBC_Op; typedef struct sBC_Function tBC_Function; @@ -14,11 +16,12 @@ struct sBC_Op { 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; diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c index c718265e..54835aea 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c @@ -18,22 +18,23 @@ // === 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; } @@ -197,7 +198,7 @@ int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *Labe 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); @@ -283,77 +284,97 @@ int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name) // 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) @@ -371,7 +392,9 @@ void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation) 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) @@ -413,6 +436,7 @@ void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type) #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)) } diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h index 9ec6eb51..955049bf 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h @@ -46,6 +46,7 @@ extern void Bytecode_SetLabel(tBC_Function *Handle, int Label); // - 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 @@ -55,7 +56,6 @@ extern void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value); 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 @@ -66,6 +66,7 @@ extern void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, 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); diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h b/Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h index 420684c9..1d15c595 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h @@ -11,51 +11,51 @@ enum eBC_Ops 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, diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index 3d3c76dd..7a94dc42 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -85,7 +85,6 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) tAST_Node *node; tSpiderValue *ret = NULL, *tmpobj; tSpiderValue *op1, *op2; // Binary operations - int cmp; // Used in comparisons int i; switch(Node->Type) @@ -571,113 +570,6 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) 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 %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 (-) @@ -699,6 +591,11 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) 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; @@ -858,6 +755,88 @@ tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int 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) diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c index 64df3a0c..1a74d4c2 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c @@ -13,6 +13,13 @@ #include #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; @@ -32,6 +39,7 @@ struct sBC_StackEnt double Real; tSpiderValue *Reference; // Used for everything else tSpiderObject *Object; + tSpiderNamespace *Namespace; }; }; @@ -82,24 +90,37 @@ int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent) 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; @@ -108,6 +129,11 @@ tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp) 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: @@ -124,12 +150,34 @@ void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value) 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) @@ -156,7 +204,10 @@ tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function * 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 @@ -165,10 +216,32 @@ tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function * 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 */ @@ -177,13 +250,15 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t 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 --; @@ -199,29 +274,42 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t // 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 @@ -229,17 +317,183 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t 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); @@ -249,11 +503,81 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t 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; @@ -261,9 +585,14 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t // 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; diff --git a/Usermode/include/spiderscript.h b/Usermode/include/spiderscript.h index c87a0e50..4a492edc 100644 --- a/Usermode/include/spiderscript.h +++ b/Usermode/include/spiderscript.h @@ -245,11 +245,29 @@ extern tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script, 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