SpiderScript - Restructured to be able to keep bytecode and AST in memory at one...
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_bytecode.c
index b938424..e240116 100644 (file)
@@ -2,32 +2,34 @@
  * SpiderScript Library
  * by John Hodge (thePowersGang)
  * 
- * bytecode_makefile.c
- * - Generate a bytecode file
+ * exec_bytecode.c
+ * - Execute bytecode
  */
 #include <stdlib.h>
-#include "bytecode_ops.h"
+#include <stdint.h>
+#include "common.h"
+#include "bytecode.h"
+#include <string.h>
+#include "ast.h"
 
-typedef sBC_StackEnt   tBC_StackEnt;
+typedef struct sBC_StackEnt    tBC_StackEnt;
+typedef struct sBC_Stack       tBC_Stack;
 
 enum eBC_StackEntTypes
 {
        ET_NULL,        // Start of the stack
-       ET_FUNCTION_START,      // Start of the function
-       ET_INTEGER,     // Integer / Boolean
-       ET_REAL,        // Real number
-       ET_OBJECT,      // Object
+       // SS_DATATYPE_*
+       ET_FUNCTION_START = NUM_SS_DATATYPES,
        ET_REFERENCE    // Reference to a tSpiderValue
 };
 
 struct sBC_StackEnt
 {
-       uint8_t EntType;
-       uint8_t _padding[3];
+       uint8_t Type;
        union {
                uint64_t        Integer;
                double          Real;
-               tSpiderValue    *Reference;
+               tSpiderValue    *Reference;     // Used for everything else
                tSpiderObject   *Object;
        };
 };
@@ -39,6 +41,10 @@ struct sBC_Stack
        tBC_StackEnt    Entries[];
 };
 
+// === PROTOTYPES ===
+tSpiderValue   *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
+ int   Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
+
 // === CODE ===
 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
 {
@@ -56,38 +62,189 @@ int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
        return 0;
 }
 
+int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
+{
+       switch(Ent->Type)
+       {
+       case SS_DATATYPE_INTEGER:
+               return !!Ent->Integer;
+       case SS_DATATYPE_REAL:
+               return (-.5f < Ent->Real && Ent->Real < 0.5f);
+       case SS_DATATYPE_OBJECT:
+               return Ent->Object != NULL;
+       case ET_FUNCTION_START:
+               return -1;
+       default:
+               return SpiderScript_IsValueTrue(Ent->Reference);
+       }
+}
+
+tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
+{
+       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:
+               return NULL;
+       default:
+               return Ent->Reference;
+       }
+}
+
+void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
+{
+       switch(Value->Type)
+       {
+       case SS_DATATYPE_INTEGER:
+               Ent->Type = SS_DATATYPE_INTEGER;
+               Ent->Integer = Value->Integer;
+               break;
+       case SS_DATATYPE_REAL:
+               Ent->Type = SS_DATATYPE_REAL;
+               Ent->Real = Value->Real;
+               break;
+       case SS_DATATYPE_OBJECT:
+               Ent->Type = SS_DATATYPE_OBJECT;
+               Ent->Object = Value->Object;
+               break;
+       default:
+               SpiderScript_ReferenceValue(Value);
+               Ent->Reference = Value;
+               break;
+       }
+}
+
 #define GET_STACKVAL(dst)      if((ret = Bytecode_int_StackPop(Stack, &dst)))    return ret;
+#define OP_INDX(op_ptr)        ((op_ptr)->Content.StringInt.Integer)
+#define OP_STRING(op_ptr)      ((op_ptr)->Content.StringInt.String)
+
+tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
+{
+       const int       stack_size = 100;
+       tSpiderValue    *ret, tmpsval;
+       tBC_Stack       *stack;
+       tBC_StackEnt    val;
+        int    i;
+       
+       stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
+       stack->EntrySpace = stack_size;
+       stack->EntryCount = 0;
+
+       // Push arguments in order (so top is last arg)
+       for( i = 0; i < NArguments; i ++ )
+       {
+               Bytecode_int_SetSpiderValue(&val, Args[i]);
+               Bytecode_int_StackPush(stack, &val);
+       }
+
+       // Call
+       Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
+
+       // Get return value
+       Bytecode_int_StackPop(stack, &val);
+       ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
+       // Ensure it's a heap value
+       if(ret == &tmpsval) {
+               ret = malloc(sizeof(tSpiderValue));
+               memcpy(ret, &tmpsval, sizeof(tSpiderValue));
+       }
+       return ret;
+}
 
