SpiderScript - Moved header to directory, ready to remove from tree
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / ast_to_bytecode.c
index ab29470..c45e7a5 100644 (file)
@@ -13,7 +13,9 @@
 #include "bytecode_ops.h"
 
 #define TRACE_VAR_LOOKUPS      0
-#define TRACE_NODE_RETURNS     0
+#define TRACE_TYPE_STACK       0
+#define MAX_NAMESPACE_DEPTH    10
+#define MAX_STACK_DEPTH        10      // This is for one function, so shouldn't need more
 
 // === IMPORTS ===
 extern tSpiderFunction *gpExports_First;
@@ -27,18 +29,31 @@ typedef struct sAST_BlockInfo
 
         int    BreakTarget;
         int    ContinueTarget;
+
+        int    NamespaceDepth;
+       const char      *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
+       
+        int    StackDepth;
+        int    Stack[MAX_STACK_DEPTH]; // Stores types of stack values
+       
+       tAST_Variable   *FirstVar;
 } tAST_BlockInfo;
 
 // === PROTOTYPES ===
 // Node Traversal
- int   AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node);
+ int   AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue);
+ int   BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode);
 // 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);
+void   BC_Variable_Clear(tAST_BlockInfo *Block);
 // - Errors
 void   AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
 void   AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
+// - Type stack
+ int   _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type);
+ int   _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType);
 
 // === GLOBALS ===
 // int giNextBlockIdent = 1;
@@ -62,6 +77,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
 {
        tBC_Function    *ret;
        tAST_BlockInfo bi = {0};
+        int    i;
 
        // TODO: Return BCFcn instead?
        if(Fcn->BCFcn)  return Fcn->BCFcn;
@@ -70,151 +86,285 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
        if(!ret)        return NULL;
        
        bi.Handle = ret;
-       if( AST_ConvertNode(&bi, Fcn->ASTFcn) )
+       
+       // Parse arguments
+       for( i = 0; i < Fcn->ArgumentCount; i ++ )
        {
+               BC_Variable_Define(&bi, Fcn->Arguments[i].Type, Fcn->Arguments[i].Name);
+       }
+
+       if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
+       {
+               AST_RuntimeError(Fcn->ASTFcn, "Error in converting function");
                Bytecode_DeleteFunction(ret);
+               BC_Variable_Clear(&bi);
                return NULL;
        }
+       BC_Variable_Clear(&bi);
+
 
+       Bytecode_AppendConstInt(ret, 0);        // TODO: NULL
+       Bytecode_AppendReturn(ret);
        Fcn->BCFcn = ret;
 
        return ret;
 }
 
+// Indepotent operation
+#define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
+       if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
+       Bytecode_AppendDelete(Block->Handle);\
+       _StackPop(Block, Node, SS_DATATYPE_UNDEF);\
+} } while(0)
+
 /**
  * \brief Convert a node into bytecode
  * \param Block        Execution context
  * \param Node Node to execute
  */
