SpiderScript - Moved header to directory, ready to remove from tree
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / ast_to_bytecode.c
index 58cc5f8..c45e7a5 100644 (file)
@@ -13,8 +13,9 @@
 #include "bytecode_ops.h"
 
 #define TRACE_VAR_LOOKUPS      0
 #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_NAMESPACE_DEPTH    10
+#define MAX_STACK_DEPTH        10      // This is for one function, so shouldn't need more
 
 // === IMPORTS ===
 extern tSpiderFunction *gpExports_First;
 
 // === IMPORTS ===
 extern tSpiderFunction *gpExports_First;
@@ -28,20 +29,31 @@ typedef struct sAST_BlockInfo
 
         int    BreakTarget;
         int    ContinueTarget;
 
         int    BreakTarget;
         int    ContinueTarget;
-       
+
+        int    NamespaceDepth;
        const char      *CurNamespaceStack[MAX_NAMESPACE_DEPTH];
        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 bKeepValue);
 } tAST_BlockInfo;
 
 // === PROTOTYPES ===
 // Node Traversal
  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);
 // 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, ...);
 // - 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;
 
 // === GLOBALS ===
 // int giNextBlockIdent = 1;
@@ -65,6 +77,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
 {
        tBC_Function    *ret;
        tAST_BlockInfo bi = {0};
 {
        tBC_Function    *ret;
        tAST_BlockInfo bi = {0};
+        int    i;
 
        // TODO: Return BCFcn instead?
        if(Fcn->BCFcn)  return Fcn->BCFcn;
 
        // TODO: Return BCFcn instead?
        if(Fcn->BCFcn)  return Fcn->BCFcn;
@@ -73,11 +86,22 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
        if(!ret)        return NULL;
        
        bi.Handle = ret;
        if(!ret)        return NULL;
        
        bi.Handle = ret;
+       
+       // 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) )
        {
        if( AST_ConvertNode(&bi, Fcn->ASTFcn, 0) )
        {
+               AST_RuntimeError(Fcn->ASTFcn, "Error in converting function");
                Bytecode_DeleteFunction(ret);
                Bytecode_DeleteFunction(ret);
+               BC_Variable_Clear(&bi);
                return NULL;
        }
                return NULL;
        }
+       BC_Variable_Clear(&bi);
+
 
        Bytecode_AppendConstInt(ret, 0);        // TODO: NULL
        Bytecode_AppendReturn(ret);
 
        Bytecode_AppendConstInt(ret, 0);        // TODO: NULL
        Bytecode_AppendReturn(ret);
@@ -90,6 +114,7 @@ tBC_Function *Bytecode_ConvertFunction(tScript_Function *Fcn)
 #define CHECK_IF_NEEDED(b_warn) do { if(!bKeepValue) {\
        if(b_warn)AST_RuntimeMessage(Node, "Bytecode", "Operation without saving");\
        Bytecode_AppendDelete(Block->Handle);\
 #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)
 
 /**
 } } while(0)
 
 /**
@@ -123,28 +148,37 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                                node;
                                node = node->NextSibling )
                        {
                                node;
                                node = node->NextSibling )
                        {
-                               AST_ConvertNode(Block, node, 0);
+                               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:
                }
                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;
-               }
-               
                // Perform assignment operation
                if( Node->Assign.Operation != NODETYPE_NOP )
                {
                // Perform assignment operation
                if( Node->Assign.Operation != NODETYPE_NOP )
                {
+                        int    t1, t2;
                        
                        
-                       ret = BC_Variable_GetValue(Block, Node->Assign.Dest);
+                       ret = AST_ConvertNode(Block, Node->Assign.Dest, 1);
                        if(ret) return ret;
                        if(ret) return ret;
+                       t1 = _StackPop(Block, Node, SS_DATATYPE_UNDEF);
+                       if(t1 < 0)      return -1;
+                       
                        ret = AST_ConvertNode(Block, Node->Assign.Value, 1);
                        if(ret) return ret;
                        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
                        switch(Node->Assign.Operation)
                        {
                        // General Binary Operations
@@ -164,7 +198,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                                AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
                                break;
                        }
                                AST_RuntimeError(Node, "Unknown operation in ASSIGN %i", Node->Assign.Operation);
                                break;
                        }
-                       printf("assign, op = %i\n", op);
+//                     printf("assign, op = %i\n", op);
+                       ret = _StackPush(Block, Node, t1);
+                       if(ret < 0)     return -1;
                        Bytecode_AppendBinOp(Block->Handle, op);
                }
                else
                        Bytecode_AppendBinOp(Block->Handle, op);
                }
                else
@@ -173,21 +209,23 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                        if(ret) return ret;
                }
                
                        if(ret) return ret;
                }
                
-               if( bKeepValue )
+               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);
                        Bytecode_AppendDuplicate(Block->Handle);
-               // Set the variable value
-               ret = BC_Variable_SetValue( Block, Node->Assign.Dest );
+               }
+               
+               ret = BC_SaveValue(Block, Node->Assign.Dest);
+               if(ret) return ret;
                break;
        
        // Post increment/decrement
        case NODETYPE_POSTINC:
        case NODETYPE_POSTDEC:
                break;
        
        // Post increment/decrement
        case NODETYPE_POSTINC:
        case NODETYPE_POSTDEC:
-               // 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;
-               }
-
                // Save original value if requested
                if(bKeepValue) {
                        ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
                // Save original value if requested
                if(bKeepValue) {
                        ret = BC_Variable_GetValue(Block, Node->UniOp.Value);
@@ -195,75 +233,104 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                }
                
                Bytecode_AppendConstInt(Block->Handle, 1);
                }
                
                Bytecode_AppendConstInt(Block->Handle, 1);
+               ret = _StackPush(Block, Node, SS_DATATYPE_INTEGER);
+               if(ret < 0)     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, BC_OP_SUBTRACT);
                else
                        Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
                if(ret) return ret;
 
                if( Node->Type == NODETYPE_POSTDEC )
                        Bytecode_AppendBinOp(Block->Handle, BC_OP_SUBTRACT);
                else
                        Bytecode_AppendBinOp(Block->Handle, BC_OP_ADD);
-               if(ret) return ret;
-
 
 
-               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;
                if(ret) return ret;
-               // Doesn't push unless needed
                break;
                break;
-       
+
        // Function Call
        // Function Call
-       case NODETYPE_METHODCALL:
-       case NODETYPE_FUNCTIONCALL:
-       case NODETYPE_CREATEOBJECT: {
+       case NODETYPE_METHODCALL: {
                 int    nargs = 0;
                 int    nargs = 0;
+               
+               ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
+               if(ret) return ret;
 
 
-               // Put the object earlier on the stack to the arguments (for exec)
-               if( Node->Type == NODETYPE_METHODCALL ) {
-                       ret = AST_ConvertNode(Block, Node->FunctionCall.Object, 1);
+               // Push arguments to the stack
+               for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
+               {
+                       ret = AST_ConvertNode(Block, node, 1);
                        if(ret) return ret;
                        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: {
+                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)
                {
                for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
                {
+                       // TODO: Type Checking
                        ret = AST_ConvertNode(Block, node, 1);
                        if(ret) return ret;
                        nargs ++;
                        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;
                }
                
                // Call the function
                }
                
                // Call the function
-               if( Node->Type == NODETYPE_METHODCALL )
+               if( Node->Type == NODETYPE_CREATEOBJECT )
                {
                {
-                       // TODO: Sanity check stack top
-                       Bytecode_AppendMethodCall(Block->Handle, Node->FunctionCall.Name, nargs);
+                       Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
                }
                else
                {
                }
                else
                {
-                        int    newnamelen = 0;
-                       char    *manglename;
-                       for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ )
-                               newnamelen = strlen(Block->CurNamespaceStack[i]) + 1;
-                       newnamelen += strlen(Node->FunctionCall.Name) + 1;
-                       manglename = alloca(newnamelen);
-                       manglename[0] = 0;
-                       for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ ) {
-                                int    pos;
-                               strcat(manglename, Block->CurNamespaceStack[i]);
-                               pos = strlen(manglename);
-                               manglename[pos] = BC_NS_SEPARATOR;
-                               manglename[pos+1] = '\0';
-                       }
-                       strcat(manglename, Node->FunctionCall.Name);
-                               
-                       if( Node->Type == NODETYPE_CREATEOBJECT )
-                       {
-                               // TODO: Sanity check stack top
-                               Bytecode_AppendCreateObj(Block->Handle, manglename, nargs);
-                       }
-                       else
-                       {
-                               Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
-                       }
+                       Bytecode_AppendFunctionCall(Block->Handle, manglename, nargs);
                }
                }
+               
+               // 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;
                CHECK_IF_NEEDED(0);     // Don't warn
                // TODO: Implement warn_unused_ret
                } break;
@@ -273,6 +340,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                 int    if_end;
                ret = AST_ConvertNode(Block, Node->If.Condition, 1);
                if(ret) return ret;
                 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_end = Bytecode_AllocateLabel(Block->Handle);
 
                
                if_end = Bytecode_AllocateLabel(Block->Handle);
 
@@ -303,7 +373,7 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
        
        // Loop
        case NODETYPE_LOOP: {
        
        // 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;
 
                 int    saved_break, saved_continue;
                const char      *saved_tag;
 
@@ -312,13 +382,14 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                if(ret) return ret;
                
                loop_start = Bytecode_AllocateLabel(Block->Handle);
                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;
                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);
                Block->Tag = Node->For.Tag;
 
                Bytecode_SetLabel(Block->Handle, loop_start);
@@ -329,22 +400,30 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                        ret = AST_ConvertNode(Block, Node->For.Condition, 1);
                        if(ret) return ret;
                        Bytecode_AppendUniOp(Block->Handle, BC_OP_LOGICNOT);
                        ret = AST_ConvertNode(Block, Node->For.Condition, 1);
                        if(ret) return ret;
                        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, 0);
                if(ret) return ret;
                        Bytecode_AppendCondJump(Block->Handle, loop_end);
                }
        
                // 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, 0);
                if(ret) return ret;
                // 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, 1);
                        if(ret) return ret;
 
                // Tail check
                if( Node->For.bCheckAfter )
                {
                        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_AppendCondJump(Block->Handle, loop_start);
                }
                else
@@ -364,13 +443,20 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
                if(ret) return ret;
                Bytecode_AppendReturn(Block->Handle);
                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] ) {
                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
                }
                if( !bi )       return 1;
                // TODO: Check if BreakTarget/ContinueTarget are valid
@@ -389,28 +475,33 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                {
                        ret = AST_ConvertNode(Block, Node->DefVar.InitialValue, 1);
                        if(ret) return ret;
                {
                        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_AppendSaveVar(Block->Handle, Node->DefVar.Name);
                }
                break;
        
        // Scope
        case NODETYPE_SCOPE:
-               for( i = 0; i < MAX_NAMESPACE_DEPTH && Block->CurNamespaceStack[i]; i ++ );
-               if( i == MAX_NAMESPACE_DEPTH ) {
-                       AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", i);
+               if( Block->NamespaceDepth == MAX_NAMESPACE_DEPTH ) {
+                       AST_RuntimeError(Node, "Exceeded max explicit namespace depth (%i)", MAX_NAMESPACE_DEPTH);
                        return 2;
                }
                        return 2;
                }
-               Block->CurNamespaceStack[i] = Node->Scope.Name;
-               ret = AST_ConvertNode(Block, Node->Scope.Element, 2);
-               Block->CurNamespaceStack[i] = NULL;
-               CHECK_IF_NEEDED(0);     // No warning?
-               // TODO: Will this collide with _CALLFUNCTION etc?
+               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);
                break;
        
        // Variable
        case NODETYPE_VARIABLE:
                ret = BC_Variable_GetValue( Block, Node );
                CHECK_IF_NEEDED(1);
+               if(ret) return ret;
                break;
        
        // Element of an Object
                break;
        
        // Element of an Object
@@ -418,7 +509,15 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                ret = AST_ConvertNode( Block, Node->Scope.Element, 1 );
                if(ret) return ret;
 
                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);
                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;
 
                CHECK_IF_NEEDED(1);
                break;
 
@@ -426,18 +525,45 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
        case NODETYPE_CAST:
                ret = AST_ConvertNode(Block, Node->Cast.Value, 1);
                if(ret) return ret;
        case NODETYPE_CAST:
                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);
                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:
                CHECK_IF_NEEDED(1);
                break;
 
        // Index into an array
        case NODETYPE_INDEX:
-               ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);      // Array
+               // - Array
+               ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
                if(ret) return ret;
                if(ret) return ret;
-               ret = AST_ConvertNode(Block, Node->BinOp.Right, 1);     // 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;
                if(ret) return ret;
+               ret = _StackPop(Block, Node, SS_DATATYPE_INTEGER);
+               if(ret < 0)     return -1;
                
                Bytecode_AppendIndex(Block->Handle);
                
                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;
 
                CHECK_IF_NEEDED(1);
                break;
 
@@ -445,23 +571,35 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
        case NODETYPE_CONSTANT:
                // TODO: Scan namespace for constant name
                AST_RuntimeError(Node, "TODO - 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);
        
        // 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);
                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_AppendConstReal(Block->Handle, Node->Constant.Real);
                CHECK_IF_NEEDED(1);
                break;
        case NODETYPE_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;
                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 (!)
        // --- Operations ---
        // Boolean Operations
        case NODETYPE_LOGICALNOT:       // Logical NOT (!)
@@ -472,7 +610,13 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
                if(!op) op = BC_OP_NEG;
                ret = AST_ConvertNode(Block, Node->UniOp.Value, 1);
                if(ret) return ret;
                if(!op) op = BC_OP_NEG;
                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);
                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;
 
                CHECK_IF_NEEDED(1);
                break;
 
@@ -481,8 +625,9 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
        case NODETYPE_LOGICALOR:        if(!op) op = BC_OP_LOGICOR;
        case NODETYPE_LOGICALXOR:       if(!op) op = BC_OP_LOGICXOR;
        // Comparisons
        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;
        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;
@@ -500,29 +645,74 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
        case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
                ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
                if(ret) return ret;
        case NODETYPE_BITROTATELEFT:    if(!op) op = BC_OP_BITROTATELEFT;
                ret = AST_ConvertNode(Block, Node->BinOp.Left, 1);
                if(ret) return ret;
+               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 = 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);
                Bytecode_AppendBinOp(Block->Handle, op);
+               _StackPush(Block, Node, ret);
                CHECK_IF_NEEDED(1);
                break;
        
        default:
                CHECK_IF_NEEDED(1);
                break;
        
        default:
-               ret = -1;
                AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
                AST_RuntimeError(Node, "BUG - SpiderScript AST_ConvertNode Unimplemented %i", Node->Type);
-               break;
+               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;
 }
 
 /**
 }
 
 /**
@@ -534,14 +724,13 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue)
  */
 int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
 {
  */
 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);
        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;
                }
        }
        
                }
        }
        