-int Bytecode_ExecuteFunction(tBC_Function *Fcn, tBC_Stack *Stack, int ArgCount);
+/**
+ * \brief Execute a bytecode function with a stack
+ */
+int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
 {
+        int    ret, ast_op, i;
        tBC_Op  *op;
        tBC_StackEnt    val1, val2;
-       tBC_StackEnt    local_vars[Fcn->MaxVariableCount+Fcn->ArgumentCount];
+       tBC_StackEnt    local_vars[Fcn->BCFcn->MaxVariableCount];       // Includes arguments
+       tSpiderValue    tmpVal1, tmpVal2;       // temp storage
+       tSpiderValue    *pval1, *pval2, *ret_val;
        
        // Pop off arguments
+       if( ArgCount > Fcn->ArgumentCount )     return -1;
+       for( i = Fcn->ArgumentCount; --i != ArgCount; )
+       {
+               local_vars[i].Integer = 0;
+               local_vars[i].Type = Fcn->Arguments[i].Type;
+       }
+       for( ; i --; )
+       {
+               GET_STACKVAL(local_vars[i]);
+               // TODO: Type checks / enforcing
+       }
        
        // Mark the start
+       memset(&val1, 0, sizeof(val1));
+       val1.Type = ET_FUNCTION_START;
+       Bytecode_int_StackPush(Stack, &val1);
 
        // Execute!
-       op = Fcn->Operations;
+       op = Fcn->BCFcn->Operations;
        while(op)
        {
                tBC_Op  *nextop = op->Next;
-               switch(op->Type)
+               ast_op = 0;
+               switch(op->Operation)
                {
+               // Jumps
                case BC_OP_JUMP:
-                       nextop = Fcn->Labels[op->StringInt.Integer];
+                       nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
                        break;
                case BC_OP_JUMPIF:
                        GET_STACKVAL(val1);
                        if( Bytecode_int_IsStackEntTrue(&val1) )
-                               nextop = Fcn->Labels[op->StringInt.Integer];
+                               nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
                        break;
                case BC_OP_JUMPIFNOT:
                        GET_STACKVAL(val1);
                        if( !Bytecode_int_IsStackEntTrue(&val1) )
-                               nextop = Fcn->Labels[op->StringInt.Integer];
+                               nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
+                       break;
+               
+               // Define variables
+               case BC_OP_DEFINEVAR: {
+                        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;
+                       memset(&local_vars[slot], 0, sizeof(local_vars[0]));
+                       local_vars[slot].Type = type;
+                       } break;
+               
+               // Operations
+               case BC_OP_ADD:
+                       ast_op = NODETYPE_ADD;
+               case BC_OP_SUBTRACT:
+                       if(!ast_op)     ast_op = NODETYPE_SUBTRACT;
+                       
+                       GET_STACKVAL(val2);
+                       GET_STACKVAL(val1);
+                       pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
+                       pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
+                       ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
+                       if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
+                       if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
+                       Bytecode_int_SetSpiderValue(&val1, ret_val);
+                       if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
                        break;
+
                default:
                        // TODO:
                        break;
@@ -96,4 +253,12 @@ int Bytecode_ExecuteFunction(tBC_Function *Fcn, tBC_Stack *Stack, int ArgCount);
        }
        
        // Clean up
+       // - Delete local vars
+
+       
+       // - Restore stack
+       
+
+       return 0;
 }
+

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