-int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
+int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
 {
        tAST_Node       *node;
         int    ret = 0;
         int    i, op = 0;
+        int    bAddedValue = 1;        // Used to tell if the value needs to be deleted
        
        switch(Node->Type)
        {
        // No Operation
        case NODETYPE_NOP:
+               bAddedValue = 0;
                break;
        
        // Code block
        case NODETYPE_BLOCK:
                Bytecode_AppendEnterContext(Block->Handle);     // Create a new block
                {
-                       tAST_BlockInfo  blockInfo;
+                       tAST_BlockInfo  blockInfo = {0};
                        blockInfo.Parent = Block;
                        blockInfo.Handle = Block->Handle;
-                       blockInfo.ContinueTarget = 0;
-                       blockInfo.BreakTarget = 0;
                        // Loop over all nodes, or until the return value is set
                        for(node = Node->Block.FirstChild;
                                node;
                                node = node->NextSibling )
                        {
-                               AST_ConvertNode(Block, node);
+                               ret = AST_ConvertNode(&blockInfo, node, 0);
+                               if(ret) return ret;
+                               if( blockInfo.StackDepth != 0 ) {
+                                       AST_RuntimeError(node, "Stack not reset at end of node");
+                                       blockInfo.StackDepth = 0;
+                               }
                        }
+                       
+                       BC_Variable_Clear(&blockInfo);
                }
                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 )
                {
+                        int    t1, t2;
+                       
+                       ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
+                       if(ret) return ret;
+                       t1 = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+                       if(t1 < 0)      return -1;
                        
-                       ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
+                       ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
+                       if(ret) return ret;
+                       t2 = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+                       if(t2 < 0)      return -1;
+
+
+                       switch(Node->Assign.Operation)
+                       {
+                       // General Binary Operations
+                       case NODETYPE_ADD:      op = BC_OP_ADD; break;
+                       case NODETYPE_SUBTRACT: op = BC_OP_SUBTRACT;    break;
+                       case NODETYPE_MULTIPLY: op = BC_OP_MULTIPLY;    break;
+                       case NODETYPE_DIVIDE:   op = BC_OP_DIVIDE;      break;
+                       case NODETYPE_MODULO:   op = BC_OP_MODULO;      break;
+                       case NODETYPE_BWAND:    op = BC_OP_BITAND;      break;
+                       case NODETYPE_BWOR:     op = BC_OP_BITOR;       break;
+                       case NODETYPE_BWXOR:    op = BC_OP_BITXOR;      break;
+                       case NODETYPE_BITSHIFTLEFT:     op = BC_OP_BITSHIFTLEFT;        break;
+                       case NODETYPE_BITSHIFTRIGHT:    op = BC_OP_BITSHIFTRIGHT;       break;
+                       case NODETYPE_BITROTATELEFT:    op = BC_OP_BITROTATELEFT;       break;
+
+                       default:
+                               AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
+                               break;
+                       }
+//                     printf("assign, op = %i\n", op);
+                       ret = _StackPush(Block, Node, t1);
+                       if(ret < 0)     return -1;
+                       Bytecode_AppendBinOp(Block->Handle, op);
+               }
+               else
+               {
+                       ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
                        if(ret) return ret;
-                       Bytecode_AppendBinOp(Block->Handle, Node->Assign.Operation);
                }
                
-               // Set the variable value
-               ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
+               if( bKeepValue ) {
+                       ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+                       if(ret < 0)     return -1;
+                       ret = _StackPush(Block, Node, ret);
+                       if(ret < 0)     return -1;
+                       ret = _StackPush(Block, Node, ret);
+                       if(ret < 0)     return -1;
+                       Bytecode_AppendDuplicate(Block->Handle);
+               }
+               
+               ret = BC_SaveValue(Block, Node->Assign.Dest);
+               if(ret) return ret;
                break;
        
        // Post increment/decrement
        case NODETYPE_POSTINC:
        case NODETYPE_POSTDEC:
+               // Save original value if requested
+               if(bKeepValue) {
+                       ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
+                       if(ret) return ret;
+               }
+               
                Bytecode_AppendConstInt(Block->Handle, 1);
+               ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER);
+               if(ret < 0)     return -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);
+               ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
                if(ret) return ret;
 
                if( Node->Type == NODETYPE_POSTDEC )
-                       Bytecode_AppendBinOp(Block->Handle, NODETYPE_SUBTRACT);
+                       Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
                else
-                       Bytecode_AppendBinOp(Block->Handle, NODETYPE_ADD);
-               if(ret) return ret;
+                       Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
 
-               ret = BC_Variable_SetValue(Block, Node->UniOp.Value);
+               ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER);      // TODO: Check for objects too
+               if(ret < 0)     return -1;
+               ret = BC_SaveValue(Block, Node->UniOp.Value);
                if(ret) return ret;
                break;
-       
+
        // Function Call
-       case NODETYPE_METHODCALL:
+       case NODETYPE_METHODCALL: {
+                int    nargs = 0;
+               
+               ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
+               if(ret) return ret;
+
+               // Push arguments to the stack
+               for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
+               {
+                       ret = AST_ConvertNode(Block, node, 1);
+                       if(ret) return ret;
+                       nargs ++;
+                       
+                       // TODO: Check arguments? Need to get the types somehow
+                       ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+                       if(ret < 0)     return -1;
+               }
+               
+               ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT);
+               if(ret < 0)     return -1;
+               Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
+
+               ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+       
+               CHECK_IF_NEEDED(0);     // Don't warn
+               // TODO: Implement warn_unused_ret
+               
+               } break;
        case NODETYPE_FUNCTIONCALL:
