SpiderScript - Moved header to directory, ready to remove from tree
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_bytecode.c
index 780bee5..9de7281 100644 (file)
@@ -41,8 +41,8 @@ struct sBC_StackEnt
 {
        uint8_t Type;
        union {
-               uint64_t        Integer;
-               double          Real;
+               int64_t Integer;
+               double  Real;
                tSpiderValue    *Reference;     // Used for everything else
                tSpiderObject   *Object;
                tSpiderNamespace        *Namespace;
@@ -84,7 +84,7 @@ int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
        case SS_DATATYPE_INTEGER:
                return !!Ent->Integer;
        case SS_DATATYPE_REAL:
-               return (-.5f < Ent->Real && Ent->Real < 0.5f);
+               return !(-.5f < Ent->Real && Ent->Real < 0.5f);
        case SS_DATATYPE_OBJECT:
                return Ent->Object != NULL;
        case ET_FUNCTION_START:
@@ -105,6 +105,7 @@ tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
                        tmp = malloc(sizeof(tSpiderValue));
                        tmp->ReferenceCount = 1;
                } else {
+                       // Stops a stack value from having free() called on it
                        tmp->ReferenceCount = 2;
                }
                break;
@@ -222,7 +223,10 @@ void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
                printf("Obj %p", Ent->Object);
                break;
        default:
-               printf("*%p", Ent->Reference);
+               if( Ent->Reference )
+                       printf("*%p (%i refs)", Ent->Reference, Ent->Reference->ReferenceCount);
+               else
+                       printf("NULL");
                break;
        }
 }
@@ -272,11 +276,14 @@ tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *
                return NULL;
        }
        free(stack);
+       
        ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
        // Ensure it's a heap value
        if(ret == &tmpsval) {
                ret = malloc(sizeof(tSpiderValue));
                memcpy(ret, &tmpsval, sizeof(tSpiderValue));
+               // Set to 2 in _GetSpiderValue, so stack doesn't have free() called
+               ret->ReferenceCount = 1;
        }
 
        return ret;
@@ -303,6 +310,135 @@ tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const c
        return ns;
 }
 