@@ -553,69 +742,44 @@ int BC_Variable_Define(tAST_BlockInfo *Block, int Type, const char *Name)
        if(prev)        prev->Next = var;
        else    Block->FirstVar = var;
        
        if(prev)        prev->Next = var;
        else    Block->FirstVar = var;
        
-       return var;
-       #else
        Bytecode_AppendDefineVar(Block->Handle, Name, Type);
        return 0;
        Bytecode_AppendDefineVar(Block->Handle, Name, Type);
        return 0;
-       #endif
 }
 
 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
 {
 }
 
 tAST_Variable *BC_Variable_Lookup(tAST_BlockInfo *Block, tAST_Node *VarNode, int CreateType)
 {
-       #if 0
        tAST_Variable   *var = NULL;
        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 )
-                       {
-                               if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
-                                       break;
-                       }
-                       if(var) break;
-               }
-               
-               if( !var )
+               for( var = bs->FirstVar; var; var = var->Next )
                {
                {
-                       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( strcmp(var->Name, VarNode->Variable.Name) == 0 )
+                               break;
                }
                }
-               
-               #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;
        
        return var;
-       #else
-       return (void*)1;
-       #endif
 }
 
 /**
 }
 
 /**
@@ -626,11 +790,13 @@ int BC_Variable_SetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
 {
        tAST_Variable   *var;
        
 {
        tAST_Variable   *var;
        
+       // TODO: Implicit definition type
        var = BC_Variable_Lookup(Block, VarNode, SS_DATATYPE_UNDEF);
        if(!var)        return -1;
 
        // TODO: Check types
 
        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;
 }
        Bytecode_AppendSaveVar(Block->Handle, VarNode->Variable.Name);
        return 0;
 }
@@ -645,10 +811,23 @@ int BC_Variable_GetValue(tAST_BlockInfo *Block, tAST_Node *VarNode)
        var = BC_Variable_Lookup(Block, VarNode, 0);    
        if(!var)        return -1;
        
        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;
 }
 
        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, ...)
 {
 #if 0
 void AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...)
 {
@@ -677,3 +856,42 @@ void AST_RuntimeError(tAST_Node *Node, const char *Format, ...)
        fprintf(stderr, "\n");
 }
 #endif
        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