-       case NODETYPE_CREATEOBJECT:
-               i = 0;
+       case NODETYPE_CREATEOBJECT: {
+                int    nargs = 0;
+               
+               // Get name (mangled into a single string)
+                int    newnamelen = 0;
+               char    *manglename;
+               for( i = 0; i < Block->NamespaceDepth; i ++ )
+                       newnamelen += strlen(Block->CurNamespaceStack[i]) + 1;
+               newnamelen += strlen(Node->FunctionCall.Name) + 1;
+//             newnamelen += 1;
+               
+               manglename = alloca(newnamelen);
+               newnamelen = 0;
+               for( i = 0; i < Block->NamespaceDepth; i ++ ) {
+                       strcpy(manglename+newnamelen, Block->CurNamespaceStack[i]);
+                       newnamelen += strlen(Block->CurNamespaceStack[i]) + 1;
+                       manglename[ newnamelen - 1 ] = BC_NS_SEPARATOR;
+               }
+               strcpy(manglename + newnamelen, Node->FunctionCall.Name);
+               newnamelen += strlen(Node->FunctionCall.Name) + 1;
+//             manglename[ newnamelen ] = '\0';        // Zero length terminator
+               Block->NamespaceDepth = 0;
+
+               // Push arguments to the stack
                for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
                {
-                       ret = AST_ConvertNode(Block, node);
+                       // TODO: Type Checking
+                       ret = AST_ConvertNode(Block, node, 1);
                        if(ret) return ret;
-                       i ++;
+                       nargs ++;
+                       
+                       // TODO: Check arguments? Need to get the types somehow
+                       ret = _StackPop(Block, node, SS_DATATYPE_UNDEF);
+                       if(ret < 0)     return -1;
                }
                
                // 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);
+                       Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
                }
                else
                {
-                       Bytecode_AppendFunctionCall(Block->Handle, Node->FunctionCall.Name, i);
+                       Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
                }
