SpiderScript - Huge changes to introduce bytecode support
authorJohn Hodge <[email protected]>
Sat, 17 Sep 2011 10:21:24 +0000 (18:21 +0800)
committerJohn Hodge <[email protected]>
Sat, 17 Sep 2011 10:21:24 +0000 (18:21 +0800)
- Scripts can be compiled into bytecode (last I checked)
- Still leaks memory
- Bytecode does not yet run

13 files changed:
Usermode/Libraries/libspiderscript.so_src/ast.c
Usermode/Libraries/libspiderscript.so_src/ast.h
Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/bytecode_optimise.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/exec_ast.c
Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/main.c
Usermode/Libraries/libspiderscript.so_src/values.c [new file with mode: 0644]
Usermode/include/spiderscript.h

index 94d697c..ce04195 100644 (file)
@@ -35,6 +35,7 @@ tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name, int Ret
        strcpy(ret->Name, Name);
        ret->Code = NULL;
        ret->Arguments = NULL;
+       ret->ArgumentCount = 0;
        ret->ReturnType = ReturnType;
        
        if(Script->LastFunction == NULL) {
@@ -57,6 +58,7 @@ void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
                Function->Arguments_Last->NextSibling = Node;
                Function->Arguments_Last = Node;
        }
+       Function->ArgumentCount ++;
 }
 
 /**
@@ -193,6 +195,7 @@ 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);
@@ -411,7 +414,7 @@ void AST_FreeNode(tAST_Node *Node)
        case NODETYPE_INTEGER:
        case NODETYPE_REAL:
                if( Node->ValueCache )
-                       Object_Dereference(Node->ValueCache);
+                       SpiderScript_DereferenceValue(Node->ValueCache);
                Node->ValueCache = NULL;
                break;
        }
index 67f7727..aa44862 100644 (file)
@@ -97,6 +97,7 @@ struct sAST_Function
        tAST_Node       *Code;  //!< Function Code
        tAST_Node       *Arguments;     // HACKJOB (Only NODETYPE_DEFVAR is allowed)
        tAST_Node       *Arguments_Last;
+        int    ArgumentCount;
        char    Name[]; //!< Function Name
 };
 
diff --git a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c
new file mode 100644 (file)
index 0000000..5cffd79
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * SpiderScript Library
+ *
+ * AST to Bytecode Conversion
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "ast.h"
+#include "bytecode_gen.h"
+#include "bytecode_ops.h"
+
+#define TRACE_VAR_LOOKUPS      0
+#define TRACE_NODE_RETURNS     0
+
+// === IMPORTS ===
+extern tSpiderFunction *gpExports_First;
+
+// === TYPES ===
+typedef struct sAST_BlockInfo
+{
+       struct sAST_BlockInfo   *Parent;
+       void    *Handle;
+       const char      *Tag;
+
+        int    BreakTarget;
+        int    ContinueTarget;
+} tAST_BlockInfo;
+
+// === PROTOTYPES ===
+// Node Traversal
+ int   AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node);
+// Variables
+ int   BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name);
+ int   BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
+ int   BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode);
+// - Errors
+void   AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
+void   AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
+
+// === GLOBALS ===
+// int giNextBlockIdent = 1;
+
+// === CODE ===
+/**
+ * \brief Convert a function into bytecode
+ */
+tBC_Function *Bytecode_ConvertFunction(tAST_Function *ASTFcn)
+{
+       tBC_Function    *ret;
+       tAST_BlockInfo bi = {0};
+       
+       {
+               tAST_Node *arg;
+                int    i;
+               char    *arg_names[ASTFcn->ArgumentCount];
+                int    arg_types[ASTFcn->ArgumentCount];
+               
+               for(arg = ASTFcn->Arguments; arg; arg = arg->NextSibling)
+               {
+                       arg_names[i] = arg->DefVar.Name;
+                       arg_types[i] = arg->DefVar.DataType;
+               }
+
+               ret = Bytecode_CreateFunction(ASTFcn->Name, ASTFcn->ArgumentCount, arg_names, arg_types);
+               if(!ret)        return NULL;
+       }
+       
+       bi.Handle = ret;
+       if( AST_ConvertNode(&bi, ASTFcn->Code) )
+       {
+               Bytecode_DeleteFunction(ret);
+               return NULL;
+       }
+       return ret;
+}
+
+/**
+ * \brief Convert a node into bytecode
+ * \param Block        Execution context
+ * \param Node Node to execute
+ */
+int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
+{
+       tAST_Node       *node;
+        int    ret = 0;
+        int    i, op = 0;
+       
+       switch(Node->Type)
+       {
+       // No Operation
+       case NODETYPE_NOP:
+               break;
+       
+       // Code block
+       case NODETYPE_BLOCK:
+               Bytecode_AppendEnterContext(Block->Handle);     // Create a new block
+               {
+                       tAST_BlockInfo  blockInfo;
+                       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);
+                       }
+               }
+               Bytecode_AppendLeaveContext(Block->Handle);     // Leave this context
+               break;
+       
+       // Assignment
+       case NODETYPE_ASSIGN:
+               // TODO: Support assigning to object attributes
+               if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
+                       AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
+                       return -1;
+               }
+               ret = AST_ConvertNode(Block, Node->Assign.Value);
+               if(ret) return ret;
+               
+               // Perform assignment operation
+               if( Node->Assign.Operation != NODETYPE_NOP )
+               {
+                       
+                       ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
+                       if(ret) return ret;
+                       Bytecode_AppendBinOp(Block->Handle, Node->Assign.Operation);
+               }
+               
+               // Set the variable value
+               ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
+               break;
+       
+       // Post increment/decrement
+       case NODETYPE_POSTINC:
+       case NODETYPE_POSTDEC:
+               Bytecode_AppendConstInt(Block->Handle, 1);
+               
+               // TODO: Support assigning to object attributes
+               if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
+                       AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
+                       return -1;
+               }
+
+               ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
+               if(ret) return ret;
+
+               if( Node->Type == NODETYPE_POSTDEC )
+                       Bytecode_AppendBinOp(Block->Handle, NODETYPE_SUBTRACT);
+               else
+                       Bytecode_AppendBinOp(Block->Handle, NODETYPE_ADD);
+               if(ret) return ret;
+
+               ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
+               if(ret) return ret;
+               break;
+       
+       // Function Call
+       case NODETYPE_METHODCALL:
+       case NODETYPE_FUNCTIONCALL:
+       case NODETYPE_CREATEOBJECT:
+               i = 0;
+               for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
+               {
+                       ret = AST_ConvertNode(Block, node);
+                       if(ret) return ret;
+                       i ++;
+               }
+               
+               // 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 )
+               {
+                       // TODO: Sanity check stack top
+                       ret = AST_ConvertNode(Block, Node->FunctionCall.Object);
+                       if(ret) return ret;
+                       Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, i);
+               }
+               else
+               {
+                       Bytecode_AppendFunctionCall(Block->Handle, Node->FunctionCall.Name, i);
+               }
+               break;
+       
+       // Conditional
+       case NODETYPE_IF: {
+                int    if_true, if_end;
+               ret = AST_ConvertNode(Block, Node->If.Condition);
+               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);
+               
+               // True
+               Bytecode_SetLabel(Block->Handle, if_true);
+               ret = AST_ConvertNode(Block, Node->If.True);
+               if(ret) return ret;
+
+               // End
+               Bytecode_SetLabel(Block->Handle, if_end);
+               } break;
+       
+       // Loop
+       case NODETYPE_LOOP: {
+                int    loop_start, loop_end;
+                int    saved_break, saved_continue;
+               const char      *saved_tag;
+
+               // Initialise
+               ret = AST_ConvertNode(Block, Node->For.Init);
+               if(ret) return ret;
+               
+               loop_start = Bytecode_AllocateLabel(Block->Handle);
+               loop_end = Bytecode_AllocateLabel(Block->Handle);
+
+               saved_break = Block->BreakTarget;
+               saved_continue = Block->ContinueTarget;
+               saved_tag = Block->Tag;
+               Block->BreakTarget = loop_end;
+               Block->ContinueTarget = loop_end;
+               Block->Tag = Node->For.Tag;
+
+               Bytecode_SetLabel(Block->Handle, loop_start);
+
+               // Check initial condition
+               if( !Node->For.bCheckAfter )
+               {
+                       ret = AST_ConvertNode(Block, Node->For.Condition);
+                       if(ret) return ret;
+                       Bytecode_AppendUniOp(Block->Handle, NODETYPE_LOGICALNOT);
+                       Bytecode_AppendCondJump(Block->Handle, loop_end);
+               }
+       
+               // Code
+               ret = AST_ConvertNode(Block, Node->For.Code);
+               if(ret) return ret;
+               
+               // Increment
+               ret = AST_ConvertNode(Block, Node->For.Increment);
+               if(ret) return ret;
+
+               // Tail check
+               if( Node->For.bCheckAfter )
+               {
+                       ret = AST_ConvertNode(Block, Node->For.Condition);
+                       if(ret) return ret;
+                       Bytecode_AppendCondJump(Block->Handle, loop_start);
+               }
+
+               Bytecode_SetLabel(Block->Handle, loop_end);
+
+               Block->BreakTarget = saved_break;
+               Block->ContinueTarget = saved_continue;
+               Block->Tag = saved_tag;
+               } break;
+       
+       // Return
+       case NODETYPE_RETURN:
+               ret = AST_ConvertNode(Block, Node->UniOp.Value);
+               if(ret) return ret;
+               Bytecode_AppendReturn(Block->Handle);
+               break;
+       
+       case NODETYPE_BREAK:
+       case NODETYPE_CONTINUE: {
+               tAST_BlockInfo  *bi = Block;
+               if( Node->Variable.Name[0] ) {
+                       while(bi && strcmp(bi->Tag, Node->Variable.Name) == 0)  bi = bi->Parent;
+               }
+               if( !bi )       return 1;
+               // TODO: Check if BreakTarget/ContinueTarget are valid
+               if( Node->Type == NODETYPE_BREAK )
+                       Bytecode_AppendJump(Block->Handle, bi->BreakTarget);
+               else
+                       Bytecode_AppendJump(Block->Handle, bi->ContinueTarget);
+               } break;
+       
+       // Define a variable
+       case NODETYPE_DEFVAR:
+               ret = BC_Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name);
+               if(ret) return ret;
+               
+               if( Node->DefVar.InitialValue )
+               {
+                       ret = AST_ConvertNode(Block, Node->DefVar.InitialValue);
+                       if(ret) return ret;
+                       Bytecode_AppendSaveVar(Block->Handle, Node->DefVar.Name);
+               }
+               break;
+       
+       // Scope
+       case NODETYPE_SCOPE:
+               Bytecode_AppendSubNamespace(Block->Handle, Node->Scope.Name);
+               ret = AST_ConvertNode(Block, Node->Scope.Element);
+               break;
+       
+       // Variable
+       case NODETYPE_VARIABLE:
+               ret = BC_Variable_GetValue( Block, Node );
+               break;
+       
+       // Element of an Object
+       case NODETYPE_ELEMENT:
+               ret = AST_ConvertNode( Block, Node->Scope.Element );
+               if(ret) return ret;
+
+               Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
+               break;
+
+       // Cast a value to another
+       case NODETYPE_CAST:
+               ret = AST_ConvertNode(Block, Node->Cast.Value);
+               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
+               if(ret) return ret;
+               ret = AST_ConvertNode(Block, Node->BinOp.Right);        // Offset
+               if(ret) return ret;
+               
+               Bytecode_AppendIndex(Block->Handle);
+               break;
+
+       // TODO: Implement runtime constants
+       case NODETYPE_CONSTANT:
+               // TODO: Scan namespace for constant name
+               AST_RuntimeError(Node, "TODO - Runtime Constants");
+               ret = -1;
+               break;
+       
+       // Constant Values
+       case NODETYPE_STRING:
+               Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
+               break;
+       case NODETYPE_INTEGER:
+               Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
+               break;
+       case NODETYPE_REAL:
+               Bytecode_AppendConstInt(Block->Handle, Node->Constant.Real);
+               break;
+       
+       // --- Operations ---
+       // Boolean Operations
+       case NODETYPE_LOGICALNOT:       // Logical NOT (!)
+               if(!op) op = BC_OP_LOGICNOT;
+       case NODETYPE_BWNOT:    // Bitwise NOT (~)
+               if(!op) op = BC_OP_BITNOT;
+       case NODETYPE_NEGATE:   // Negation (-)
+               if(!op) op = BC_OP_NEG;
+               ret = AST_ConvertNode(Block, Node->UniOp.Value);
+               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;
+       // Comparisons
+       case NODETYPE_EQUALS:   if(!op) op = BC_OP_EQUALS;
+       case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
+       case NODETYPE_GREATERTHAN:      if(!op) op = BC_OP_GREATERTHAN;
+       case NODETYPE_LESSTHANEQUAL:    if(!op) op = BC_OP_LESSTHANOREQUAL;
+       case NODETYPE_GREATERTHANEQUAL: if(!op) op = BC_OP_GREATERTHANOREQUAL;
+       // General Binary Operations
+       case NODETYPE_ADD:      if(!op) op = BC_OP_ADD;
+       case NODETYPE_SUBTRACT: if(!op) op = BC_OP_SUBTRACT;
+       case NODETYPE_MULTIPLY: if(!op) op = BC_OP_MULTIPLY;
+       case NODETYPE_DIVIDE:   if(!op) op = BC_OP_DIVIDE;
+       case NODETYPE_MODULO:   if(!op) op = BC_OP_MODULO;
+       case NODETYPE_BWAND:    if(!op) op = BC_OP_BITAND;
+       case NODETYPE_BWOR:     if(!op) op = BC_OP_BITOR;
+       case NODETYPE_BWXOR:    if(!op) op = BC_OP_BITXOR;
+       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);
+               if(ret) return ret;
+               ret = AST_ConvertNode(Block, Node->BinOp.Right);
+               if(ret) return ret;
+               
+               Bytecode_AppendBinOp(Block->Handle, op);
+               break;
+       
+       //default:
+       //      ret = NULL;
+       //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
+       //      break;
+       }
+
+       #if TRACE_NODE_RETURNS
+       if(ret && ret != ERRPTR) {
+               AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
+       }
+       else {
+               AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
+       }
+       #endif
+
+       return ret;
+}
+
+/**
+ * \brief Define a variable
+ * \param Block        Current block state
+ * \param Type Type of the variable
+ * \param Name Name of the variable
+ * \return Boolean Failure
+ */
+int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
+{
+       #if 0
+       tAST_Variable   *var, *prev = NULL;
+       
+       for( var = Block->FirstVar; var; prev = var, var = var->Next )
+       {
+               if( strcmp(var->Name, Name) == 0 ) {
+                       AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
+                       return ERRPTR;
+               }
+       }
+       
+       var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
+       var->Next = NULL;
+       var->Type = Type;
+       strcpy(var->Name, Name);
+       
+       if(prev)        prev->Next = var;
+       else    Block->FirstVar = var;
+       
+       return var;
+       #else
+       Bytecode_AppendDefineVar(Block->Handle, Name, Type);
+       return 0;
+       #endif
+}
+
+tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
+{
+       #if 0
+       tAST_Variable   *var = NULL;
+       
+       // Speed hack
+       if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
+               var = VarNode->ValueCache;
+               #if TRACE_VAR_LOOKUPS
+               AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
+                       VarNode->Variable.Name, var,
+                       VarNode->BlockState, VarNode->BlockIdent
+                       );
+               #endif
+       }
+       else
+       {
+               tAST_BlockInfo  *bs;
+               for( bs = Block; bs; bs = bs->Parent )
+               {
+                       for( var = bs->FirstVar; var; var = var->Next )
+                       {
+                               if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
+                                       break;
+                       }
+                       if(var) break;
+               }
+               
+               if( !var )
+               {
+                       if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
+                               // Define variable
+                               var = BC_Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
+                       }
+                       else
+                       {
+                               AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
+                               return NULL;
+                       }
+               }
+               
+               #if TRACE_VAR_LOOKUPS
+               AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
+                       VarNode->Variable.Name, var,
+                       Block, Block->Ident);
+               #endif
+               
+               VarNode->ValueCache = var;
+               VarNode->BlockState = Block;
+               VarNode->BlockIdent = Block->Ident;
+       }
+       
+       return var;
+       #else
+       return (void*)1;
+       #endif
+}
+
+/**
+ * \brief Set the value of a variable
+ * \return Boolean Failure
+ */
+int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
+{
+       tAST_Variable   *var;
+       
+       var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
+       if(!var)        return -1;
+
+       // TODO: Check types
+
+       Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
+       return 0;
+}
+
+/**
+ * \brief Get the value of a variable
+ */
+int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
+{
+       tAST_Variable   *var;
+
+       var = BC_Variable_Lookup(Block, VarNode, 0);    
+       if(!var)        return -1;
+       
+       Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
+       return 0;
+}
+
+#if 0
+void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
+{
+       va_list args;
+       
+       if(Node) {
+               fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
+       }
+       fprintf(stderr, "%s: ", Type);
+       va_start(args, Format);
+       vfprintf(stderr, Format, args);
+       va_end(args);
+       fprintf(stderr, "\n");
+}
+void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
+{
+       va_list args;
+       
+       if(Node) {
+               fprintf(stderr, "%s:%i: ", Node->File, Node->Line);
+       }
+       fprintf(stderr, "error: ");
+       va_start(args, Format);
+       vfprintf(stderr, Format, args);
+       va_end(args);
+       fprintf(stderr, "\n");
+}
+#endif
diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c
new file mode 100644 (file)
index 0000000..8ae7f32
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * SpiderScript Library
+ * by John Hodge (thePowersGang)
+ * 
+ * bytecode_gen.c
+ * - Generate bytecode
+ */
+#include <stdlib.h>
+#include <stdint.h>
+#include "bytecode_ops.h"
+#include <stdio.h>
+#include "bytecode_gen.h"
+#include <string.h>
+
+// === IMPORTS ===
+
+// === STRUCTURES ===
+typedef struct sBC_Op  tBC_Op;
+
+struct sBC_Op
+{
+       tBC_Op  *Next;
+        int    Operation;
+        int    bUseInteger;
+       union {
+               struct {
+                       const char *String;
+                        int    Integer;
+               } StringInt;
+               
+               uint64_t        Integer;
+               double  Real;
+       } Content;
+};
+
+struct sBC_Function
+{
+       const char      *Name;
+       
+        int    LabelCount;
+        int    LabelSpace;
+       tBC_Op  **Labels;
+       
+        int    MaxVariableCount;
+       // NOTE: These fields are invalid after compilation
+        int    VariableCount;
+        int    VariableSpace;
+       const char      **VariableNames;        // Only type needs to be stored
+        int    CurContextDepth;        // Used to get the real var count
+
+        int    OperationCount;
+       tBC_Op  *Operations;
+       tBC_Op  *OperationsEnd;
+
+        int    ArgumentCount;
+       struct {
+               char    *Name;
+                int    Type;
+       }       Arguments[];
+};
+
+// === PROTOTYPES ===
+tBC_Op *Bytecode_int_AllocateOp(int Operation);
+
+// === GLOBALS ===
+
+// === CODE ===
+tBC_Op *Bytecode_int_AllocateOp(int Operation)
+{
+       tBC_Op  *ret;
+
+       ret = malloc(sizeof(tBC_Op));
+       if(!ret)        return NULL;
+
+       ret->Next = NULL;
+       ret->Operation = Operation;
+       ret->bUseInteger = 0;
+
+       return ret;
+}
+
+tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **ArgNames, int *ArgTypes)
+{
+       tBC_Function *ret;
+        int    i;
+
+       ret = malloc(sizeof(tBC_Function) + ArgCount*sizeof(ret->Arguments[0]));
+       if(!ret)        return NULL;
+       
+       ret->Name = Name;
+       ret->LabelSpace = ret->LabelCount = 0;
+       ret->Labels = NULL;
+       
+       ret->VariableCount = ret->VariableSpace = 0;
+       ret->VariableNames = NULL;
+
+       ret->OperationCount = 0;
+       ret->Operations = NULL;
+       ret->OperationsEnd = (void*)&ret->Operations;
+
+       ret->ArgumentCount = ArgCount;
+       for( i = 0; i < ArgCount; i ++ )
+       {
+               ret->Arguments[i].Name = strdup(ArgNames[i]);
+               ret->Arguments[i].Type = ArgTypes[i];
+       }
+
+       return ret;
+}
+
+void Bytecode_DeleteFunction(tBC_Function *Fcn)
+{
+       tBC_Op  *op;
+        int    i;
+       for( i = 0; i < Fcn->ArgumentCount; i ++ )
+       {
+               free(Fcn->Arguments[i].Name);
+       }
+       for( op = Fcn->Operations; op; )
+       {
+               tBC_Op  *nextop = op->Next;
+               free(op);
+               op = nextop;
+       }
+       free(Fcn->VariableNames);
+       free(Fcn->Labels);
+       free(Fcn);
+}
+
+int StringList_GetString(tStringList *List, const char *String, int Length)
+{
+        int    strIdx = 0;
+       tString *ent;
+       for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
+       {
+               if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0)     break;
+       }
+       if( ent ) {
+               ent->RefCount ++;
+       }
+       else {
+               ent = malloc(sizeof(tString) + Length + 1);
+               if(!ent)        return -1;
+               ent->Next = NULL;
+               ent->Length = Length;
+               ent->RefCount = 1;
+               memcpy(ent->Data, String, Length);
+               ent->Data[Length] = '\0';
+               
+               if(List->Head)
+                       List->Tail->Next = ent;
+               else
+                       List->Head = ent;
+               List->Tail = ent;
+               List->Count ++;
+       }
+       return strIdx;
+}
+
+int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
+{
+       tBC_Op  *op;
+        int    len = 0, idx = 0;
+        int    i;
+
+       void _put_byte(uint8_t byte)
+       {
+               uint8_t *buf = Output;
+               if(Output)      buf[len] = byte;
+               len ++;
+       }
+
+       void _put_dword(uint32_t value)
+       {
+               uint8_t *buf = Output;
+               if(Output) {
+                       buf[len+0] = value & 0xFF;
+                       buf[len+1] = value >> 8;
+                       buf[len+2] = value >> 16;
+                       buf[len+3] = value >> 24;
+               }
+               len += 4;
+       }
+       
+       void _put_qword(uint64_t value)
+       {
+               _put_dword(value & 0xFFFFFFFF);
+               _put_dword(value >> 32);
+       }
+
+       void _put_double(double value)
+       {
+               // TODO: Machine agnostic
+               if(Output) {
+                       *(double*)( (char*)Output + len ) = value;
+               }
+               len += sizeof(double);
+       }
+
+       void _put_string(const char *str, int len)
+       {
+                int    strIdx = 0;
+               if( Output ) {
+                       strIdx = StringList_GetString(Strings, str, len);
+               }
+       
+               // TODO: Relocations    
+               _put_dword(strIdx);
+       }
+
+       for( op = Function->Operations; op; op = op->Next, idx ++ )
+       {
+               // If first run, convert labels into byte offsets
+               if( !Output )
+               {
+                       for( i = 0; i < Function->LabelCount; i ++ )
+                       {
+                               if(LabelOffsets[i])     continue;
+                               if(op != Function->Labels[i])   continue;
+                               
+                               LabelOffsets[i] = len;
+                       }
+               }
+
+               _put_byte(op->Operation);
+               switch(op->Operation)
+               {
+               // Relocate jumps (the value only matters if `Output` is non-NULL)
+               case BC_OP_JUMP:
+               case BC_OP_JUMPIF:
+               case BC_OP_JUMPIFNOT:
+                       // TODO: Relocations?
+                       _put_dword( LabelOffsets[op->Content.StringInt.Integer] );
+                       break;
+               // Special case for inline values
+               case BC_OP_LOADINT:
+                       _put_qword(op->Content.Integer);
+                       break;
+               case BC_OP_LOADREAL:
+                       _put_double(op->Content.Real);
+                       break;
+               case BC_OP_LOADSTR:
+                       _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
+                       break;
+               // Everthing else just gets handled nicely
+               default:
+                       if( op->Content.StringInt.String )
+                               _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
+                       if( op->bUseInteger )
+                               _put_dword(op->Content.StringInt.Integer);
+                       break;
+               }
+       }
+
+       return len;
+}
+
+char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
+{
+        int    len;
+        int    *label_offsets;
+       char    *code;
+
+       label_offsets = calloc( sizeof(int), Function->LabelCount );
+       if(!label_offsets)      return NULL;
+
+       len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
+
+       code = malloc(len);
+       
+       Bytecode_int_Serialize(Function, code, label_offsets, Strings);
+
+       free(label_offsets);
+
+       *Length = len;
+
+       return code;
+}
+
+int Bytecode_AllocateLabel(tBC_Function *Handle)
+{
+        int    ret;
+       
+       if( Handle->LabelCount == Handle->LabelSpace ) {
+               void *tmp;
+               Handle->LabelSpace += 20;       // TODO: Don't hardcode increment
+               tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
+               if( !tmp ) {
+                       Handle->LabelSpace -= 20;
+                       return -1;
+               }
+               Handle->Labels = tmp;
+       }
+       ret = Handle->LabelCount ++;
+       Handle->Labels[ret] = 0;
+       return ret;
+}
+
+void Bytecode_SetLabel(tBC_Function *Handle, int Label)
+{
+       if(Label < 0)   return ;
+       
+       if(Label >= Handle->LabelCount) return ;
+
+       Handle->Labels[Label] = Handle->OperationsEnd;
+       return ;
+}
+
+void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
+{
+       Op->Next = NULL;
+       if( Fcn->Operations )
+               Fcn->OperationsEnd->Next = Op;
+       else
+               Fcn->Operations = Op;
+       Fcn->OperationsEnd = Op;
+}
+
+void Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
+{
+       if(Handle->VariableCount == Handle->VariableSpace) {
+               void    *tmp;
+               Handle->VariableSpace += 10;
+               tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
+               if(!tmp)        return ;        // TODO: Error
+               Handle->VariableNames = tmp;
+       }
+       Handle->VariableNames[Handle->VariableCount] = Name;
+       Handle->VariableCount ++;
+       // Get max count (used when executing to get the frame size)
+       if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
+               Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
+}
+
+int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
+{
+        int    i;
+       // Get the start of this context
+       for( i = Handle->VariableCount; i --; )
+       {
+               if( Handle->VariableNames[i] == NULL )  break;
+       }
+       // Check for duplicate allocation
+       for( ; i < Handle->VariableCount; i ++ )
+       {
+               if( strcmp(Name, Handle->VariableNames[i]) == 0 )
+                       return i;
+       }
+       return -1;
+}
+
+#define DEF_BC_NONE(_op) { \
+       tBC_Op *op = Bytecode_int_AllocateOp(_op); \
+       op->Content.Integer = 0; \
+       op->bUseInteger = 0; \
+       Bytecode_int_AppendOp(Handle, op);\
+}
+
+#define DEF_BC_STRINT(_op, _str, _int) { \
+       tBC_Op *op = Bytecode_int_AllocateOp(_op);\
+       op->Content.StringInt.Integer = _int;\
+       op->Content.StringInt.String = _str;\
+       op->bUseInteger = 1;\
+       Bytecode_int_AppendOp(Handle, op);\
+}
+#define DEF_BC_STR(_op, _str) {\
+       tBC_Op *op = Bytecode_int_AllocateOp(_op);\
+       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)
+void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
+       DEF_BC_STRINT(BC_OP_JUMPIF, NULL, 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_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_STR(BC_OP_SAVEVAR, Name)
+
+// --- Constants
+void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
+{
+       tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
+       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);
+       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)
+
+// --- 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)
+       DEF_BC_NONE(BC_OP_INDEX)
+
+void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
+       DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
+void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
+       DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
+void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
+       DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
+
+void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
+       DEF_BC_NONE(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)
+
+// Does some bookeeping to allocate variable slots at compile time
+void Bytecode_AppendEnterContext(tBC_Function *Handle)
+{
+       Handle->CurContextDepth ++;
+       Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this    
+
+       DEF_BC_NONE(BC_OP_ENTERCONTEXT)
+}
+void Bytecode_AppendLeaveContext(tBC_Function *Handle)
+{
+        int    i;
+       for( i = Handle->VariableCount; i --; )
+       {
+               if( Handle->VariableNames[i] == NULL )  break;
+       }
+       Handle->CurContextDepth --;
+
+       DEF_BC_NONE(BC_OP_LEAVECONTEXT)
+}
+//void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
+//     DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
+void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
+{
+       #if 1
+       // Check for duplicates
+       if( Bytecode_int_GetVarIndex(Handle, Name) )
+               return ;        // TODO: Error
+       #endif
+
+       Bytecode_int_AddVariable(Handle, Name);
+       
+       DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, Type)
+}
diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.h
new file mode 100644 (file)
index 0000000..b2f19cf
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SpiderScript Library
+ * - By John Hodge (thePowersGang)
+ *
+ * bytecode_gen.h
+ * - Bytecode Generation header
+ */
+#ifndef _BYTECODE_GEN_H_
+#define _BYTECODE_GEN_H_
+
+#include "ast.h"
+
+typedef struct sBC_Function    tBC_Function;
+typedef struct sStringList     tStringList;
+typedef struct sString tString;
+//typedef struct sAST_Function tAST_Function;
+
+struct sString
+{
+       tString *Next;
+        int    Length;
+        int    RefCount;
+       char    Data[];
+};
+
+struct sStringList
+{
+       tString *Head;
+       tString *Tail;
+        int    Count;
+};
+
+
+extern int     Bytecode_ConvertScript(tSpiderScript *Script, const char *DestFile);
+extern tBC_Function    *Bytecode_ConvertFunction(tAST_Function *ASTFcn);
+extern tBC_Function    *Bytecode_NewBlankFunction(void);
+extern void    Bytecode_DeleteFunction(tBC_Function *Fcn);
+
+extern char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings);
+extern int     StringList_GetString(tStringList *List, const char *String, int Length);
+extern tBC_Function    *Bytecode_CreateFunction(const char *Name, int ArgCount, char **ArgNames, int *ArgTypes);
+
+extern int     Bytecode_AllocateLabel(tBC_Function *Handle);
+extern void    Bytecode_SetLabel(tBC_Function *Handle, int Label);
+// Bytecode adding
+// - Flow Control
+extern void    Bytecode_AppendJump(tBC_Function *Handle, int Label);
+extern void    Bytecode_AppendCondJump(tBC_Function *Handle, int Label);
+extern void    Bytecode_AppendReturn(tBC_Function *Handle);
+// - Operation Stack
+//  > Load/Store
+extern void    Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name);
+extern void    Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name); // (Obj->)?var = 
+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
+extern void    Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount);
+extern void    Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount);
+extern void    Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount);
+//  > Manipulation
+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);
+// - Context
+//   TODO: Are contexts needed? Should variables be allocated like labels?
+extern void    Bytecode_AppendEnterContext(tBC_Function *Handle);
+extern void    Bytecode_AppendLeaveContext(tBC_Function *Handle);
+//extern void  Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
+extern void    Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type);
+
+#endif
+
diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_makefile.c
new file mode 100644 (file)
index 0000000..a4c9b71
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * SpiderScript Library
+ * by John Hodge (thePowersGang)
+ * 
+ * bytecode_makefile.c
+ * - Generate a bytecode file
+ */
+#include <stdlib.h>
+#include "ast.h"
+#include "bytecode_gen.h"
+#include <stdio.h>
+#include <string.h>
+
+// === IMPORTS ===
+
+// === PROTOTYPES ===
+
+// === GLOBALS ===
+
+// === CODE ===
+int Bytecode_ConvertScript(tSpiderScript *Script, const char *DestFile)
+{
+       tStringList     strings = {0};
+       tAST_Function   *fcn;
+       FILE    *fp;
+        int    fcn_hdr_offset = 0;
+        int    fcn_count = 0;
+        int    strtab_ofs;
+
+       void _put8(uint8_t val)
+       {
+               fwrite(&val, 1, 1, fp);
+       }
+       void _put32(uint32_t val)
+       {
+               _put8(val & 0xFF);
+               _put8(val >> 8);
+               _put8(val >> 16);
+               _put8(val >> 24);
+       }
+
+       fp = fopen(DestFile, "wb");
+       if(!fp) return 1;
+       
+       // Create header
+       fwrite("SSBC\r\n\xBC\x55", 8, 1, fp);
+       _put32(0);      // Function count, to be filled
+       _put32(0);      // String count
+       _put32(0);      // String table offset
+       // TODO: Variant info
+
+       fcn_hdr_offset = ftell(fp);
+
+       // Create function descriptors
+       for(fcn = Script->Script->Functions; fcn; fcn = fcn->Next, fcn_count ++)
+       {
+               tAST_Node *arg;
+
+               _put32( StringList_GetString(&strings, fcn->Name, strlen(fcn->Name)) );
+               _put32( 0 );    // Code offset
+               _put8( fcn->ReturnType );
+               
+               if(fcn->ArgumentCount > 255) {
+                       // ERROR: Too many args
+                       return 2;
+               }
+               _put8( fcn->ArgumentCount );
+
+               // Argument types?
+               for(arg = fcn->Arguments; arg; arg = arg->NextSibling)
+               {
+                       _put32( StringList_GetString(&strings, arg->DefVar.Name, strlen(arg->DefVar.Name)) );
+                       _put8( arg->DefVar.DataType );
+               }
+       }
+
+       // Put function code in
+       for(fcn = Script->Script->Functions; fcn; fcn = fcn->Next)
+       {
+               char    *code;
+                int    len, code_pos;
+               tBC_Function    *bc_fcn;
+       
+               // Fix header   
+               code_pos = ftell(fp);
+               fseek(fp, SEEK_SET, fcn_hdr_offset + 4);
+               _put32( code_pos );
+               fseek(fp, SEEK_SET, code_pos );
+
+               fcn_hdr_offset += 4+4+1+1+(4+1)*fcn->ArgumentCount;
+               
+               // Write code
+               bc_fcn = Bytecode_ConvertFunction(fcn);
+               code = Bytecode_SerialiseFunction(bc_fcn, &len, &strings);
+               Bytecode_DeleteFunction(bc_fcn);
+               fwrite(code, len, 1, fp);
+       }
+
+       // String table
+       strtab_ofs = ftell(fp);
+       {
+                int    string_offset = strtab_ofs + (4+4)*strings.Count;
+               tString *str;
+               // Array
+               for(str = strings.Head; str; str = str->Next)
+               {
+                       _put32(str->Length);
+                       _put32(string_offset);
+                       string_offset += str->Length + 1;
+               }
+               // Data
+               for(str = strings.Head; str; str = str->Next)
+               {
+                       fwrite(str->Data, str->Length, 1, fp);
+                       _put8(0);
+               }
+       }
+
+       // Fix header
+       fseek(fp, 8, SEEK_SET);
+       _put32(fcn_count);
+       _put32(strings.Count);
+       _put32(strtab_ofs);
+
+       return 0;
+}
+
diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h b/Usermode/Libraries/libspiderscript.so_src/bytecode_ops.h
new file mode 100644 (file)
index 0000000..420684c
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ */
+#ifndef _BYTECODE_OPS_H_
+#define _BYTECODE_OPS_H_
+
+enum eBC_Ops
+{
+       BC_OP_NOP,
+       
+       BC_OP_JUMP,
+       BC_OP_JUMPIF,
+       BC_OP_JUMPIFNOT,
+       
+       BC_OP_RETURN,
+       BC_OP_CALLFUNCTION,
+       BC_OP_CALLMETHOD,
+       BC_OP_CREATEOBJ,        
+       
+       BC_OP_LOADVAR,
+       BC_OP_SAVEVAR,
+
+       BC_OP_LOADINT,
+       BC_OP_LOADREAL,
+       BC_OP_LOADSTR,
+
+       BC_OP_CAST,     
+       
+       BC_OP_SCOPE,
+       BC_OP_ELEMENT,
+       BC_OP_INDEX,
+
+       BC_OP_ENTERCONTEXT,
+       BC_OP_LEAVECONTEXT,
+       BC_OP_DEFINEVAR,
+
+       // Operations
+       BC_OP_LOGICNOT,
+       BC_OP_LOGICAND,
+       BC_OP_LOGICOR,
+       BC_OP_LOGICXOR,
+
+       BC_OP_BITNOT,
+       BC_OP_BITAND,
+       BC_OP_BITOR,
+       BC_OP_BITXOR,
+
+       BC_OP_BITSHIFTLEFT,
+       BC_OP_BITSHIFTRIGHT,
+       BC_OP_BITROTATELEFT,
+
+       BC_OP_NEG,
+       BC_OP_ADD,
+       BC_OP_SUBTRACT,
+       BC_OP_MULTIPLY,
+       BC_OP_DIVIDE,
+       BC_OP_MODULO,
+
+       BC_OP_EQUALS,
+       BC_OP_NOTEQUALS,
+       BC_OP_LESSTHAN,
+       BC_OP_LESSTHANOREQUAL,
+       BC_OP_GREATERTHAN,
+       BC_OP_GREATERTHANOREQUAL
+};
+
+#endif
diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_optimise.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_optimise.c
new file mode 100644 (file)
index 0000000..3da6aa5
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * SpiderScript Library
+ * by John Hodge (thePowersGang)
+ * 
+ * bytecode_gen.c
+ * - Generate bytecode
+ */
+#include <stdlib.h>
+#include "bytecode_ops.h"
+
+// Patterns:
+// TODO: Figure out what optimisations can be done
+
+int Bytecode_OptimizeFunction(tBC_Function *Function)
+{
+       for( op = Function->Operations; op; op = op->Next, idx ++ )
+       {
+       }
+}
index 5ba1554..0c1a402 100644 (file)
 extern tSpiderFunction *gpExports_First;
 
 // === PROTOTYPES ===
