SpiderScript - Bytecode now _runs_ still buggy
authorJohn Hodge <[email protected]>
Tue, 20 Sep 2011 14:20:50 +0000 (22:20 +0800)
committerJohn Hodge <[email protected]>
Tue, 20 Sep 2011 14:20:50 +0000 (22:20 +0800)
Usermode/Libraries/libspiderscript.so_src/ast.c
Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c
Usermode/Libraries/libspiderscript.so_src/bytecode.h
Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c
Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h
Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h
Usermode/Libraries/libspiderscript.so_src/exec_ast.c
Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c
Usermode/include/spiderscript.h

index 78a54be..12f9f77 100644 (file)
@@ -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);
index ab29470..6b7e038 100644 (file)
@@ -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;
        
index e00e240..bc3c91c 100644 (file)
@@ -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;
index c718265..54835ae 100644 (file)
 // === 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))
 }
index 9ec6eb5..955049b 100644 (file)
@@ -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);
index 420684c..1d15c59 100644 (file)
@@ -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,
index 3d3c76d..7a94dc4 100644 (file)
@@ -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 <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 (-)
@@ -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)
index 64df3a0..1a74d4c 100644 (file)
 #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;
 
@@ -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;
index c87a0e5..4a492ed 100644 (file)
@@ -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

UCC git Repository :: git.ucc.asn.au