-               break;
+               
+               // TODO: Get return type
+               ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+               
+               CHECK_IF_NEEDED(0);     // Don't warn
+               // TODO: Implement warn_unused_ret
+               } break;
        
        // Conditional
        case NODETYPE_IF: {
-                int    if_true, if_end;
-               ret = AST_ConvertNode(Block, Node->If.Condition);
+                int    if_end;
+               ret = AST_ConvertNode(Block, Node->If.Condition, 1);
                if(ret) return ret;
+               // TODO: Should be boolean/integer, but meh
+               ret = _StackPop(Block, Node->If.Condition, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
                
-               if_true = Bytecode_AllocateLabel(Block->Handle);
                if_end = Bytecode_AllocateLabel(Block->Handle);
-       
-               Bytecode_AppendCondJump(Block->Handle, if_true);
 
-               // False
-               ret = AST_ConvertNode(Block, Node->If.False);
-               if(ret) return ret;
-               Bytecode_AppendJump(Block->Handle, if_end);
+               if( Node->If.False->Type != NODETYPE_NOP )
+               {
+                        int    if_true = Bytecode_AllocateLabel(Block->Handle);
+                       
+                       Bytecode_AppendCondJump(Block->Handle, if_true);
+       
+                       // False
+                       ret = AST_ConvertNode(Block, Node->If.False, 0);
+                       if(ret) return ret;
+                       Bytecode_AppendJump(Block->Handle, if_end);
+                       Bytecode_SetLabel(Block->Handle, if_true);
+               }
+               else
+               {
+                       Bytecode_AppendCondJumpNot(Block->Handle, if_end);
+               }
                
                // True
-               Bytecode_SetLabel(Block->Handle, if_true);
-               ret = AST_ConvertNode(Block, Node->If.True);
+               ret = AST_ConvertNode(Block, Node->If.True, 0);
                if(ret) return ret;
 
                // End
@@ -223,22 +373,23 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
        
        // Loop
        case NODETYPE_LOOP: {
-                int    loop_start, loop_end;
+                int    loop_start, loop_end, code_end;
                 int    saved_break, saved_continue;
                const char      *saved_tag;
 
                // Initialise
-               ret = AST_ConvertNode(Block, Node->For.Init);
+               ret = AST_ConvertNode(Block, Node->For.Init, 0);
                if(ret) return ret;
                
                loop_start = Bytecode_AllocateLabel(Block->Handle);
+               code_end = 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->ContinueTarget = code_end;
                Block->Tag = Node->For.Tag;
 
                Bytecode_SetLabel(Block->Handle, loop_start);
@@ -246,27 +397,39 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
                // Check initial condition
                if( !Node->For.bCheckAfter )
                {
-                       ret = AST_ConvertNode(Block, Node->For.Condition);
+                       ret = AST_ConvertNode(Block, Node->For.Condition, 1);
                        if(ret) return ret;
-                       Bytecode_AppendUniOp(Block->Handle, NODETYPE_LOGICALNOT);
+                       Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
+                       ret = _StackPop(Block, Node->For.Condition, SS_DATATYPE_UNDEF); // Boolean?
+                       if(ret < 0)     return -1;
                        Bytecode_AppendCondJump(Block->Handle, loop_end);
                }
        
                // Code
-               ret = AST_ConvertNode(Block, Node->For.Code);
+               ret = AST_ConvertNode(Block, Node->For.Code, 0);
                if(ret) return ret;
-               
+
+               Bytecode_SetLabel(Block->Handle, code_end);
+       
                // Increment
-               ret = AST_ConvertNode(Block, Node->For.Increment);
+               ret = AST_ConvertNode(Block, Node->For.Increment, 0);
                if(ret) return ret;
+//             ret = _StackPop(Block, Node->For.Increment, SS_DATATYPE_UNDEF); // TODO: Check if needed
+//             if(ret < 0)     return -1;
 
                // Tail check
                if( Node->For.bCheckAfter )
                {
-                       ret = AST_ConvertNode(Block, Node->For.Condition);
+                       ret = AST_ConvertNode(Block, Node->For.Condition, 1);
                        if(ret) return ret;
+                       ret = _StackPop(Block, Node->If.Condition, SS_DATATYPE_UNDEF);  // Boolean?
+                       if(ret < 0)     return ret;
                        Bytecode_AppendCondJump(Block->Handle, loop_start);
                }
+               else
+               {
+                       Bytecode_AppendJump(Block->Handle, loop_start);
+               }
 
                Bytecode_SetLabel(Block->Handle, loop_end);
 
@@ -277,16 +440,23 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
        
        // Return
        case NODETYPE_RETURN:
-               ret = AST_ConvertNode(Block, Node->UniOp.Value);
+               ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
                if(ret) return ret;
                Bytecode_AppendReturn(Block->Handle);
+               ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF);   // 
+               if(ret < 0)     return -1;
                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;
+                       while(bi && (!bi->Tag || strcmp(bi->Tag, Node->Variable.Name) != 0))
+                               bi = bi->Parent;
+               }
+               else {
+                       while(bi && !bi->Tag)
+                               bi = bi->Parent;
                }
                if( !bi )       return 1;
                // TODO: Check if BreakTarget/ContinueTarget are valid
@@ -303,66 +473,133 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
                
                if( Node->DefVar.InitialValue )
                {
-                       ret = AST_ConvertNode(Block, Node->DefVar.InitialValue);
+                       ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
                        if(ret) return ret;
+                       ret = _StackPop(Block, Node->DefVar.InitialValue, Node->DefVar.DataType);
+                       if(ret < 0)     return -1;
                        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);
+               if( Block->NamespaceDepth == MAX_NAMESPACE_DEPTH ) {
+                       AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", MAX_NAMESPACE_DEPTH);
+                       return 2;
+               }
+               Block->CurNamespaceStack[ Block->NamespaceDepth ] = Node->Scope.Name;
+               Block->NamespaceDepth ++;
+               ret = AST_ConvertNode(Block, Node->Scope.Element, bKeepValue);
+               if(ret) return ret;
+               if( Block->NamespaceDepth != 0 ) {
+                       AST_RuntimeError(Node, "Namespace scope used but no element at the end");
+               }
+               bAddedValue = 0;
                break;
        
        // Variable
        case NODETYPE_VARIABLE:
                ret = BC_Variable_GetValue( Block, Node );
+               CHECK_IF_NEEDED(1);
+               if(ret) return ret;
                break;
        
        // Element of an Object
        case NODETYPE_ELEMENT:
-               ret = AST_ConvertNode( Block, Node->Scope.Element );
+               ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
                if(ret) return ret;
 
+               // TODO: Support elements for non-objects
+               ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT);
+               if(ret < 0)     return -1;
+
                Bytecode_AppendElement(Block->Handle, Node->Scope.Name);