-// - Values
-void   Object_Dereference(tSpiderValue *Object);
-void   Object_Reference(tSpiderValue *Object);
-tSpiderValue   *SpiderScript_CreateInteger(uint64_t Value);
-tSpiderValue   *SpiderScript_CreateReal(double Value);
-tSpiderValue   *SpiderScript_CreateString(int Length, const char *Data);
-tSpiderValue   *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
- int   SpiderScript_IsValueTrue(tSpiderValue *Value);
-void   SpiderScript_FreeValue(tSpiderValue *Value);
-char   *SpiderScript_DumpValue(tSpiderValue *Value);
 // - Node Execution
 tSpiderValue   *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
 tSpiderValue   *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
@@ -43,365 +33,6 @@ void        AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
  int   giNextBlockIdent = 1;
 
 // === CODE ===
-/**
- * \brief Dereference a created object
- */
-void Object_Dereference(tSpiderValue *Object)
-{
-       if(!Object)     return ;
-       if(Object == ERRPTR)    return ;
-       Object->ReferenceCount --;
-//     printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount);
-       if( Object->ReferenceCount == 0 ) {
-               switch( (enum eSpiderScript_DataTypes) Object->Type )
-               {
-               case SS_DATATYPE_OBJECT:
-                       Object->Object->Type->Destructor( Object->Object );
-                       break;
-               case SS_DATATYPE_OPAQUE:
-                       Object->Opaque.Destroy( Object->Opaque.Data );
-                       break;
-               default:
-                       break;
-               }
-               free(Object);
-       }
-}
-
-void Object_Reference(tSpiderValue *Object)
-{
-       if(!Object)     return ;
-       Object->ReferenceCount ++;
-//     printf("%p Referenced (%i)\n", Object, Object->ReferenceCount);
-}
-
-/**
- * \brief Allocate and initialise a SpiderScript object
- */
-tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
-{
-        int    size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
-       tSpiderObject   *ret = malloc(size);
-       
-       ret->Type = Class;
-       ret->ReferenceCount = 1;
-       ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
-       memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
-       
-       return ret;
-}
-
-/**
- * \brief Create an integer object
- */
-tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
-{
-       tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
-       ret->Type = SS_DATATYPE_INTEGER;
-       ret->ReferenceCount = 1;
-       ret->Integer = Value;
-       return ret;
-}
-
-/**
- * \brief Create an real number object
- */
-tSpiderValue *SpiderScript_CreateReal(double Value)
-{
-       tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
-       ret->Type = SS_DATATYPE_REAL;
-       ret->ReferenceCount = 1;
-       ret->Real = Value;
-       return ret;
-}
-
-/**
- * \brief Create an string object
- */
-tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
-{
-       tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
-       ret->Type = SS_DATATYPE_STRING;
-       ret->ReferenceCount = 1;
-       ret->String.Length = Length;
-       if( Data )
-               memcpy(ret->String.Data, Data, Length);
-       else
-               memset(ret->String.Data, 0, Length);
-       ret->String.Data[Length] = '\0';
-       return ret;
-}
-
-/**
- * \brief Concatenate two strings
- */
-tSpiderValue *Object_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
-{
-        int    newLen = 0;
-       tSpiderValue    *ret;
-       if(Str1)        newLen += Str1->String.Length;
-       if(Str2)        newLen += Str2->String.Length;
-       ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
-       ret->Type = SS_DATATYPE_STRING;
-       ret->ReferenceCount = 1;
-       ret->String.Length = newLen;
-       if(Str1)
-               memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
-       if(Str2) {
-               if(Str1)
-                       memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
-               else
-                       memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
-       }
-       ret->String.Data[ newLen ] = '\0';
-       return ret;
-}
-
-/**
- * \brief Cast one object to another
- * \brief Type Destination type
- * \brief Source       Input data
- */
-tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
-{
-       tSpiderValue    *ret = ERRPTR;
-        int    len = 0;
-
-       if( !Source )
-       {
-               switch(Type)
-               {
-               case SS_DATATYPE_INTEGER:       return SpiderScript_CreateInteger(0);
-               case SS_DATATYPE_REAL:  return SpiderScript_CreateReal(0);
-               case SS_DATATYPE_STRING:        return SpiderScript_CreateString(4, "null");
-               }
-               return NULL;
-       }
-       
-       // Check if anything needs to be done
-       if( Source->Type == Type ) {
-               Object_Reference(Source);
-               return Source;
-       }
-       
-       // Debug
-       #if 0
-       {
-               printf("Casting %i ", Source->Type);
-               switch(Source->Type)
-               {
-               case SS_DATATYPE_INTEGER:       printf("0x%lx", Source->Integer);       break;
-               case SS_DATATYPE_STRING:        printf("\"%s\"", Source->String.Data);  break;
-               case SS_DATATYPE_REAL:  printf("%f", Source->Real);     break;
-               default:        break;
-               }
-               printf(" to %i\n", Type);
-       }
-       #endif
-       
-       // Object casts
-       #if 0
-       if( Source->Type == SS_DATATYPE_OBJECT )
-       {
-               const char      *name = NULL;
-               switch(Type)
-               {
-               case SS_DATATYPE_INTEGER:       name = "cast Integer";  break;
-               case SS_DATATYPE_REAL:          name = "cast Real";     break;
-               case SS_DATATYPE_STRING:        name = "cast String";   break;
-               case SS_DATATYPE_ARRAY:         name = "cast Array";    break;
-               default:
-                       AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
-                       return ERRPTR;
-               }
-               if( fcnname )
-               {
-                       ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
-                       if( ret != ERRPTR )
-                               return ret;
-                       // Fall through and try casting (which will usually fail)
-               }
-       }
-       #endif
-       
-       switch( (enum eSpiderScript_DataTypes)Type )
-       {
-       case SS_DATATYPE_UNDEF:
-       case SS_DATATYPE_ARRAY:
-       case SS_DATATYPE_OPAQUE:
-               AST_RuntimeError(NULL, "Invalid cast to %i", Type);
-               return ERRPTR;
-       case SS_DATATYPE_OBJECT:
-               // TODO: 
-               AST_RuntimeError(NULL, "Invalid cast to %i", Type);
-               return ERRPTR;
-       
-       case SS_DATATYPE_INTEGER:
-               ret = malloc(sizeof(tSpiderValue));
-               ret->Type = SS_DATATYPE_INTEGER;
-               ret->ReferenceCount = 1;
-               switch(Source->Type)
-               {
-               case SS_DATATYPE_INTEGER:       break;  // Handled above
-               case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
-               case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
-               default:
-                       AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
-                       free(ret);
-                       ret = ERRPTR;
-                       break;
-               }
-               break;
-       
-       case SS_DATATYPE_REAL:
-               ret = malloc(sizeof(tSpiderValue));
-               ret->Type = SS_DATATYPE_REAL;
-               ret->ReferenceCount = 1;
-               switch(Source->Type)
-               {
-               case SS_DATATYPE_STRING:        ret->Real = atof(Source->String.Data);  break;
-               case SS_DATATYPE_INTEGER:       ret->Real = Source->Integer;    break;
-               default:
-                       AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
-                       free(ret);
-                       ret = ERRPTR;
-                       break;
-               }
-               break;
-       
-       case SS_DATATYPE_STRING:
-               switch(Source->Type)
-               {
-               case SS_DATATYPE_INTEGER:       len = snprintf(NULL, 0, "%li", Source->Integer);        break;
-               case SS_DATATYPE_REAL:  len = snprintf(NULL, 0, "%g", Source->Real);    break;
-               default:        break;
-               }
-               ret = malloc(sizeof(tSpiderValue) + len + 1);
-               ret->Type = SS_DATATYPE_STRING;
-               ret->ReferenceCount = 1;
-               ret->String.Length = len;
-               switch(Source->Type)
-               {
-               case SS_DATATYPE_INTEGER:       sprintf(ret->String.Data, "%li", Source->Integer);      break;
-               case SS_DATATYPE_REAL:
-                       sprintf(ret->String.Data, "%g", Source->Real);  break;
-               default:
-                       AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
-                       free(ret);
-                       ret = ERRPTR;
-                       break;
-               }
-               break;
-       
-       default:
-               AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
-               ret = ERRPTR;
-               break;
-       }
-       
-       return ret;
-}
-
-/**
- * \brief Condenses a value down to a boolean
- */
-int SpiderScript_IsValueTrue(tSpiderValue *Value)
-{
-       if( Value == ERRPTR )   return 0;
-       if( Value == NULL )     return 0;
-       
-       switch( (enum eSpiderScript_DataTypes)Value->Type )
-       {
-       case SS_DATATYPE_UNDEF:
-               return 0;
-       
-       case SS_DATATYPE_INTEGER:
-               return !!Value->Integer;
-       
-       case SS_DATATYPE_REAL:
-               return (-.5f < Value->Real && Value->Real < 0.5f);
-       
-       case SS_DATATYPE_STRING:
-               return Value->String.Length > 0;
-       
-       case SS_DATATYPE_OBJECT:
-               return Value->Object != NULL;
-       
-       case SS_DATATYPE_OPAQUE:
-               return Value->Opaque.Data != NULL;
-       
-       case SS_DATATYPE_ARRAY:
-               return Value->Array.Length > 0;
-       default:
-               AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
-               return 0;
-       }
-       return 0;
-}
-
-/**
- * \brief Free a value
- * \note Just calls Object_Dereference
- */
-void SpiderScript_FreeValue(tSpiderValue *Value)
-{
-       Object_Dereference(Value);
-}
-
-/**
- * \brief Dump a value into a string
- * \return Heap string
- */
-char *SpiderScript_DumpValue(tSpiderValue *Value)
-{
-       char    *ret;
-       if( Value == ERRPTR )
-               return strdup("ERRPTR");
-       if( Value == NULL )
-               return strdup("null");
-       
-       switch( (enum eSpiderScript_DataTypes)Value->Type )
-       {
-       case SS_DATATYPE_UNDEF: return strdup("undefined");
-       
-       case SS_DATATYPE_INTEGER:
-               ret = malloc( sizeof(Value->Integer)*2 + 3 );
-               sprintf(ret, "0x%lx", Value->Integer);
-               return ret;
-       
-       case SS_DATATYPE_REAL:
-               ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
-               sprintf(ret, "%f", Value->Real);
-               return ret;
-       
-       case SS_DATATYPE_STRING:
-               ret = malloc( Value->String.Length + 3 );
-               ret[0] = '"';
-               strcpy(ret+1, Value->String.Data);
-               ret[Value->String.Length+1] = '"';
-               ret[Value->String.Length+2] = '\0';
-               return ret;
-       
-       case SS_DATATYPE_OBJECT:
-               ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
-               sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
-               return ret;
-       
-       case SS_DATATYPE_OPAQUE:
-               ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
-               sprintf(ret, "*%p", Value->Opaque.Data);
-               return ret;
-       
-       case SS_DATATYPE_ARRAY:
-               return strdup("Array");
-       
-       default:
-               AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
-               return NULL;
-       }
-       
-}
-
 /**
  * \brief Execute a script function
  * \param Script       Script context to execute in
@@ -456,7 +87,7 @@ tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
                        ret = AST_ExecuteNode(&bs, astFcn->Code);
                        if(ret != ERRPTR)
                        {
-                               Object_Dereference(ret);        // Dereference output of last block statement
+                               SpiderScript_DereferenceValue(ret);     // Dereference output of last block statement
                                ret = bs.RetVal;        // Set to return value of block
                        }
                        bFound = 1;
@@ -640,7 +271,7 @@ tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
                        ret = AST_ExecuteNode(&bs, astFcn->Code);
                        if( ret != ERRPTR )
                        {
-                               Object_Dereference(ret);        // Dereference output of last block statement
+                               SpiderScript_DereferenceValue(ret);     // Dereference output of last block statement
                                ret = bs.RetVal;        // Set to return value of block
                        }
                        bFound = 1;
@@ -768,7 +399,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        {
                                ret = AST_ExecuteNode(&blockInfo, node);
                                if(ret == ERRPTR)       break;  // Error check
-                               if(ret != NULL) Object_Dereference(ret);        // Free unused value
+                               if(ret != NULL) SpiderScript_DereferenceValue(ret);     // Free unused value
                        }
                        // Clean up variables
                        while(blockInfo.FirstVar)
@@ -813,7 +444,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        #if 0
                        #else
                        if(varVal && varVal->ReferenceCount == 2) {
-                               Object_Dereference(varVal);
+                               SpiderScript_DereferenceValue(varVal);
 //                             printf("pre: (%s) varVal->ReferenceCount = %i\n",
 //                                     Node->Assign.Dest->Variable.Name,
 //                                     varVal->ReferenceCount);
@@ -822,12 +453,12 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
                        if(value == ERRPTR)     return ERRPTR;
 
-                       if(ret) Object_Dereference(ret);
+                       if(ret) SpiderScript_DereferenceValue(ret);
                        #if 0
-                       if(varVal)      Object_Dereference(varVal);
+                       if(varVal)      SpiderScript_DereferenceValue(varVal);
                        #else
                        if(varVal && varVal->ReferenceCount == 1) {
-                               Object_Reference(varVal);
+                               SpiderScript_ReferenceValue(varVal);
 //                             printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
                                break;  // If varVal was non-null, it has been updated by _BinOp
                        }
@@ -838,7 +469,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                
                // Set the variable value
                if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
-                       Object_Dereference( ret );
+                       SpiderScript_DereferenceValue( ret );
                        return ERRPTR;
                }
                break;
@@ -873,10 +504,10 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        ret = varVal;
                
                        if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
-                               Object_Dereference( ret );
+                               SpiderScript_DereferenceValue( ret );
                                return ERRPTR;
                        }
-                       Object_Dereference( value );
+                       SpiderScript_DereferenceValue( value );
                }
                break;
        
@@ -893,7 +524,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        {
                                params[i] = AST_ExecuteNode(Block, node);
                                if( params[i] == ERRPTR ) {
-                                       while(i--)      Object_Dereference(params[i]);
+                                       while(i--)      SpiderScript_DereferenceValue(params[i]);
                                        ret = ERRPTR;
                                        goto _return;
                                }
@@ -917,7 +548,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                                if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
                                        AST_RuntimeError(Node->FunctionCall.Object,
                                                "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
-                                       while(i--)      Object_Dereference(params[i]);
+                                       while(i--)      SpiderScript_DereferenceValue(params[i]);
                                        ret = ERRPTR;
                                        break;
                                }
@@ -925,7 +556,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                                        obj->Object, Node->FunctionCall.Name,
                                        Node->FunctionCall.NumArgs, params
                                        );
-                               Object_Dereference(obj);
+                               SpiderScript_DereferenceValue(obj);
                        }
                        else
                        {
@@ -937,7 +568,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
 
                        
                        // Dereference parameters
-                       while(i--)      Object_Dereference(params[i]);
+                       while(i--)      SpiderScript_DereferenceValue(params[i]);
                        
                        // falls out
                }
@@ -953,9 +584,9 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                else {
                        tmpobj = AST_ExecuteNode(Block, Node->If.False);
                }
-               Object_Dereference(ret);
+               SpiderScript_DereferenceValue(ret);
                if( tmpobj == ERRPTR )  return ERRPTR;
-               Object_Dereference(tmpobj);
+               SpiderScript_DereferenceValue(tmpobj);
                ret = NULL;
                break;
        
@@ -968,12 +599,12 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                // Check initial condition
                if( !Node->For.bCheckAfter )
                {
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                
                        ret = AST_ExecuteNode(Block, Node->For.Condition);
                        if(ret == ERRPTR)       return ERRPTR;
                        if(!SpiderScript_IsValueTrue(ret)) {
-                               Object_Dereference(ret);
+                               SpiderScript_DereferenceValue(ret);
                                ret = NULL;
                                break;
                        }
@@ -982,12 +613,12 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                // Perform loop
                for( ;; )
                {
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                        
                        // Code
                        ret = AST_ExecuteNode(Block, Node->For.Code);
                        if(ret == ERRPTR)       return ERRPTR;
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                        
                        if(Block->BreakTarget)
                        {
@@ -1008,14 +639,14 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        // Increment
                        ret = AST_ExecuteNode(Block, Node->For.Increment);
                        if(ret == ERRPTR)       return ERRPTR;
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                        
                        // Check condition
                        ret = AST_ExecuteNode(Block, Node->For.Condition);
                        if(ret == ERRPTR)       return ERRPTR;
                        if(!SpiderScript_IsValueTrue(ret))      break;
                }
-               Object_Dereference(ret);
+               SpiderScript_DereferenceValue(ret);
                ret = NULL;
                break;
        
@@ -1046,7 +677,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                ret = NULL;
                if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
                        ret = ERRPTR;
-               Object_Dereference(tmpobj);
+               SpiderScript_DereferenceValue(tmpobj);
                break;
        
        // Scope
@@ -1104,7 +735,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
                        {
                                ret = tmpobj->Object->Attributes[i];
-                               Object_Reference(ret);
+                               SpiderScript_ReferenceValue(ret);
                                break;
                        }
                }
@@ -1122,7 +753,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
                if(tmpobj == ERRPTR) return ERRPTR;
                ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
-               Object_Dereference(tmpobj);
+               SpiderScript_DereferenceValue(tmpobj);
                }
                break;
 
@@ -1132,7 +763,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                if(op1 == ERRPTR)       return ERRPTR;
                op2 = AST_ExecuteNode(Block, Node->BinOp.Right);        // Offset
                if(op2 == ERRPTR) {
-                       Object_Dereference(op1);
+                       SpiderScript_DereferenceValue(op1);
                        return ERRPTR;
                }
                
@@ -1153,7 +784,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
                {
                        tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
-                       Object_Dereference(op2);
+                       SpiderScript_DereferenceValue(op2);
                        op2 = tmpobj;
                }
                
@@ -1165,10 +796,10 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                }
                
                ret = op1->Array.Items[ op2->Integer ];
-               Object_Reference(ret);
+               SpiderScript_ReferenceValue(ret);
                
-               Object_Dereference(op1);
-               Object_Dereference(op2);
+               SpiderScript_DereferenceValue(op1);
+               SpiderScript_DereferenceValue(op2);
                break;
 
        // TODO: Implement runtime constants
@@ -1183,7 +814,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
        case NODETYPE_INTEGER:
        case NODETYPE_REAL:
                ret = &Node->Constant;
-               Object_Reference(ret);
+               SpiderScript_ReferenceValue(ret);
                break;
        
        // --- Operations ---
@@ -1192,7 +823,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
                if(op1 == ERRPTR)       return ERRPTR;
                ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
-               Object_Dereference(op1);
+               SpiderScript_DereferenceValue(op1);
                break;
        case NODETYPE_LOGICALAND:       // Logical AND (&&)
        case NODETYPE_LOGICALOR:        // Logical OR (||)
@@ -1201,7 +832,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                if(op1 == ERRPTR)       return ERRPTR;
                op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
                if(op2 == ERRPTR) {
-                       Object_Dereference(op1);
+                       SpiderScript_DereferenceValue(op1);
                        return ERRPTR;
                }
                
@@ -1220,8 +851,8 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                }
                
                // Free intermediate objects
-               Object_Dereference(op1);
-               Object_Dereference(op2);
+               SpiderScript_DereferenceValue(op1);
+               SpiderScript_DereferenceValue(op2);
                break;
        
        // Comparisons
@@ -1234,15 +865,15 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                if(op1 == ERRPTR)       return ERRPTR;
                op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
                if(op2 == ERRPTR) {
-                       Object_Dereference(op1);
+                       SpiderScript_DereferenceValue(op1);
                        ret = ERRPTR;
                        break;
                }
                
                if( !op1 || !op2 ) {
                        AST_RuntimeError(Node, "NULL Comparison (%p and %p)", op1, op2);
-                       if(op1) Object_Dereference(op1);
-                       if(op2) Object_Dereference(op2);
+                       if(op1) SpiderScript_DereferenceValue(op1);
+                       if(op2) SpiderScript_DereferenceValue(op2);
                        ret = SpiderScript_CreateInteger( !op1 && !op2 );
                        break;
                }
@@ -1254,9 +885,9 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        {
                                tmpobj = op2;
                                op2 = SpiderScript_CastValueTo(op1->Type, op2);
-                               Object_Dereference(tmpobj);
+                               SpiderScript_DereferenceValue(tmpobj);
                                if(op2 == ERRPTR) {
-                                       Object_Dereference(op1);
+                                       SpiderScript_DereferenceValue(op1);
                                        return ERRPTR;
                                }
                        }
@@ -1309,8 +940,8 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                }
                
                // Free intermediate objects
-               Object_Dereference(op1);
-               Object_Dereference(op2);
+               SpiderScript_DereferenceValue(op1);
+               SpiderScript_DereferenceValue(op2);
                
                // Error check
                if( ret == ERRPTR )
@@ -1337,7 +968,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
                if(op1 == ERRPTR)       return ERRPTR;
                ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
-               Object_Dereference(op1);
+               SpiderScript_DereferenceValue(op1);
                break;
        
        // General Binary Operations
@@ -1357,15 +988,15 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                if(op1 == ERRPTR)       return ERRPTR;
                op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
                if(op2 == ERRPTR) {
-                       Object_Dereference(op1);
+                       SpiderScript_DereferenceValue(op1);
                        return ERRPTR;
                }
                
                ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
                
                // Free intermediate objects
-               Object_Dereference(op1);
-               Object_Dereference(op2);
+               SpiderScript_DereferenceValue(op1);
+               SpiderScript_DereferenceValue(op2);
                break;
        
        //default:
@@ -1417,7 +1048,7 @@ tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int
        // Integer Operations
        case SS_DATATYPE_INTEGER:
                if( Value->ReferenceCount == 1 )
-                       Object_Reference(ret = Value);
+                       SpiderScript_ReferenceValue(ret = Value);
                else
                        ret = SpiderScript_CreateInteger(0);
                switch(Operation)
@@ -1426,7 +1057,7 @@ tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int
                case NODETYPE_BWNOT:    ret->Integer = ~Value->Integer; break;
                default:
                        AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                        ret = ERRPTR;
                        break;
                }
@@ -1520,7 +1151,7 @@ tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int
                switch(Operation)
                {
                case NODETYPE_ADD:      // Concatenate
-                       ret = Object_StringConcat(Left, Right);
+                       ret = SpiderScript_StringConcat(Left, Right);
                        break;
                // TODO: Support python style 'i = %i' % i ?
                // Might do it via a function call
@@ -1540,7 +1171,7 @@ tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int
        // Integer Operations
        case SS_DATATYPE_INTEGER:
                if( Left->ReferenceCount == 1 )
-                       Object_Reference(ret = Left);
+                       SpiderScript_ReferenceValue(ret = Left);
                else
                        ret = SpiderScript_CreateInteger(0);
                switch(Operation)
@@ -1560,7 +1191,7 @@ tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int
                        break;
                default:
                        AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                        ret = ERRPTR;
                        break;
                }
@@ -1569,7 +1200,7 @@ tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int
        // Real Numbers
        case SS_DATATYPE_REAL:
                if( Left->ReferenceCount == 1 )
-                       Object_Reference(ret = Left);
+                       SpiderScript_ReferenceValue(ret = Left);
                else
                        ret = SpiderScript_CreateReal(0);
                switch(Operation)
@@ -1580,7 +1211,7 @@ tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int
                case NODETYPE_DIVIDE:   ret->Real = Left->Real / Right->Real;   break;
                default:
                        AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
-                       Object_Dereference(ret);
+                       SpiderScript_DereferenceValue(ret);
                        ret = ERRPTR;
                        break;
                }
@@ -1620,7 +1251,7 @@ tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Nam
        var->Next = NULL;
        var->Type = Type;
        var->Object = Value;
-       if(Value)       Object_Reference(Value);
+       if(Value)       SpiderScript_ReferenceValue(Value);
        strcpy(var->Name, Name);
        
        if(prev)        prev->Next = var;
@@ -1705,8 +1336,8 @@ int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *
        }
 
 //     printf("Assign %p to '%s'\n", Value, var->Name);
-       Object_Reference(Value);
-       Object_Dereference(var->Object);
+       SpiderScript_ReferenceValue(Value);
+       SpiderScript_DereferenceValue(var->Object);
        var->Object = Value;
        return 0;
 }
@@ -1720,7 +1351,7 @@ tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
        
        if( !var )      return ERRPTR;
        
-       Object_Reference(var->Object);
+       SpiderScript_ReferenceValue(var->Object);
        return var->Object;
 }
 
@@ -1730,7 +1361,7 @@ tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
 void Variable_Destroy(tAST_Variable *Variable)
 {
 //     printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
-       Object_Dereference(Variable->Object);
+       SpiderScript_DereferenceValue(Variable->Object);
        free(Variable);
 }
 
diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c
new file mode 100644 (file)
index 0000000..b938424
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * SpiderScript Library
+ * by John Hodge (thePowersGang)
+ * 
+ * bytecode_makefile.c
+ * - Generate a bytecode file
+ */
+#include <stdlib.h>
+#include "bytecode_ops.h"
+
+typedef sBC_StackEnt   tBC_StackEnt;
+
+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
+       ET_REFERENCE    // Reference to a tSpiderValue
+};
+
+struct sBC_StackEnt
+{
+       uint8_t EntType;
+       uint8_t _padding[3];
+       union {
+               uint64_t        Integer;
+               double          Real;
+               tSpiderValue    *Reference;
+               tSpiderObject   *Object;
+       };
+};
+
+struct sBC_Stack
+{
+        int    EntrySpace;
+        int    EntryCount;
+       tBC_StackEnt    Entries[];
+};
+
+// === CODE ===
+int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
+{
+       if( Stack->EntryCount == 0 )    return 1;
+       Stack->EntryCount --;
+       *Dest = Stack->Entries[Stack->EntryCount];
+       return 0;
+}
+
+int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
+{
+       if( Stack->EntryCount == Stack->EntrySpace )    return 1;
+       Stack->Entries[Stack->EntryCount] = *Src;
+       Stack->EntryCount ++;
+       return 0;
+}
+
+#define GET_STACKVAL(dst)      if((ret = Bytecode_int_StackPop(Stack, &dst)))    return ret;
+
+int Bytecode_ExecuteFunction(tBC_Function *Fcn, tBC_Stack *Stack, int ArgCount);
+{
+       tBC_Op  *op;
+       tBC_StackEnt    val1, val2;
+       tBC_StackEnt    local_vars[Fcn->MaxVariableCount+Fcn->ArgumentCount];
+       
+       // Pop off arguments
+       
+       // Mark the start
+
+       // Execute!
+       op = Fcn->Operations;
+       while(op)
+       {
+               tBC_Op  *nextop = op->Next;
+               switch(op->Type)
+               {
+               case BC_OP_JUMP:
+                       nextop = Fcn->Labels[op->StringInt.Integer];
+                       break;
+               case BC_OP_JUMPIF:
+                       GET_STACKVAL(val1);
+                       if( Bytecode_int_IsStackEntTrue(&val1) )
+                               nextop = Fcn->Labels[op->StringInt.Integer];
+                       break;
+               case BC_OP_JUMPIFNOT:
+                       GET_STACKVAL(val1);
+                       if( !Bytecode_int_IsStackEntTrue(&val1) )
+                               nextop = Fcn->Labels[op->StringInt.Integer];
+                       break;
+               default:
+                       // TODO:
+                       break;
+               }
+               op = nextop;
+       }
+       
+       // Clean up
+}
index bfeaf50..f26a40c 100644 (file)
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <spiderscript.h>
 #include "ast.h"