+/**
+ * \brief Call an external function (may recurse into Bytecode_ExecuteFunction, but may not)
+ */
+int Bytecode_int_CallExternFunction(tSpiderScript *Script, tBC_Stack *Stack, tSpiderNamespace *DefaultNS, tBC_Op *op )
+{
+       const char      *name = OP_STRING(op);
+        int    arg_count = OP_INDX(op);
+        int    i, ret = 0;
+       tSpiderValue    *args[arg_count];
+       tSpiderValue    *rv;
+       tBC_StackEnt    val1;
+       const char      *namespaces[] = {NULL}; // TODO: Default/imported namespaces
+
+       DEBUG_F("CALL (general) %s %i args\n", name, arg_count);
+       
+       // Read arguments
+       for( i = arg_count; i --; )
+       {
+               GET_STACKVAL(val1);
+               args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
+               Bytecode_int_DerefStackValue(&val1);
+       }
+       
+       // Call the function etc.
+       if( op->Operation == BC_OP_CALLFUNCTION )
+       {
+               rv = SpiderScript_ExecuteFunction(Script, name, namespaces, arg_count, args, &op->CacheEnt);
+       }
+       else if( op->Operation == BC_OP_CREATEOBJ )
+       {
+               rv = SpiderScript_CreateObject(Script, name, namespaces, arg_count, args);
+       }
+       else if( op->Operation == BC_OP_CALLMETHOD )
+       {
+               tSpiderObject   *obj;
+               GET_STACKVAL(val1);
+               
+               if(val1.Type == SS_DATATYPE_OBJECT)
+                       obj = val1.Object;
+               else if(val1.Type == ET_REFERENCE && val1.Reference && val1.Reference->Type == SS_DATATYPE_OBJECT)
+                       obj = val1.Reference->Object;
+               else {
+                       // Error
+                       AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
+                       return -1;
+               }
+               rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
+               Bytecode_int_DerefStackValue(&val1);
+       }
+       else
+       {
+               AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
+               rv = ERRPTR;
+       }
+       if(rv == ERRPTR) {
+               AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
+               return -1;
+       }
+       // 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);
+
+       #if 0
+       if(!rv) {
+               printf("%s returned NULL\n", name);
+       }
+       if( rv && rv != ERRPTR && rv->ReferenceCount != 1 ) {
+               printf("Return value from %s reference count fail (%i)\n",
+                       name, rv->ReferenceCount);
+       }
+       #endif  
+
+       return 0;
+}
+
+int Bytecode_int_LocalBinOp_Integer(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
+{
+       switch(Operation)
+       {
+       case BC_OP_ADD:         Val1->Integer = Val1->Integer + Val2->Integer;  break;
+       case BC_OP_SUBTRACT:    Val1->Integer = Val1->Integer - Val2->Integer;  break;
+       case BC_OP_MULTIPLY:    Val1->Integer = Val1->Integer * Val2->Integer;  break;
+       case BC_OP_DIVIDE:      Val1->Integer = Val1->Integer / Val2->Integer;  break;
+       
+       case BC_OP_EQUALS:              Val1->Integer = (Val1->Integer == Val2->Integer);       break;
+       case BC_OP_NOTEQUALS:           Val1->Integer = (Val1->Integer != Val2->Integer);       break;
+       case BC_OP_LESSTHAN:            Val1->Integer = (Val1->Integer <  Val2->Integer);       break;
+       case BC_OP_LESSTHANOREQUAL:     Val1->Integer = (Val1->Integer <= Val2->Integer);       break;
+       case BC_OP_GREATERTHAN:         Val1->Integer = (Val1->Integer >  Val2->Integer);       break;
+       case BC_OP_GREATERTHANOREQUAL:  Val1->Integer = (Val1->Integer >= Val2->Integer);       break;
+       
+       case BC_OP_BITAND:      Val1->Integer = Val1->Integer & Val2->Integer;  break;
+       case BC_OP_BITOR:       Val1->Integer = Val1->Integer | Val2->Integer;  break;
+       case BC_OP_BITXOR:      Val1->Integer = Val1->Integer ^ Val2->Integer;  break;
+       case BC_OP_MODULO:      Val1->Integer = Val1->Integer % Val2->Integer;  break;
+       default:        AST_RuntimeError(NULL, "Invalid operation on datatype Integer"); return -1;
+       }
+       return 0;
+}
+
+int Bytecode_int_LocalBinOp_Real(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
+{
+       switch(Operation)
+       {
+       // Real = Real OP Real
+       case BC_OP_ADD:         Val1->Real = Val1->Real + Val2->Real;   return 0;
+       case BC_OP_SUBTRACT:    Val1->Real = Val1->Real - Val2->Real;   return 0;
+       case BC_OP_MULTIPLY:    Val1->Real = Val1->Real * Val2->Real;   return 0;
+       case BC_OP_DIVIDE:      Val1->Real = Val1->Real / Val2->Real;   return 0;
+
+       // Bool/Integer = Real OP Real
+       case BC_OP_EQUALS:              Val1->Integer = (Val1->Real == Val2->Real);     break;
+       case BC_OP_NOTEQUALS:           Val1->Integer = (Val1->Real != Val2->Real);     break;
+       case BC_OP_LESSTHAN:            Val1->Integer = (Val1->Real <  Val2->Real);     break;
+       case BC_OP_LESSTHANOREQUAL:     Val1->Integer = (Val1->Real <= Val2->Real);     break;
+       case BC_OP_GREATERTHAN:         Val1->Integer = (Val1->Real >  Val2->Real);     break;
+       case BC_OP_GREATERTHANOREQUAL:  Val1->Integer = (Val1->Real >= Val2->Real);     break;
+       
+       default:        AST_RuntimeError(NULL, "Invalid operation on datatype Real"); return -1;
+       }
+       Val1->Type = SS_DATATYPE_INTEGER;       // Becomes logical
+       return 0;
+}
+
 #define STATE_HDR()    DEBUG_F("%p %2i ", op, Stack->EntryCount)
 
 /**
@@ -326,6 +462,7 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
        // Pop off arguments
        if( ArgCount > Fcn->ArgumentCount )     return -1;
        DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
+       // - Handle optional arguments
        for( i = Fcn->ArgumentCount; i > ArgCount; )
        {
                i --;
@@ -359,7 +496,6 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                // Jumps
                case BC_OP_JUMP:
                        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;
@@ -412,29 +548,119 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                        break;
 
                // Variables
-               case BC_OP_LOADVAR:
+               case BC_OP_LOADVAR: {
+                        int    slot = OP_INDX(op);
                        STATE_HDR();
-                       DEBUG_F("LOADVAR %i ", OP_INDX(op));
-                       if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
-                               AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
+                       DEBUG_F("LOADVAR %i ", slot);
+                       if( slot < 0 || slot >= local_var_count ) {
+                               AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
                                return -1;
                        }
-                       DEBUG_F("("); PRINT_STACKVAL(local_vars[OP_INDX(op)]); DEBUG_F(")\n");
-                       PUT_STACKVAL(local_vars[OP_INDX(op)]);
-                       Bytecode_int_RefStackValue( &local_vars[OP_INDX(op)] );
-                       break;
-               case BC_OP_SAVEVAR:
+                       DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
+                       PUT_STACKVAL(local_vars[slot]);
+                       Bytecode_int_RefStackValue( &local_vars[slot] );
+                       } break;
+               case BC_OP_SAVEVAR: {
+                        int    slot = OP_INDX(op);
                        STATE_HDR();
-                       DEBUG_F("SAVEVAR %i = ", OP_INDX(op));
-                       if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
-                               AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
+                       DEBUG_F("SAVEVAR %i = ", slot);
+                       if( slot < 0 || slot >= local_var_count ) {
+                               AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
                                return -1;
                        }
-                       DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[OP_INDX(op)]); DEBUG_F("] ");
-                       Bytecode_int_DerefStackValue( &local_vars[OP_INDX(op)] );
-                       GET_STACKVAL(local_vars[OP_INDX(op)]);
-                       PRINT_STACKVAL(local_vars[OP_INDX(op)]);
+                       // Remove whatever was in there before
+                       DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] ");
+                       Bytecode_int_DerefStackValue( &local_vars[slot] );
+                       // Place new in
+                       GET_STACKVAL(local_vars[slot]);
+                       PRINT_STACKVAL(local_vars[slot]);
                        DEBUG_F("\n");
+                       } break;
+
+               // Array index (get or set)
+               case BC_OP_INDEX:
+               case BC_OP_SETINDEX:
+                       STATE_HDR();
+                       GET_STACKVAL(val1);     // Index
+                       // TODO: Check that index is an integer
+                       if( val1.Type != SS_DATATYPE_INTEGER ) {
+                               nextop = NULL;
+                               break;
+                       }
+
+                       // Get array as raw spider value
+                       GET_STACKVAL(val2);     // Array
+                       pval1 = Bytecode_int_GetSpiderValue(&val2, &tmpVal1);
+                       Bytecode_int_DerefStackValue(&val2);
+
+                       if( op->Operation == BC_OP_SETINDEX ) {
+                               GET_STACKVAL(val2);
+                               pval2 = Bytecode_int_GetSpiderValue(&val2, NULL);
+                               Bytecode_int_DerefStackValue(&val2);
+                               
+                               DEBUG_F("SETINDEX %i ", val1.Integer); PRINT_STACKVAL(val2); DEBUG_F("\n");
+                       
+                               ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, pval2);
+                               if(ret_val == ERRPTR) { nextop = NULL; break; }
+                               SpiderScript_DereferenceValue(pval2);
+                       }
+                       else {
+                               DEBUG_F("INDEX %i ", val1.Integer);
+                               ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, ERRPTR);
+                               if(ret_val == ERRPTR) { nextop = NULL; break; }
+                               
+                               Bytecode_int_SetSpiderValue(&val1, ret_val);
+                               SpiderScript_DereferenceValue(ret_val);
+                               PUT_STACKVAL(val1);
+
+                               DEBUG_F("[Got "); PRINT_STACKVAL(val1); DEBUG_F("]\n");
+
+                       }
+                       // Dereference the array (or object, ...)
+                       if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
+                       break;
+               
+               // Object element (get or set)
+               case BC_OP_ELEMENT:
+               case BC_OP_SETELEMENT:
+                       STATE_HDR();
+                       
+                       GET_STACKVAL(val1);
+                       // - Integers/Reals can't have elements :)
+                       if( val1.Type != ET_REFERENCE ) {
+                               nextop = NULL;
+                               break;
+                       }
+
+                       pval1 = Bytecode_int_GetSpiderValue(&val1, NULL);
+                       Bytecode_int_DerefStackValue(&val1);
+
+                       if( op->Operation == BC_OP_SETELEMENT ) {
+                               GET_STACKVAL(val2);
+                               pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
+                               Bytecode_int_DerefStackValue(&val2);
+                               
+                               DEBUG_F("SETELEMENT %s ", OP_STRING(op)); PRINT_STACKVAL(val2); DEBUG_F("\n");
+
+                               ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), pval2);
+                               if(ret_val == ERRPTR) { nextop = NULL; break; }
+                               
+                               if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
+                       }
+                       else {
+                               DEBUG_F("ELEMENT %s ", OP_STRING(op));
+                               
+                               ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), ERRPTR);
+                               if(ret_val == ERRPTR) { nextop = NULL; break; }
+
+                               Bytecode_int_SetSpiderValue(&val2, ret_val);
+                               SpiderScript_DereferenceValue(ret_val);
+                               PUT_STACKVAL(val2);
+       
+                               DEBUG_F("[Got "); PRINT_STACKVAL(val2); DEBUG_F("]\n");
+                       }
+                       
+                       SpiderScript_DereferenceValue(pval1);
                        break;
 
                // Constants:
@@ -459,6 +685,13 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                        val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
                        PUT_STACKVAL(val1);
                        break;
+               case BC_OP_LOADNULL:
+                       STATE_HDR();
+                       DEBUG_F("LOADNULL\n");
+                       val1.Type = ET_REFERENCE;
+                       val1.Reference = NULL;
+                       PUT_STACKVAL(val1);
+                       break;
 
                case BC_OP_CAST:
                        STATE_HDR();
@@ -469,25 +702,26 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                                PUT_STACKVAL(val1);
                                break;
                        }
-                       switch(val2.Type * 100 + val1.Type )
-                       {
-                       case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
+                       if( val2.Type == SS_DATATYPE_INTEGER && val1.Type == SS_DATATYPE_REAL ) {
                                val2.Integer = val1.Real;
-                               PUT_STACKVAL(val2);
-                               break;
-                       case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
+                       }
+                       else if( val2.Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_INTEGER ) {
                                val2.Real = val1.Integer;
-                               PUT_STACKVAL(val2);
-                               break;
-                       default: {
+                       }
+                       else {
                                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;
+                               
+                               if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
+                               Bytecode_int_DerefStackValue(&val1);
+//                             printf("CAST (%x->%x) - Original %i references remaining\n",
+//                                     pval1->Type, OP_INDX(op),
+//                                     pval1->ReferenceCount);
                        }
+                       PUT_STACKVAL(val2);
                        break;
 
                case BC_OP_DUPSTACK:
@@ -519,11 +753,14 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                        Bytecode_int_StackPush(Stack, &val2);
                        Bytecode_int_DerefStackValue(&val1);
                        break;
+               
                case BC_OP_BITNOT:
-                       if(!ast_op)     ast_op = NODETYPE_BWNOT;
+                       if(!ast_op)     ast_op = NODETYPE_BWNOT,        opstr = "BITNOT";
+               case BC_OP_NEG:
+                       if(!ast_op)     ast_op = NODETYPE_NEGATE,       opstr = "NEG";
 
                        STATE_HDR();
-                       DEBUG_F("UNIOP %i\n", ast_op);
+                       DEBUG_F("%s\n", opstr);
 
                        GET_STACKVAL(val1);
                        pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
@@ -598,6 +835,8 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
 
                case BC_OP_EQUALS:
                        if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
+               case BC_OP_NOTEQUALS:
+                       if(!ast_op)     ast_op = NODETYPE_NOTEQUALS,    opstr = "NOTEQUALS";
                case BC_OP_LESSTHAN:
                        if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
                case BC_OP_LESSTHANOREQUAL:
@@ -613,36 +852,36 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                        GET_STACKVAL(val2);     // Right
                        GET_STACKVAL(val1);     // Left
 
-                       #define PERFORM_NUM_OP(_type, _field) if(val1.Type == _type && val1.Type == val2.Type) { \
-                               switch(op->Operation) { \
-                               case BC_OP_ADD: val1._field = val1._field + val2._field;        break; \
-                               case BC_OP_SUBTRACT:    val1._field = val1._field - val2._field;        break; \
-                               case BC_OP_MULTIPLY:    val1._field = val1._field * val2._field;        break; \
-                               case BC_OP_DIVIDE:      val1._field = val1._field / val2._field;        break; \
-                               case BC_OP_EQUALS:      val1._field = val1._field == val2._field;       break; \
-                               case BC_OP_LESSTHAN:    val1._field = val1._field < val2._field;        break; \
-                               case BC_OP_LESSTHANOREQUAL:     val1._field = val1._field <= val2._field;       break; \
-                               case BC_OP_GREATERTHAN: val1._field = val1._field > val2._field;        break; \
-                               case BC_OP_GREATERTHANOREQUAL:  val1._field = val1._field >= val2._field;       break; \
-                               \
-                               case BC_OP_BITAND:      val1._field = (int64_t)val1._field & (int64_t)val2._field;      break; \
-                               case BC_OP_BITOR:       val1._field = (int64_t)val1._field | (int64_t)val2._field;      break; \
-                               case BC_OP_BITXOR:      val1._field = (int64_t)val1._field ^ (int64_t)val2._field;      break; \
-                               case BC_OP_MODULO:      val1._field = (int64_t)val1._field % (int64_t)val2._field;      break; \
-                               default:        AST_RuntimeError(NULL, "Invalid operation on datatype %i", _type); nextop = NULL; break;\
-                               }\
-                               PUT_STACKVAL(val1);\
-                               break;\
+                       DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")");
+                       DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n");
+
+                       // Perform integer operations locally
+                       if( val1.Type == SS_DATATYPE_INTEGER && val2.Type == SS_DATATYPE_INTEGER )
+                       {
+                               if( Bytecode_int_LocalBinOp_Integer(op->Operation, &val1, &val2) ) {
+                                       nextop = NULL;
+                                       break;
+                               }
+                               PUT_STACKVAL(val1);
+                               break;
                        }
 
-                       PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer);
-                       PERFORM_NUM_OP(SS_DATATYPE_REAL, Real);
+                       if(val1. Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_REAL )
+                       {
+                               if( Bytecode_int_LocalBinOp_Real(op->Operation, &val1, &val2) ) {
+                                       nextop = NULL;
+                                       break;
+                               }
+                               PUT_STACKVAL(val1);
+                               break;
+                       }
                
                        pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
                        pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
                        Bytecode_int_DerefStackValue(&val1);
                        Bytecode_int_DerefStackValue(&val2);
 
+                       // Hand to AST execution code
                        ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
                        if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
                        if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
@@ -660,16 +899,15 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                // Functions etc
                case BC_OP_CREATEOBJ:
                case BC_OP_CALLFUNCTION:
-               case BC_OP_CALLMETHOD: {
-                       tScript_Function        *fcn = NULL;
-                       const char      *name = OP_STRING(op);
-                        int    arg_count = OP_INDX(op);
-                       
+               case BC_OP_CALLMETHOD:
                        STATE_HDR();
-                       DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
 
                        if( op->Operation == BC_OP_CALLFUNCTION )
                        {
+                               tScript_Function        *fcn = NULL;
+                               const char      *name = OP_STRING(op);
+                                int    arg_count = OP_INDX(op);
+                               DEBUG_F("CALL (local) %s %i args\n", name, arg_count);
                                // Check current script functions (for fast call)
                                for(fcn = Script->Functions; fcn; fcn = fcn->Next)
                                {
@@ -684,82 +922,17 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
                                        break;
                                }
                        }
-                       
+               
                        // Slower call
-                       {
-                               tSpiderNamespace        *ns = NULL;
-                               tSpiderValue    *args[arg_count];
-                               tSpiderValue    *rv;
-                               // Read arguments
-                               for( i = arg_count; i --; )
-                               {
-                                       GET_STACKVAL(val1);
-                                       args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
-                                       Bytecode_int_DerefStackValue(&val1);
-                               }
-                               
-                               // Resolve namespace into pointer
-                               if( op->Operation != BC_OP_CALLMETHOD ) {
-                                       if( name[0] == BC_NS_SEPARATOR ) {
-                                               name ++;
-                                               ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
-                                       }
-                                       else {
-                                               // TODO: Support multiple default namespaces
-                                               ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
-                                       }
-                               }
-                               
-                               // Call the function etc.
-                               if( op->Operation == BC_OP_CALLFUNCTION )
-                               {
-                                       rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
-                               }
-                               else if( op->Operation == BC_OP_CREATEOBJ )
-                               {
-                                       rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
-                               }
-                               else if( op->Operation == BC_OP_CALLMETHOD )
-                               {
-                                       tSpiderObject   *obj;
-                                       GET_STACKVAL(val1);
-                                       
-                                       if(val1.Type == SS_DATATYPE_OBJECT)
-                                               obj = val1.Object;
-                                       else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT)
-                                               obj = val1.Reference->Object;
-                                       else {
-                                               // Error
-                                               AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
-                                               nextop = NULL;
-                                               break;
-                                       }
-                                       rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
-                                       Bytecode_int_DerefStackValue(&val1);
-                               }
-                               else
-                               {
-                                       AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
-                                       rv = ERRPTR;
-                               }
-                               if(rv == ERRPTR) {
-                                       AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
-                                       nextop = NULL;
-                                       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);
+                       if( Bytecode_int_CallExternFunction( Script, Stack, default_namespace, op ) ) {
+                               nextop = NULL;
+                               break;
                        }
-                       break;
+                       break;
 
                case BC_OP_RETURN:
                        STATE_HDR();
+
                        DEBUG_F("RETURN\n");
                        nextop = NULL;
                        break;
@@ -780,22 +953,29 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t
        {
                if( local_vars[i].Type != ET_NULL )
                {
+                       DEBUG_F("Var %i - ", i); 
+                       PRINT_STACKVAL(local_vars[i]);
                        Bytecode_int_DerefStackValue(&local_vars[i]);
+                       DEBUG_F("\n");
                }
+               else
+                       DEBUG_F("Var %i - empty\n", i);
        }
        
        // - Restore stack
-//     printf("TODO: Roll back stack\n");
        if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
                Stack->EntryCount --;
        else
        {
+                int    n_rolled = 1;
                GET_STACKVAL(val1);
                while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
                {
                        Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
+                       n_rolled ++;
                }
                PUT_STACKVAL(val1);
+               DEBUG_F("Rolled back %i entries\n", n_rolled);
        }
        
 

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