+               
+               // TODO: Somehow know this at compile time?
+               ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+               CHECK_IF_NEEDED(1);
                break;
 
        // Cast a value to another
        case NODETYPE_CAST:
-               ret = AST_ConvertNode(Block, Node->Cast.Value);
+               ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
                if(ret) return ret;
+               ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+               
                Bytecode_AppendCast(Block->Handle, Node->Cast.DataType);
+               ret = _StackPush(Block, Node, Node->Cast.DataType);
+               if(ret < 0)     return -1;
+               CHECK_IF_NEEDED(1);
                break;
 
        // Index into an array
        case NODETYPE_INDEX:
-               ret = AST_ConvertNode(Block, Node->BinOp.Left); // Array
+               // - Array
+               ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
                if(ret) return ret;
-               ret = AST_ConvertNode(Block, Node->BinOp.Right);        // Offset
+               //  > Type check
+               ret = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+               if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) {
+                       AST_RuntimeError(Node, "Type mismatch, Expected an array, got %i",
+                               ret);
+                       return -2;
+               }
+               i = ret;        // Hackily save the datatype
+
+               // - Offset
+               ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
                if(ret) return ret;
+               ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER);
+               if(ret < 0)     return -1;
                
                Bytecode_AppendIndex(Block->Handle);
+               
+               // Update the array depth
+               if( i != SS_DATATYPE_ARRAY ) {
+                       i = SS_DOWNARRAY(i);    // Decrease the array level
+               }
+               ret = _StackPush(Block, Node, i);
+               if(ret < 0)     return -1;
+               
+               CHECK_IF_NEEDED(1);
                break;
 
        // TODO: Implement runtime constants
        case NODETYPE_CONSTANT:
                // TODO: Scan namespace for constant name
                AST_RuntimeError(Node, "TODO - Runtime Constants");
-               ret = -1;
-               break;
+               Block->NamespaceDepth = 0;
+               return -1;
        
        // Constant Values
        case NODETYPE_STRING:
                Bytecode_AppendConstString(Block->Handle, Node->Constant.String.Data, Node->Constant.String.Length);
+               ret = _StackPush(Block, Node, SS_DATATYPE_STRING);
+               if(ret < 0)     return -1;
+               CHECK_IF_NEEDED(1);
                break;
        case NODETYPE_INTEGER:
                Bytecode_AppendConstInt(Block->Handle, Node->Constant.Integer);
+               ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER);
+               if(ret < 0)     return -1;
+               CHECK_IF_NEEDED(1);
                break;
        case NODETYPE_REAL:
-               Bytecode_AppendConstInt(Block->Handle, Node->Constant.Real);
+               Bytecode_AppendConstReal(Block->Handle, Node->Constant.Real);
+               ret = _StackPush(Block, Node, SS_DATATYPE_REAL);
+               if(ret < 0)     return -1;
+               CHECK_IF_NEEDED(1);
                break;
-       
+       case NODETYPE_NULL:
+               Bytecode_AppendConstNull(Block->Handle);
+               ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+               CHECK_IF_NEEDED(1);
+               break;
+
        // --- Operations ---
        // Boolean Operations
        case NODETYPE_LOGICALNOT:       // Logical NOT (!)
@@ -371,20 +608,26 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
                if(!op) op = BC_OP_BITNOT;
        case NODETYPE_NEGATE:   // Negation (-)
                if(!op) op = BC_OP_NEG;
-               ret = AST_ConvertNode(Block, Node->UniOp.Value);
+               ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
                if(ret) return ret;
+               ret = _StackPop(Block, Node->UniOp.Value, SS_DATATYPE_UNDEF);   // TODO: Integer/Real/Undef
+               if(ret < 0)     return -1;
+
                Bytecode_AppendUniOp(Block->Handle, op);