+#include "bytecode_gen.h"
 
 // === IMPORTS ===
 extern tAST_Script     *Parse_Buffer(tSpiderVariant *Variant, const char *Buffer, const char *Filename);
@@ -94,6 +95,11 @@ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filen
        return ret;
 }
 
+int SpiderScript_SaveBytecode(tSpiderScript *Script, const char *DestFile)
+{
+       return Bytecode_ConvertScript(Script, DestFile);
+}
+
 /**
  * \brief Free a script
  */
diff --git a/Usermode/Libraries/libspiderscript.so_src/values.c b/Usermode/Libraries/libspiderscript.so_src/values.c
new file mode 100644 (file)
index 0000000..f05360d
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * SpiderScript Library
+ * by John Hodge (thePowersGang)
+ * 
+ * values.c
+ * - Manage tSpiderValue objects
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "spiderscript.h"
+
+// === IMPORTS ===
+extern void    AST_RuntimeError(void *Node, const char *Format, ...);
+
+// === PROTOTYPES ===
+void   SpiderScript_DereferenceValue(tSpiderValue *Object);
+void   SpiderScript_ReferenceValue(tSpiderValue *Object);
+tSpiderValue   *SpiderScript_CreateInteger(uint64_t Value);
+tSpiderValue   *SpiderScript_CreateReal(double Value);
+tSpiderValue   *SpiderScript_CreateString(int Length, const char *Data);
+tSpiderValue   *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
+ int   SpiderScript_IsValueTrue(tSpiderValue *Value);
+void   SpiderScript_FreeValue(tSpiderValue *Value);
+char   *SpiderScript_DumpValue(tSpiderValue *Value);
+
+// === CODE ===
+/**
+ * \brief Dereference a created object
+ */
+void SpiderScript_DereferenceValue(tSpiderValue *Object)
+{
+       if(!Object || Object == ERRPTR) return ;
+       Object->ReferenceCount --;
+       if( Object->ReferenceCount == 0 )
+       {
+               switch( (enum eSpiderScript_DataTypes) Object->Type )
+               {
+               case SS_DATATYPE_OBJECT:
+                       Object->Object->Type->Destructor( Object->Object );
+                       break;
+               case SS_DATATYPE_OPAQUE:
+                       Object->Opaque.Destroy( Object->Opaque.Data );
+                       break;
+               default:
+                       break;
+               }
+               free(Object);
+       }
+}
+
+/**
+ * \brief Reference a value
+ */
+void SpiderScript_ReferenceValue(tSpiderValue *Object)
+{
+       if(!Object || Object == ERRPTR) return ;
+       Object->ReferenceCount ++;
+}
+
+/**
+ * \brief Allocate and initialise a SpiderScript object
+ */
+tSpiderObject *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes)
+{
+        int    size = sizeof(tSpiderObject) + Class->NAttributes * sizeof(tSpiderValue*) + ExtraBytes;
+       tSpiderObject   *ret = malloc(size);
+       
+       ret->Type = Class;
+       ret->ReferenceCount = 1;
+       ret->OpaqueData = &ret->Attributes[ Class->NAttributes ];
+       memset( ret->Attributes, 0, Class->NAttributes * sizeof(tSpiderValue*) );
+       
+       return ret;
+}
+
+/**
+ * \brief Create an integer object
+ */
+tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
+{
+       tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
+       ret->Type = SS_DATATYPE_INTEGER;
+       ret->ReferenceCount = 1;
+       ret->Integer = Value;
+       return ret;
+}
+
+/**
+ * \brief Create an real number object
+ */
+tSpiderValue *SpiderScript_CreateReal(double Value)
+{
+       tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
+       ret->Type = SS_DATATYPE_REAL;
+       ret->ReferenceCount = 1;
+       ret->Real = Value;
+       return ret;
+}
+
+/**
+ * \brief Create an string object
+ */
+tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
+{
+       tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
+       ret->Type = SS_DATATYPE_STRING;
+       ret->ReferenceCount = 1;
+       ret->String.Length = Length;
+       if( Data )
+               memcpy(ret->String.Data, Data, Length);
+       else
+               memset(ret->String.Data, 0, Length);
+       ret->String.Data[Length] = '\0';
+       return ret;
+}
+
+/**
+ * \brief Concatenate two strings
+ */
+tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2)
+{
+        int    newLen = 0;
+       tSpiderValue    *ret;
+       
+       if( Str1 && Str1->Type != SS_DATATYPE_STRING)
+               return NULL;
+       if( Str2 && Str2->Type != SS_DATATYPE_STRING)
+               return NULL;
+       
+       if(Str1)        newLen += Str1->String.Length;
+       if(Str2)        newLen += Str2->String.Length;
+       ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
+       ret->Type = SS_DATATYPE_STRING;
+       ret->ReferenceCount = 1;
+       ret->String.Length = newLen;
+       if(Str1)
+               memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
+       if(Str2) {
+               if(Str1)
+                       memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
+               else
+                       memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
+       }
+       ret->String.Data[ newLen ] = '\0';
+       return ret;
+}
+
+/**
+ * \brief Cast one object to another
+ * \brief Type Destination type
+ * \brief Source       Input data
+ */
+tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
+{
+       tSpiderValue    *ret = ERRPTR;
+        int    len = 0;
+
+       if( !Source )
+       {
+               switch(Type)
+               {
+               case SS_DATATYPE_INTEGER:       return SpiderScript_CreateInteger(0);
+               case SS_DATATYPE_REAL:  return SpiderScript_CreateReal(0);
+               case SS_DATATYPE_STRING:        return SpiderScript_CreateString(4, "null");
+               }
+               return NULL;
+       }
+       
+       // Check if anything needs to be done
+       if( Source->Type == Type ) {
+               SpiderScript_DereferenceValue(Source);
+               return Source;
+       }
+       
+       // Debug
+       #if 0
+       {
+               printf("Casting %i ", Source->Type);
+               switch(Source->Type)
+               {
+               case SS_DATATYPE_INTEGER:       printf("0x%lx", Source->Integer);       break;
+               case SS_DATATYPE_STRING:        printf("\"%s\"", Source->String.Data);  break;
+               case SS_DATATYPE_REAL:  printf("%f", Source->Real);     break;
+               default:        break;
+               }
+               printf(" to %i\n", Type);
+       }
+       #endif
+       
+       // Object casts
+       #if 0
+       if( Source->Type == SS_DATATYPE_OBJECT )
+       {
+               const char      *name = NULL;
+               switch(Type)
+               {
+               case SS_DATATYPE_INTEGER:       name = "cast Integer";  break;
+               case SS_DATATYPE_REAL:          name = "cast Real";     break;
+               case SS_DATATYPE_STRING:        name = "cast String";   break;
+               case SS_DATATYPE_ARRAY:         name = "cast Array";    break;
+               default:
+                       AST_RuntimeError(NULL, "Invalid cast to %i from Object", Type);
+                       return ERRPTR;
+               }
+               if( fcnname )
+               {
+                       ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
+                       if( ret != ERRPTR )
+                               return ret;
+                       // Fall through and try casting (which will usually fail)
+               }
+       }
+       #endif
+       
+       switch( (enum eSpiderScript_DataTypes)Type )
+       {
+       case SS_DATATYPE_UNDEF:
+       case SS_DATATYPE_ARRAY:
+       case SS_DATATYPE_OPAQUE:
+               AST_RuntimeError(NULL, "Invalid cast to %i", Type);
+               return ERRPTR;
+       case SS_DATATYPE_OBJECT:
+               // TODO: 
+               AST_RuntimeError(NULL, "Invalid cast to %i", Type);
+               return ERRPTR;
+       
+       case SS_DATATYPE_INTEGER:
+               ret = malloc(sizeof(tSpiderValue));
+               ret->Type = SS_DATATYPE_INTEGER;
+               ret->ReferenceCount = 1;
+               switch(Source->Type)
+               {
+               case SS_DATATYPE_INTEGER:       break;  // Handled above
+               case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
+               case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
+               default:
+                       AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type);
+                       free(ret);
+                       ret = ERRPTR;
+                       break;
+               }
+               break;
+       
+       case SS_DATATYPE_REAL:
+               ret = malloc(sizeof(tSpiderValue));
+               ret->Type = SS_DATATYPE_REAL;
+               ret->ReferenceCount = 1;
+               switch(Source->Type)
+               {
+               case SS_DATATYPE_STRING:        ret->Real = atof(Source->String.Data);  break;
+               case SS_DATATYPE_INTEGER:       ret->Real = Source->Integer;    break;
+               default:
+                       AST_RuntimeError(NULL, "Invalid cast from %i to Real", Source->Type);
+                       free(ret);
+                       ret = ERRPTR;
+                       break;
+               }
+               break;
+       
+       case SS_DATATYPE_STRING:
+               switch(Source->Type)
+               {
+               case SS_DATATYPE_INTEGER:       len = snprintf(NULL, 0, "%li", Source->Integer);        break;
+               case SS_DATATYPE_REAL:  len = snprintf(NULL, 0, "%g", Source->Real);    break;
+               default:        break;
+               }
+               ret = malloc(sizeof(tSpiderValue) + len + 1);
+               ret->Type = SS_DATATYPE_STRING;
+               ret->ReferenceCount = 1;
+               ret->String.Length = len;
+               switch(Source->Type)
+               {
+               case SS_DATATYPE_INTEGER:       sprintf(ret->String.Data, "%li", Source->Integer);      break;
+               case SS_DATATYPE_REAL:
+                       sprintf(ret->String.Data, "%g", Source->Real);  break;
+               default:
+                       AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type);
+                       free(ret);
+                       ret = ERRPTR;
+                       break;
+               }
+               break;
+       
+       default:
+               AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target %i", Type);
+               ret = ERRPTR;
+               break;
+       }
+       
+       return ret;
+}
+
+/**
+ * \brief Condenses a value down to a boolean
+ */
+int SpiderScript_IsValueTrue(tSpiderValue *Value)
+{
+       if( Value == ERRPTR )   return 0;
+       if( Value == NULL )     return 0;
+       
+       switch( (enum eSpiderScript_DataTypes)Value->Type )
+       {
+       case SS_DATATYPE_UNDEF:
+               return 0;
+       
+       case SS_DATATYPE_INTEGER:
+               return !!Value->Integer;
+       
+       case SS_DATATYPE_REAL:
+               return (-.5f < Value->Real && Value->Real < 0.5f);
+       
+       case SS_DATATYPE_STRING:
+               return Value->String.Length > 0;
+       
+       case SS_DATATYPE_OBJECT:
+               return Value->Object != NULL;
+       
+       case SS_DATATYPE_OPAQUE:
+               return Value->Opaque.Data != NULL;
+       
+       case SS_DATATYPE_ARRAY:
+               return Value->Array.Length > 0;
+       default:
+               AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type);
+               return 0;
+       }
+       return 0;
+}
+
+/**
+ * \brief Free a value
+ * \note Just calls Object_Dereference
+ */
+void SpiderScript_FreeValue(tSpiderValue *Value)
+{
+       SpiderScript_DereferenceValue(Value);
+}
+
+/**
+ * \brief Dump a value into a string
+ * \return Heap string
+ */
+char *SpiderScript_DumpValue(tSpiderValue *Value)
+{
+       char    *ret;
+       if( Value == ERRPTR )
+               return strdup("ERRPTR");
+       if( Value == NULL )
+               return strdup("null");
+       
+       switch( (enum eSpiderScript_DataTypes)Value->Type )
+       {
+       case SS_DATATYPE_UNDEF: return strdup("undefined");
+       
+       case SS_DATATYPE_INTEGER:
+               ret = malloc( sizeof(Value->Integer)*2 + 3 );
+               sprintf(ret, "0x%lx", Value->Integer);
+               return ret;
+       
+       case SS_DATATYPE_REAL:
+               ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
+               sprintf(ret, "%f", Value->Real);
+               return ret;
+       
+       case SS_DATATYPE_STRING:
+               ret = malloc( Value->String.Length + 3 );
+               ret[0] = '"';
+               strcpy(ret+1, Value->String.Data);
+               ret[Value->String.Length+1] = '"';
+               ret[Value->String.Length+2] = '\0';
+               return ret;
+       
+       case SS_DATATYPE_OBJECT:
+               ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
+               sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
+               return ret;
+       
+       case SS_DATATYPE_OPAQUE:
+               ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
+               sprintf(ret, "*%p", Value->Opaque.Data);
+               return ret;
+       
+       case SS_DATATYPE_ARRAY:
+               return strdup("Array");
+       
+       default:
+               AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type);
+               return NULL;
+       }
+       
+}
+
+
index 60870ef..c87a0e5 100644 (file)
@@ -246,6 +246,11 @@ extern tSpiderValue        *SpiderScript_ExecuteFunction(tSpiderScript *Script,
        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 Free a script
  * \param Script       Script structure to free
@@ -258,9 +263,12 @@ extern tSpiderObject       *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int E
  * \name tSpiderValue Manipulation functions
  * \{
  */
+extern void    SpiderScript_DereferenceValue(tSpiderValue *Object);
+extern void    SpiderScript_ReferenceValue(tSpiderValue *Object);
 extern tSpiderValue    *SpiderScript_CreateInteger(uint64_t Value);
 extern tSpiderValue    *SpiderScript_CreateReal(double Value);
 extern tSpiderValue    *SpiderScript_CreateString(int Length, const char *Data);
+extern tSpiderValue    *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2);
 extern tSpiderValue    *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
 extern int     SpiderScript_IsValueTrue(tSpiderValue *Value);
 extern void    SpiderScript_FreeValue(tSpiderValue *Value);

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