+               ret = _StackPush(Block, Node, ret);     // TODO: Logic = _INTEGER, Neg = No change
+               if(ret < 0)     return -1;
+               
+               CHECK_IF_NEEDED(1);
                break;
 
-       case NODETYPE_LOGICALAND:       // Logical AND (&&)
-               if(!op) op = BC_OP_LOGICAND;
-       case NODETYPE_LOGICALOR:        // Logical OR (||)
-               if(!op) op = BC_OP_LOGICOR;
-       case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
-               if(!op) op = BC_OP_LOGICXOR;
+       // Logic
+       case NODETYPE_LOGICALAND:       if(!op) op = BC_OP_LOGICAND;
+       case NODETYPE_LOGICALOR:        if(!op) op = BC_OP_LOGICOR;
+       case NODETYPE_LOGICALXOR:       if(!op) op = BC_OP_LOGICXOR;
        // Comparisons
-       case NODETYPE_EQUALS:   if(!op) op = BC_OP_EQUALS;
-       case NODETYPE_LESSTHAN: if(!op) op = BC_OP_LESSTHAN;
+       case NODETYPE_EQUALS:           if(!op) op = BC_OP_EQUALS;
+       case NODETYPE_NOTEQUALS:        if(!op) op = BC_OP_NOTEQUALS;
+       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;
@@ -400,30 +643,76 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
        case NODETYPE_BITSHIFTLEFT:     if(!op) op = BC_OP_BITSHIFTLEFT;
        case NODETYPE_BITSHIFTRIGHT:    if(!op) op = BC_OP_BITSHIFTRIGHT;
        case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
-               ret = AST_ConvertNode(Block, Node->BinOp.Left);
+               ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
                if(ret) return ret;
-               ret = AST_ConvertNode(Block, Node->BinOp.Right);
+               ret = _StackPop(Block, Node->BinOp.Left, SS_DATATYPE_UNDEF);    // TODO: Integer/Real/Object
+               if(ret < 0)     return -1;
+       
+               ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);
                if(ret) return ret;
+               ret = _StackPop(Block, Node->BinOp.Right, SS_DATATYPE_UNDEF);   // TODO: Integer/Real/Object
+               if(ret < 0)     return -1;
                
                Bytecode_AppendBinOp(Block->Handle, op);
+               _StackPush(Block, Node, ret);
+               CHECK_IF_NEEDED(1);
                break;
        
-       //default:
-       //      ret = NULL;
-       //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
-       //      break;
+       default:
+               AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
+               return -1;
        }
 
-       #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 0;
+}
 
-       return ret;
+int BC_SaveValue(tAST_BlockInfo *Block, tAST_Node *DestNode)
+{
+        int    ret, type;
+       switch(DestNode->Type)
+       {
+       // Variable, simple
+       case NODETYPE_VARIABLE:
+               ret = BC_Variable_SetValue( Block, DestNode );
+               if(ret) return ret;
+               break;
+       // Array index
+       case NODETYPE_INDEX:
+               ret = AST_ConvertNode(Block, DestNode->BinOp.Left, 1);  // Array
+               if(ret) return ret;
+               ret = _StackPop(Block, DestNode->BinOp.Left, SS_DATATYPE_UNDEF);
+               if(ret < 0)     return -1;
+               if(ret != SS_DATATYPE_ARRAY && SS_GETARRAYDEPTH(ret) == 0) {
+                       AST_RuntimeError(DestNode, "Type mismatch, Expected an array, got %i",
+                               ret);
+                       return -2;
+               }
+               type = SS_DOWNARRAY(ret);
+               
+               ret = AST_ConvertNode(Block, DestNode->BinOp.Right, 1); // Offset
+               if(ret) return ret;
+               ret = _StackPop(Block, DestNode->BinOp.Right, SS_DATATYPE_INTEGER);
+               if(ret < 0)     return -1;
+               
+               Bytecode_AppendSetIndex( Block->Handle );
+               _StackPop(Block, DestNode, type);
+               break;
+       // Object element
+       case NODETYPE_ELEMENT:
+               ret = AST_ConvertNode(Block, DestNode->Scope.Element, 1);
+               if(ret) return ret;
+               ret = _StackPop(Block, DestNode->Scope.Element, SS_DATATYPE_OBJECT);
+               if(ret < 0)     return -1;
+               
+               Bytecode_AppendSetElement( Block->Handle, DestNode->Scope.Name );
+               break;
+       // Anything else
+       default:
+               // TODO: Support assigning to object attributes
+               AST_RuntimeError(DestNode, "Assignment target is not a LValue");
+               return -1;
+       }
+       return 0;
 }
 
 /**
@@ -435,14 +724,13 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node)
  */
 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;
+                       return -1;
                }
        }
        
@@ -454,69 +742,44 @@ int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *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;
+       tAST_BlockInfo  *bs;
        
-       // 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
+       for( bs = Block; bs; bs = bs->Parent )
        {
-               tAST_BlockInfo  *bs;
-               for( bs = Block; bs; bs = bs->Parent )
+               for( var = bs->FirstVar; var; var = var->Next )
                {
-                       for( var = bs->FirstVar; var; var = var->Next )
-                       {
-                               if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
-                                       break;
-                       }
-                       if(var) break;
+                       if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
+                               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;
+               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", "Variable lookup of '%s' %p type %i",
+               VarNode->Variable.Name, var, var->Type);
+       #endif
        
        return var;
-       #else
-       return (void*)1;
-       #endif
 }
 
 /**
@@ -527,11 +790,13 @@ int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
 {
        tAST_Variable   *var;
        
+       // TODO: Implicit definition type
        var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
        if(!var)        return -1;
 
        // TODO: Check types
 
+       _StackPop(Block, VarNode, var->Type);
        Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
        return 0;
 }
@@ -546,10 +811,23 @@ int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
        var = BC_Variable_Lookup(Block, VarNode, 0);    
        if(!var)        return -1;
        
+       _StackPush(Block, VarNode, var->Type);
        Bytecode_AppendLoadVar(Block->Handle, VarNode->Variable.Name);
        return 0;
 }
 
+void BC_Variable_Clear(tAST_BlockInfo *Block)
+{
+       tAST_Variable   *var;
+       for( var = Block->FirstVar; var; )
+       {
+               tAST_Variable   *tv = var->Next;
+               free( var );
+               var = tv;
+       }
+       Block->FirstVar = NULL;
+}
+
 #if 0
 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
 {
@@ -578,3 +856,42 @@ void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
        fprintf(stderr, "\n");
 }
 #endif
+
+int _StackPush(tAST_BlockInfo *Block, tAST_Node *Node, int Type)
+{
+       if(Block->StackDepth == MAX_STACK_DEPTH - 1) {
+               AST_RuntimeError(Node, "BUG - Stack overflow in AST-Bytecode conversion (node=%i)",
+                       Node->Type);
+               return -1;
+       }
+
+       #if TRACE_TYPE_STACK
+       AST_RuntimeMessage(Node, "_StackPush", "%x - NT%i", Type, Node->Type);
+       #endif
+       Block->Stack[ ++Block->StackDepth ] = Type;
+       return Type;
+}
+
+int _StackPop(tAST_BlockInfo *Block, tAST_Node *Node, int WantedType)
+{
+       if(Block->StackDepth == 0) {
+               AST_RuntimeError(Node, "BUG - Stack underflow in AST-Bytecode conversion (node=%i)",
+                       Node->Type);
+               return -1;
+       }
+       #if TRACE_TYPE_STACK
+       AST_RuntimeMessage(Node, "_StackPop", "%x(?==%x) - NT%i",
+               Block->Stack[ Block->StackDepth ], WantedType, Node->Type);
+       #endif
+       if(WantedType != SS_DATATYPE_UNDEF && Block->Stack[ Block->StackDepth ] != SS_DATATYPE_UNDEF)
+       {
+               if( Block->Stack[ Block->StackDepth ] != WantedType ) {
+                       AST_RuntimeError(Node, "AST-Bytecode - Type mismatch (wanted %x got %x)",
+                               WantedType, Block->Stack[ Block->StackDepth ]);
+                       // TODO: Message?
+                       return -2;
+               }
+       }
+       return Block->Stack[Block->StackDepth--];
+}
+

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