SpiderScript - Implementing objects and classes, fixing bugs
authorJohn Hodge <[email protected]>
Sat, 2 Apr 2011 06:17:34 +0000 (14:17 +0800)
committerJohn Hodge <[email protected]>
Sat, 2 Apr 2011 06:17:34 +0000 (14:17 +0800)
Usermode/Libraries/libspiderscript.so_src/ast.c
Usermode/Libraries/libspiderscript.so_src/ast.h
Usermode/Libraries/libspiderscript.so_src/exec_ast.c
Usermode/Libraries/libspiderscript.so_src/main.c
Usermode/Libraries/libspiderscript.so_src/parse.c
Usermode/include/spiderscript.h

index 1453a92..36568e6 100644 (file)
@@ -65,131 +65,6 @@ void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
  * \name Node Manipulation
  * \{
  */
-/**
- * \brief Get the in-memory size of a node
- */
-size_t AST_GetNodeSize(tAST_Node *Node)
-{
-       size_t  ret;
-       tAST_Node       *node;
-       
-       if(!Node)
-               return 0;
-       
-       ret = sizeof(tAST_Node*) + sizeof(tAST_NodeType)
-               + sizeof(const char *) + sizeof(int);
-       
-       switch(Node->Type)
-       {
-       // Block of code
-       case NODETYPE_BLOCK:
-               ret += sizeof(Node->Block);
-               for( node = Node->Block.FirstChild; node; )
-               {
-                       ret += AST_GetNodeSize(node);
-                       node = node->NextSibling;
-               }
-               break;
-       
-       // Function Call
-       case NODETYPE_FUNCTIONCALL:
-               ret += sizeof(Node->FunctionCall) + strlen(Node->FunctionCall.Name) + 1;
-               for( node = Node->FunctionCall.FirstArg; node; )
-               {
-                       ret += AST_GetNodeSize(node);
-                       node = node->NextSibling;
-               }
-               break;
-       
-       // If node
-       case NODETYPE_IF:
-               ret += sizeof(Node->If);
-               ret += AST_GetNodeSize(Node->If.Condition);
-               ret += AST_GetNodeSize(Node->If.True);
-               ret += AST_GetNodeSize(Node->If.False);
-               break;
-       
-       // Looping Construct (For loop node)
-       case NODETYPE_LOOP:
-               ret += sizeof(Node->For);
-               ret += AST_GetNodeSize(Node->For.Init);
-               ret += AST_GetNodeSize(Node->For.Condition);
-               ret += AST_GetNodeSize(Node->For.Increment);
-               ret += AST_GetNodeSize(Node->For.Code);
-               break;
-       
-       // Asignment
-       case NODETYPE_ASSIGN:
-               ret += sizeof(Node->Assign);
-               ret += AST_GetNodeSize(Node->Assign.Dest);
-               ret += AST_GetNodeSize(Node->Assign.Value);
-               break;
-       
-       // Casting
-       case NODETYPE_CAST:
-               ret += sizeof(Node->Cast);
-               ret += AST_GetNodeSize(Node->Cast.Value);
-               break;
-       
-       // Define a variable
-       case NODETYPE_DEFVAR:
-               ret += sizeof(Node->DefVar) + strlen(Node->DefVar.Name) + 1;
-               for( node = Node->DefVar.LevelSizes; node; )
-               {
-                       ret += AST_GetNodeSize(node);
-                       node = node->NextSibling;
-               }
-               break;
-       
-       // Unary Operations
-       case NODETYPE_RETURN:
-               ret += sizeof(Node->UniOp);
-               ret += AST_GetNodeSize(Node->UniOp.Value);
-               break;
-       
-       // Binary Operations
-       case NODETYPE_INDEX:
-       case NODETYPE_ADD:
-       case NODETYPE_SUBTRACT:
-       case NODETYPE_MULTIPLY:
-       case NODETYPE_DIVIDE:
-       case NODETYPE_MODULO:
-       case NODETYPE_BITSHIFTLEFT:
-       case NODETYPE_BITSHIFTRIGHT:
-       case NODETYPE_BITROTATELEFT:
-       case NODETYPE_BWAND:    case NODETYPE_LOGICALAND:
-       case NODETYPE_BWOR:     case NODETYPE_LOGICALOR:
-       case NODETYPE_BWXOR:    case NODETYPE_LOGICALXOR:
-       case NODETYPE_EQUALS:
-       case NODETYPE_LESSTHAN:
-       case NODETYPE_GREATERTHAN:
-               ret += sizeof(Node->BinOp);
-               ret += AST_GetNodeSize( Node->BinOp.Left );
-               ret += AST_GetNodeSize( Node->BinOp.Right );
-               break;
-       
-       // Node types with no children
-       case NODETYPE_NOP:
-               break;
-       case NODETYPE_VARIABLE:
-       case NODETYPE_CONSTANT:
-               ret += sizeof(Node->Variable) + strlen(Node->Variable.Name) + 1;
-               break;
-       case NODETYPE_STRING:
-               ret += sizeof(Node->String) + Node->String.Length;
-               break;
-       case NODETYPE_INTEGER:
-               ret += sizeof(Node->Integer);
-               break;
-       case NODETYPE_REAL:
-               ret += sizeof(Node->Real);
-               break;
-       }
-       return ret;
-}
-
-#if 1
-
 #define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
        if(_buffer)     memcpy((char*)_buffer + _offset, _dataptr, _len);\
        _offset += _len; \
@@ -220,6 +95,8 @@ size_t AST_GetNodeSize(tAST_Node *Node)
        int len = strlen(_string);\
        WRITE_16(_buffer, _offset, len);\
        WRITE_N(_buffer, _offset, len, _string);\
+       if((_offset & 1) == 1)WRITE_8(_buffer, _offset, 0); \
+       if((_offset & 3) == 2)WRITE_16(_buffer, _offset, 0); \
 } while(0)
 #define WRITE_NODELIST(_buffer, _offset, _listHead)    do {\
        tAST_Node *node; \
@@ -262,8 +139,8 @@ size_t AST_WriteScript(void *Buffer, tAST_Script *Script)
  */
 size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
 {
-       off_t   ptr;
-       typeof(Offset)  baseOfs = Offset;
+       size_t  ptr;
+       size_t  baseOfs = Offset;
        
        if(!Node) {
                fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
@@ -271,9 +148,11 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
        }
        
        WRITE_32(Buffer, Offset, 0);    // Next
-       WRITE_8(Buffer, Offset, Node->Type);
-       //WRITE_32(Buffer, Offset, 0);  // File
+       WRITE_16(Buffer, Offset, Node->Type);
+       // TODO: Scan the buffer for the location of the filename (with NULL byte)
+       //       else, write the string at the end of the node
        WRITE_16(Buffer, Offset, Node->Line);   // Line
+       //WRITE_32(Buffer, Offset, 0);  // File
        
        switch(Node->Type)
        {
@@ -283,83 +162,65 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
                break;
        
        // Function Call
+       case NODETYPE_METHODCALL:
+               Offset += AST_WriteNode(Buffer, Offset, Node->FunctionCall.Object);
        case NODETYPE_FUNCTIONCALL:
+       case NODETYPE_CREATEOBJECT:
+               // TODO: Search for the same function name and add a pointer
                WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
                WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
                break;
        
        // If node
        case NODETYPE_IF:
-               ptr = Offset;
-               WRITE_32(Buffer, Offset, 0);    // Condition
-               WRITE_32(Buffer, Offset, 0);    // True
-               WRITE_32(Buffer, Offset, 0);    // False
-               
                Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
-               WRITE_32(Buffer, ptr, Offset);
                break;
        
        // Looping Construct (For loop node)
        case NODETYPE_LOOP:
                WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
-               ptr = Offset;
-               WRITE_32(Buffer, Offset, 0);    // Init
-               WRITE_32(Buffer, Offset, 0);    // Condition
-               WRITE_32(Buffer, Offset, 0);    // Increment
-               WRITE_32(Buffer, Offset, 0);    // Code
                
                Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
-               WRITE_32(Buffer, ptr, Offset);
                break;
        
        // Asignment
        case NODETYPE_ASSIGN:
                WRITE_8(Buffer, Offset, Node->Assign.Operation);
-               ptr = Offset;
-               WRITE_32(Buffer, Offset, 0);    // Dest
-               WRITE_32(Buffer, Offset, 0);    // Value
-               
                Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
-               WRITE_32(Buffer, ptr, Offset);
                break;
        
        // Casting
        case NODETYPE_CAST:
                WRITE_8(Buffer, Offset, Node->Cast.DataType);
-               ptr = Offset;
-               WRITE_32(Buffer, Offset, 0);
-               
                Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
-               WRITE_32(Buffer, ptr, Offset);
                break;
        
        // Define a variable
        case NODETYPE_DEFVAR:
                WRITE_8(Buffer, Offset, Node->DefVar.DataType);
-               WRITE_8(Buffer, Offset, Node->DefVar.Depth);
+               // TODO: Duplicate compress the strings
                WRITE_STR(Buffer, Offset, Node->DefVar.Name);
                
                WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes);
                break;
        
+       // Scope Reference
+       case NODETYPE_SCOPE:
+       case NODETYPE_ELEMENT:
+               WRITE_STR(Buffer, Offset, Node->Scope.Name);
+               Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
+               break;
+       
        // Unary Operations
        case NODETYPE_RETURN:
                ptr = Offset;
-               WRITE_32(Buffer, Offset, 0);
                Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
-               WRITE_32(Buffer, ptr, Offset);
                break;
        
        // Binary Operations
@@ -378,13 +239,8 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
        case NODETYPE_EQUALS:
        case NODETYPE_LESSTHAN:
        case NODETYPE_GREATERTHAN:
-               ptr = Offset;
-               WRITE_32(Buffer, Offset, 0);    // Left
-               WRITE_32(Buffer, Offset, 0);    // Right
                Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
-               WRITE_32(Buffer, ptr, Offset);
                Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
-               WRITE_32(Buffer, ptr, Offset);
                break;
        
        // Node types with no children
@@ -392,6 +248,7 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
                break;
        case NODETYPE_VARIABLE:
        case NODETYPE_CONSTANT:
+               // TODO: De-Duplicate the strings
                WRITE_STR(Buffer, Offset, Node->Variable.Name);
                break;
        case NODETYPE_STRING:
@@ -405,143 +262,13 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
                WRITE_REAL(Buffer, Offset, Node->Real);
                break;
        
-       default:
-               fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
-               break;
+       //default:
+       //      fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
+       //      break;
        }
        
        return Offset - baseOfs;
 }
-#elif 0
-/**
- * \brief Write a node to a file
- */
-void AST_WriteNode(FILE *FP, tAST_Node *Node)
-{
-       tAST_Node       *node;
-       intptr_t        ptr;
-        int    ret;
-       
-       if(!Node)       return ;
-       
-       ptr = ftell(FP) + AST_GetNodeSize(Node);
-       fwrite(&ptr, sizeof(ptr), 1, FP);
-       fwrite(&Node->Type, sizeof(Node->Type), 1, FP);
-       ptr = 0;        fwrite(&ptr, sizeof(ptr), 1, FP);       // File
-       fwrite(&Node->Line, sizeof(Node->Line), 1, FP);
-       
-       ret = sizeof(tAST_Node*) + sizeof(tAST_NodeType)
-               + sizeof(const char *) + sizeof(int);
-       
-       switch(Node->Type)
-       {
-       // Block of code
-       case NODETYPE_BLOCK:
-               ret += sizeof(Node->Block);
-               for( node = Node->Block.FirstChild; node; )
-               {
-                       ret += AST_GetNodeSize(node);
-                       node = node->NextSibling;
-               }
-               break;
-       
-       // Function Call
-       case NODETYPE_FUNCTIONCALL:
-               ret += sizeof(Node->FunctionCall) + strlen(Node->FunctionCall.Name) + 1;
-               for( node = Node->FunctionCall.FirstArg; node; )
-               {
-                       ret += AST_GetNodeSize(node);
-                       node = node->NextSibling;
-               }
-               break;
-       
-       // If node
-       case NODETYPE_IF:
-               ret += sizeof(Node->If);
-               ret += AST_GetNodeSize(Node->If.Condition);
-               ret += AST_GetNodeSize(Node->If.True);
-               ret += AST_GetNodeSize(Node->If.False);
-               break;
-       
-       // Looping Construct (For loop node)
-       case NODETYPE_LOOP:
-               ret += sizeof(Node->For);
-               ret += AST_GetNodeSize(Node->For.Init);
-               ret += AST_GetNodeSize(Node->For.Condition);
-               ret += AST_GetNodeSize(Node->For.Increment);
-               ret += AST_GetNodeSize(Node->For.Code);
-               break;
-       
-       // Asignment
-       case NODETYPE_ASSIGN:
-               ret += sizeof(Node->Assign);
-               ret += AST_GetNodeSize(Node->Assign.Dest);
-               ret += AST_GetNodeSize(Node->Assign.Value);
-               break;
-       
-       // Casting
-       case NODETYPE_CAST:
-               ret += sizeof(Node->Cast);
-               ret += AST_GetNodeSize(Node->Cast.Value);
-               break;
-       
-       // Define a variable
-       case NODETYPE_DEFVAR:
-               ret += sizeof(Node->DefVar) + strlen(Node->DefVar.Name) + 1;
-               for( node = Node->DefVar.LevelSizes; node; )
-               {
-                       ret += AST_GetNodeSize(node);
-                       node = node->NextSibling;
-               }
-               break;
-       
-       // Unary Operations
-       case NODETYPE_RETURN:
-               ret += sizeof(Node->UniOp);
-               ret += AST_GetNodeSize(Node->UniOp.Value);
-               break;
-       
-       // Binary Operations
-       case NODETYPE_INDEX:
-       case NODETYPE_ADD:
-       case NODETYPE_SUBTRACT:
-       case NODETYPE_MULTIPLY:
-       case NODETYPE_DIVIDE:
-       case NODETYPE_MODULO:
-       case NODETYPE_BITSHIFTLEFT:
-       case NODETYPE_BITSHIFTRIGHT:
-       case NODETYPE_BITROTATELEFT:
-       case NODETYPE_BWAND:    case NODETYPE_LOGICALAND:
-       case NODETYPE_BWOR:     case NODETYPE_LOGICALOR:
-       case NODETYPE_BWXOR:    case NODETYPE_LOGICALXOR:
-       case NODETYPE_EQUALS:
-       case NODETYPE_LESSTHAN:
-       case NODETYPE_GREATERTHAN:
-               ret += sizeof(Node->BinOp);
-               ret += AST_GetNodeSize( Node->BinOp.Left );
-               ret += AST_GetNodeSize( Node->BinOp.Right );
-               break;
-       
-       // Node types with no children
-       case NODETYPE_NOP:
-               break;
-       case NODETYPE_VARIABLE:
-       case NODETYPE_CONSTANT:
-               ret += sizeof(Node->Variable) + strlen(Node->Variable.Name) + 1;
-               break;
-       case NODETYPE_STRING:
-               ret += sizeof(Node->String) + Node->String.Length;
-               break;
-       case NODETYPE_INTEGER:
-               ret += sizeof(Node->Integer);
-               break;
-       case NODETYPE_REAL:
-               ret += sizeof(Node->Real);
-               break;
-       }
-       return ret;
-}
-#endif
 
 /**
  * \brief Free a node and all subnodes
@@ -565,7 +292,10 @@ void AST_FreeNode(tAST_Node *Node)
                break;
        
        // Function Call
+       case NODETYPE_METHODCALL:
+               AST_FreeNode(Node->FunctionCall.Object);
        case NODETYPE_FUNCTIONCALL:
+       case NODETYPE_CREATEOBJECT:
                for( node = Node->FunctionCall.FirstArg; node; )
                {
                        tAST_Node       *savedNext = node->NextSibling;
@@ -600,6 +330,11 @@ void AST_FreeNode(tAST_Node *Node)
                AST_FreeNode(Node->Cast.Value);
                break;
        
+       case NODETYPE_SCOPE:
+       case NODETYPE_ELEMENT:
+               AST_FreeNode(Node->Scope.Element);
+               break;
+       
        // Define a variable
        case NODETYPE_DEFVAR:
                for( node = Node->DefVar.LevelSizes; node; )
@@ -646,12 +381,12 @@ void AST_FreeNode(tAST_Node *Node)
        free( Node );
 }
 
-tAST_Node *AST_NewCodeBlock(void)
+tAST_Node *AST_NewCodeBlock(tParser *Parser)
 {
        tAST_Node       *ret = malloc( sizeof(tAST_Node) );
        
        ret->NextSibling = NULL;
-       //ret->Line = Parser->CurLine;
+       ret->Line = Parser->CurLine;
        ret->Type = NODETYPE_BLOCK;
        ret->Block.FirstChild = NULL;
        ret->Block.LastChild = NULL;
@@ -850,6 +585,34 @@ tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
        ret->NextSibling = NULL;
        ret->Line = Parser->CurLine;
        ret->Type = NODETYPE_FUNCTIONCALL;
+       ret->FunctionCall.Object = NULL;
+       ret->FunctionCall.FirstArg = NULL;
+       ret->FunctionCall.LastArg = NULL;
+       strcpy(ret->FunctionCall.Name, Name);
+       return ret;
+}
+tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       
+       ret->NextSibling = NULL;
+       ret->Line = Parser->CurLine;
+       ret->Type = NODETYPE_METHODCALL;
+       ret->FunctionCall.Object = Object;
+       ret->FunctionCall.FirstArg = NULL;
+       ret->FunctionCall.LastArg = NULL;
+       strcpy(ret->FunctionCall.Name, Name);
+       return ret;
+}
+
+tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       
+       ret->NextSibling = NULL;
+       ret->Line = Parser->CurLine;
+       ret->Type = NODETYPE_CREATEOBJECT;
+       ret->FunctionCall.Object = NULL;
        ret->FunctionCall.FirstArg = NULL;
        ret->FunctionCall.LastArg = NULL;
        strcpy(ret->FunctionCall.Name, Name);
@@ -861,7 +624,13 @@ tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
  */
 void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
 {
-       if( Node->Type != NODETYPE_FUNCTIONCALL )       return ;
+       if( Node->Type != NODETYPE_FUNCTIONCALL
+        && Node->Type != NODETYPE_CREATEOBJECT
+        && Node->Type != NODETYPE_METHODCALL)
+       {
+               fprintf(stderr, "BUG REPORT: AST_AppendFunctionCallArg on an invalid node type (%i)\n", Node->Type);
+               return ;
+       }
        
        if(Node->FunctionCall.LastArg) {
                Node->FunctionCall.LastArg->NextSibling = Arg;
@@ -873,6 +642,36 @@ void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
        }
 }
 
+/**
+ * \brief Add a scope node
+ */
+tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       
+       ret->NextSibling = NULL;
+       ret->Line = Parser->CurLine;
+       ret->Type = NODETYPE_SCOPE;
+       ret->Scope.Element = Child;
+       strcpy(ret->Scope.Name, Name);
+       return ret;
+}
+
+/**
+ * \brief Add a scope node
+ */
+tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       
+       ret->NextSibling = NULL;
+       ret->Line = Parser->CurLine;
+       ret->Type = NODETYPE_ELEMENT;
+       ret->Scope.Element = Object;
+       strcpy(ret->Scope.Name, Name);
+       return ret;
+}
+
 /**
  * \}
  */
index 1118130..c6593ac 100644 (file)
@@ -29,11 +29,15 @@ enum eAST_NodeTypes
        NODETYPE_REAL,  //!< Real Constant
        
        NODETYPE_DEFVAR,        //!< Define a variable (Variable)
+       NODETYPE_SCOPE, //!< Dereference a Namespace/Class static
+       NODETYPE_ELEMENT,       //!< Reference a class attribute
        NODETYPE_CAST,  //!< Cast a value to another (Uniop)
        
        NODETYPE_RETURN,        //!< Return from a function (reserved word)
        NODETYPE_ASSIGN,        //!< Variable assignment operator
        NODETYPE_FUNCTIONCALL,  //!< Call a function
+       NODETYPE_METHODCALL,    //!< Call a class method
+       NODETYPE_CREATEOBJECT,  //!< Create an object
        
        NODETYPE_IF,    //!< Conditional
        NODETYPE_LOOP,  //!< Looping Construct
@@ -72,6 +76,7 @@ struct sSpiderScript
 
 struct sAST_Script
 {
+       // TODO: Namespaces and Classes
        tAST_Function   *Functions;
        tAST_Function   *LastFunction;
 };
@@ -116,6 +121,7 @@ struct sAST_Node
                }       BinOp;
                
                struct {
+                       tAST_Node       *Object;
                        tAST_Node       *FirstArg;
                        tAST_Node       *LastArg;
                        char    Name[];
@@ -136,16 +142,21 @@ struct sAST_Node
                }       For;
                
                /**
-                * \note Used for \a NODETYPE_VARIABLE and \a NODETYPE_CONSTANT
+                * \note Used for \a NODETYPE_VARIABLE, \a NODETYPE_CONSTANT and
+                *       \a NODETYPE_SCOPE
                 */
                struct {
                        char    _unused;        // Shut GCC up
                        char    Name[];
                }       Variable;
                
+               struct {
+                       tAST_Node       *Element;
+                       char    Name[];
+               }       Scope;  // Used by NODETYPE_SCOPE and NODETYPE_ELEMENT
+               
                struct {
                         int    DataType;
-                        int    Depth;
                        tAST_Node       *LevelSizes;
                        tAST_Node       *LevelSizes_Last;
                        char    Name[];
@@ -175,6 +186,8 @@ struct sAST_BlockState
        tSpiderScript   *Script;        //!< Script
        tAST_Variable   *FirstVar;      //!< First variable in the list
        tSpiderValue    *RetVal;
+       tSpiderNamespace        *BaseNamespace; //!< Base namespace (for entire block)
+       tSpiderNamespace        *CurNamespace;  //!< Currently selected namespace
 };
 
 struct sAST_Variable
@@ -193,15 +206,20 @@ extern size_t     AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node);
 extern tAST_Function   *AST_AppendFunction(tAST_Script *Script, const char *Name);
 extern void    AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Arg);
 extern void    AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root);
+
 extern tAST_Node       *AST_NewString(tParser *Parser, const char *String, int Length);
 extern tAST_Node       *AST_NewInteger(tParser *Parser, uint64_t Value);
 extern tAST_Node       *AST_NewVariable(tParser *Parser, const char *Name);
 extern tAST_Node       *AST_NewDefineVar(tParser *Parser, int Type, const char *Name);
 extern tAST_Node       *AST_NewConstant(tParser *Parser, const char *Name);
+extern tAST_Node       *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name);
+
 extern tAST_Node       *AST_NewFunctionCall(tParser *Parser, const char *Name);
+extern tAST_Node       *AST_NewCreateObject(tParser *Parser, const char *Name);
+extern tAST_Node       *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name);
 extern void    AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg);
 
-extern tAST_Node       *AST_NewCodeBlock(void);
+extern tAST_Node       *AST_NewCodeBlock(tParser *Parser);
 extern void    AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
 
 extern tAST_Node       *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False);
@@ -211,6 +229,7 @@ extern tAST_Node    *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest,
 extern tAST_Node       *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value);
 extern tAST_Node       *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right);
 extern tAST_Node       *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value);
+extern tAST_Node       *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child);
 
 extern void    AST_FreeNode(tAST_Node *Node);
 
index b6b569f..e0de9ff 100644 (file)
@@ -6,6 +6,9 @@
 #include <string.h>
 #include "ast.h"
 
+// === IMPORTS ===
+extern tSpiderFunction *gpExports_First;
+
 // === PROTOTYPES ===
 void   Object_Dereference(tSpiderValue *Object);
 void   Object_Reference(tSpiderValue *Object);
@@ -60,6 +63,22 @@ void Object_Reference(tSpiderValue *Object)
 //     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
  */
@@ -93,7 +112,10 @@ tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
        ret->Type = SS_DATATYPE_STRING;
        ret->ReferenceCount = 1;
        ret->String.Length = Length;
-       memcpy(ret->String.Data, Data, Length);
+       if( Data )
+               memcpy(ret->String.Data, Data, Length);
+       else
+               memset(ret->String.Data, 0, Length);
        ret->String.Data[Length] = '\0';
        return ret;
 }
@@ -141,11 +163,36 @@ tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
                return Source;
        }
        
+       #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:
+       case SS_DATATYPE_OBJECT:
                AST_RuntimeError(NULL, "Invalid cast to %i", Type);
                return ERRPTR;
        
@@ -297,6 +344,310 @@ char *SpiderScript_DumpValue(tSpiderValue *Value)
        
 }
 
+/**
+ * \brief Execute a script function
+ * \param Script       Script context to execute in
+ * \param Function     Function name to execute
+ * \param NArguments   Number of arguments to pass
+ * \param Arguments    Arguments passed
+ */
+tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script,
+       tSpiderNamespace *Namespace, const char *Function,
+       int NArguments, tSpiderValue **Arguments)
+{
+       char    *trueName = NULL;
+        int    bFound = 0;     // Used to keep nesting levels down
+       tSpiderValue    *ret = ERRPTR;
+       tSpiderFunction *fcn;
+       
+       // First: Find the function in the script
+       {
+               tAST_Function   *astFcn;
+               for( astFcn = Script->Script->Functions; astFcn; astFcn = astFcn->Next )
+               {
+                       if( strcmp(astFcn->Name, Function) == 0 )
+                               break;
+               }
+               // Execute!
+               if(astFcn)
+               {
+                       tAST_BlockState bs;
+                       tAST_Node       *arg;
+                        int    i = 0;
+                       
+                       // Build a block State
+                       bs.FirstVar = NULL;
+                       bs.RetVal = NULL;
+                       bs.Parent = NULL;
+                       bs.BaseNamespace = &Script->Variant->RootNamespace;
+                       bs.CurNamespace = NULL;
+                       bs.Script = Script;
+                       
+                       
+                       for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
+                       {
+                               // TODO: Type checks
+                               Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
+                               if( i >= NArguments )   break;  // TODO: Return gracefully
+                               Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
+                       }
+                       
+                       // Execute function
+                       ret = AST_ExecuteNode(&bs, astFcn->Code);
+                       Object_Dereference(ret);        // Dereference output of last block statement
+                       ret = bs.RetVal;        // Set to return value of block
+                       bFound = 1;
+                       
+                       while(bs.FirstVar)
+                       {
+                               tAST_Variable   *nextVar = bs.FirstVar->Next;
+                               Variable_Destroy( bs.FirstVar );
+                               bs.FirstVar = nextVar;
+                       }
+               }
+       }
+       
+       // Didn't find it in script?
+       if(!bFound)
+       {
+               fcn = NULL;     // Just to allow the below code to be neat
+               
+               // Second: Scan current namespace
+               if( !fcn && Namespace )
+               {
+                       for( fcn = Namespace->Functions; fcn; fcn = fcn->Next )
+                       {
+                               if( strcmp( fcn->Name, Function ) == 0 )
+                                       break;
+                       }
+               }
+               
+               // Third: Search the variant's global exports
+               if( !fcn )
+               {
+                       for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
+                       {
+                               if( strcmp( fcn->Name, Function ) == 0 )
+                                       break;
+                       }
+               }
+               
+               // Fourth: Search language exports
+               if( !fcn )
+               {
+                       for( fcn = gpExports_First; fcn; fcn = fcn->Next )
+                       {
+                               if( strcmp( fcn->Name, Function ) == 0 )
+                                       break;
+                       }
+               }
+               
+               // Execute!
+               if(fcn)
+               {
+                       // TODO: Type Checking
+                       ret = fcn->Handler( Script, NArguments, Arguments );
+                       bFound = 1;
+               }
+       }
+       
+       // Not found?
+       if(!bFound)
+       {
+               fprintf(stderr, "Undefined reference to '%s'\n", trueName);
+               return ERRPTR;
+       }
+       
+       return ret;
+}
+
+/**
+ * \brief Execute an object method function
+ * \param Script       Script context to execute in
+ * \param Function     Function name to execute
+ * \param NArguments   Number of arguments to pass
+ * \param Arguments    Arguments passed
+ */
+tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script, tSpiderObject *Object,
+       const char *MethodName,
+       int NArguments, tSpiderValue **Arguments)
+{
+       tSpiderFunction *fcn;
+       tSpiderValue    this;
+       tSpiderValue    *newargs[NArguments+1];
+        int    i;
+       
+       for( fcn = Object->Type->Methods; fcn; fcn = fcn->Next )
+       {
+               if( strcmp(fcn->Name, MethodName) == 0 )
+                       break;
+       }
+       
+       if( !fcn )
+       {
+               AST_RuntimeError(NULL, "Class '%s' does not have a method '%s'",
+                       Object->Type->Name, MethodName);
+               return ERRPTR;
+       }
+       
+       this.Type = SS_DATATYPE_OBJECT;
+       this.ReferenceCount = 1;
+       this.Object = Object;
+       
+       newargs[0] = &this;
+       memcpy(&newargs[1], Arguments, NArguments*sizeof(tSpiderValue*));
+       
+       // TODO: Type Checking
+       for( i = 0; fcn->ArgTypes[i]; i ++ )
+       {
+               if( i >= NArguments ) {
+                       AST_RuntimeError(NULL, "Argument count mismatch (%i passed)",
+                               NArguments);
+                       return ERRPTR;
+               }
+               if( Arguments[i] && Arguments[i]->Type != fcn->ArgTypes[i] )
+               {
+                       AST_RuntimeError(NULL, "Argument type mismatch (%i, expected %i)",
+                               Arguments[i]->Type, fcn->ArgTypes[i]);
+                       return ERRPTR;
+               }
+       }
+       
+       return fcn->Handler(Script, NArguments+1, newargs);
+}
+
+/**
+ * \brief Execute a script function
+ * \param Script       Script context to execute in
+ * \param Function     Function name to execute
+ * \param NArguments   Number of arguments to pass
+ * \param Arguments    Arguments passed
+ */
+tSpiderValue *SpiderScript_CreateObject(tSpiderScript *Script,
+       tSpiderNamespace *Namespace, const char *ClassName,
+       int NArguments, tSpiderValue **Arguments)
+{
+        int    bFound = 0;     // Used to keep nesting levels down
+       tSpiderValue    *ret = ERRPTR;
+       tSpiderObjectDef        *class;
+       
+       // First: Find the function in the script
+       // TODO: Implement scripted classes
+       #if 0
+       {
+               tAST_Function   *astClass;
+               for( astClass = Script->Script->Classes; astClass; astClass = astClass->Next )
+               {
+                       if( strcmp(astClass->Name, ClassName) == 0 )
+                               break;
+               }
+               // Execute!
+               if(astClass)
+               {
+                       tAST_BlockState bs;
+                       tAST_Node       *arg;
+                        int    i = 0;
+                       
+                       // Build a block State
+                       bs.FirstVar = NULL;
+                       bs.RetVal = NULL;
+                       bs.Parent = NULL;
+                       bs.BaseNamespace = &Script->Variant->RootNamespace;
+                       bs.CurNamespace = NULL;
+                       bs.Script = Script;
+                       
+                       
+                       for( arg = astFcn->Arguments; arg; arg = arg->NextSibling, i++ )
+                       {
+                               // TODO: Type checks
+                               Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
+                               if( i >= NArguments )   break;  // TODO: Return gracefully
+                               Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
+                       }
+                       
+                       // Execute function
+                       ret = AST_ExecuteNode(&bs, astFcn->Code);
+                       Object_Dereference(ret);        // Dereference output of last block statement
+                       ret = bs.RetVal;        // Set to return value of block
+                       bFound = 1;
+                       
+                       while(bs.FirstVar)
+                       {
+                               tAST_Variable   *nextVar = bs.FirstVar->Next;
+                               Variable_Destroy( bs.FirstVar );
+                               bs.FirstVar = nextVar;
+                       }
+               }
+       }
+       #endif
+       
+       // Didn't find it in script?
+       if(!bFound)
+       {
+               class = NULL;   // Just to allow the below code to be neat
+               
+               // Second: Scan current namespace
+               if( !class && Namespace )
+               {
+                       for( class = Namespace->Classes; class; class = class->Next )
+                       {
+                               if( strcmp( class->Name, ClassName ) == 0 )
+                                       break;
+                       }
+               }
+               
+               #if 0
+               // Third: Search the variant's global exports
+               if( !class )
+               {
+                       for( class = Script->Variant->Classes; class; class = fcn->Next )
+                       {
+                               if( strcmp( class->Name, Function ) == 0 )
+                                       break;
+                       }
+               }
+               #endif
+               
+               #if 0
+               // Fourth: Search language exports
+               if( !class )
+               {
+                       for( class = gpExports_First; class; class = fcn->Next )
+                       {
+                               if( strcmp( class->Name, ClassName ) == 0 )
+                                       break;
+                       }
+               }
+               #endif
+               
+               // Execute!
+               if(class)
+               {
+                       tSpiderObject   *obj;
+                       // TODO: Type Checking
+                       obj = class->Constructor( NArguments, Arguments );
+                       if( obj == NULL || obj == ERRPTR )
+                               return (void *)obj;
+                       
+                       ret = malloc( sizeof(tSpiderValue) );
+                       ret->Type = SS_DATATYPE_OBJECT;
+                       ret->ReferenceCount = 1;
+                       ret->Object = obj;
+                       bFound = 1;
+               }
+       }
+       
+       // Not found?
+       if(!bFound)
+       {
+               fprintf(stderr, "Undefined reference to '%s'\n", ClassName);
+               return ERRPTR;
+       }
+       
+       return ret;
+}
+
+
 /**
  * \brief Execute an AST node and return its value
  */
@@ -306,6 +657,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
        tSpiderValue    *ret = NULL, *tmpobj;
        tSpiderValue    *op1, *op2;     // Binary operations
         int    cmp;    // Used in comparisons
+        int    i=0;
        
        switch(Node->Type)
        {
@@ -316,10 +668,10 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
        case NODETYPE_BLOCK:
                {
                        tAST_BlockState blockInfo;
+                       memcpy(&blockInfo, Block, sizeof(tAST_BlockState));
                        blockInfo.FirstVar = NULL;
                        blockInfo.RetVal = NULL;
                        blockInfo.Parent = Block;
-                       blockInfo.Script = Block->Script;
                        ret = NULL;
                        for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
                        {
@@ -374,7 +726,9 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                break;
        
        // Function Call
+       case NODETYPE_METHODCALL:
        case NODETYPE_FUNCTIONCALL:
+       case NODETYPE_CREATEOBJECT:
                {
                         int    nParams = 0;
                        for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
@@ -383,8 +737,9 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        // Logical block (used to allocate `params`)
                        {
                                tSpiderValue    *params[nParams];
-                                int    i=0;
-                               for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
+                               i = 0;
+                               for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
+                               {
                                        params[i] = AST_ExecuteNode(Block, node);
                                        if( params[i] == ERRPTR ) {
                                                while(i--)      Object_Dereference(params[i]);
@@ -394,9 +749,42 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                                        i ++;
                                }
                                
-                               // Call the function (SpiderScript_ExecuteMethod does the
-                               // required namespace handling)
-                               ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
+                               if( !Block->CurNamespace )
+                                       Block->CurNamespace = Block->BaseNamespace;
+                               
+                               // Call the function
+                               if( Node->Type == NODETYPE_CREATEOBJECT )
+                               {
+                                       ret = SpiderScript_CreateObject(Block->Script,
+                                               Block->CurNamespace,
+                                               Node->FunctionCall.Name,
+                                               nParams, params
+                                               );
+                               }
+                               else if( Node->Type == NODETYPE_METHODCALL )
+                               {
+                                       tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
+                                       if( !obj || 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]);
+                                               ret = ERRPTR;
+                                               break;
+                                       }
+                                       ret = SpiderScript_ExecuteMethod(Block->Script,
+                                               obj->Object, Node->FunctionCall.Name,
+                                               nParams, params
+                                               );
+                                       Object_Dereference(obj);
+                               }
+                               else
+                               {
+                                       ret = SpiderScript_ExecuteFunction(Block->Script,
+                                               Block->CurNamespace, Node->FunctionCall.Name,
+                                               nParams, params
+                                               );
+                               }
+
                                
                                // Dereference parameters
                                while(i--)      Object_Dereference(params[i]);
@@ -454,7 +842,6 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
        case NODETYPE_RETURN:
                ret = AST_ExecuteNode(Block, Node->UniOp.Value);
                Block->RetVal = ret;    // Return value set
-               //Object_Reference(ret);        // Make sure it exists after return
                ret = NULL;     // the `return` statement does not return a value
                break;
        
@@ -465,31 +852,128 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
                        ret = ERRPTR;
                break;
        
+       // Scope
+       case NODETYPE_SCOPE:
+               {
+               tSpiderNamespace        *ns;
+               
+               // Set current namespace if unset
+               if( !Block->CurNamespace )
+                       Block->CurNamespace = Block->BaseNamespace;
+               
+               // Empty string means use the root namespace
+               if( Node->Scope.Name[0] == '\0' )
+               {
+                       ns = &Block->Script->Variant->RootNamespace;
+               }
+               else
+               {
+                       // Otherwise scan the current namespace for the element
+                       for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
+                       {
+                               if( strcmp(ns->Name, Node->Scope.Name) == 0 )
+                                       break;
+                       }
+               }
+               if(!ns) {
+                       AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
+                       ret = ERRPTR;
+                       break;
+               }
+               Block->CurNamespace = ns;
+               
+               ret = AST_ExecuteNode(Block, Node->Scope.Element);
+               }
+               break;
+       
        // Variable
        case NODETYPE_VARIABLE:
                ret = Variable_GetValue( Block, Node->Variable.Name );
                break;
+       
+       // Element of an Object
+       case NODETYPE_ELEMENT:
+               tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
+               if( tmpobj->Type != SS_DATATYPE_OBJECT )
+               {
+                       AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
+                       ret = ERRPTR;
+                       break ;
+               }
+               
+               for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
+               {
+                       if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
+                       {
+                               ret = tmpobj->Object->Attributes[i];
+                               Object_Reference(ret);
+                               break;
+                       }
+               }
+               if( i == tmpobj->Object->Type->NAttributes )
+               {
+                       AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
+                               Node->Scope.Name, tmpobj->Object->Type->Name);
+                       ret = ERRPTR;
+               }
+               break;
 
        // Cast a value to another
        case NODETYPE_CAST:
                {
-               tSpiderValue    *tmp = AST_ExecuteNode(Block, Node->Cast.Value);
-               ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmp );
-               Object_Dereference(tmp);
+               tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
+               ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
+               Object_Dereference(tmpobj);
                }
                break;
 
        // Index into an array
        case NODETYPE_INDEX:
-               AST_RuntimeError(Node, "TODO - Array Indexing");
-               ret = ERRPTR;
+               op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
+               op2 = AST_ExecuteNode(Block, Node->BinOp.Right);        // Offset
+               
+               if( op1->Type != SS_DATATYPE_ARRAY )
+               {
+                       // TODO: Implement "operator []" on objects
+                       AST_RuntimeError(Node, "Indexing non-array");
+                       ret = ERRPTR;
+                       break;
+               }
+               
+               if( op2->Type != SS_DATATYPE_INTEGER && !Block->Script->Variant->bImplicitCasts ) {
+                       AST_RuntimeError(Node, "Array index is not an integer");
+                       ret = ERRPTR;
+                       break;
+               }
+               
+               if( op2->Type != SS_DATATYPE_INTEGER )
+               {
+                       tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
+                       Object_Dereference(op2);
+                       op2 = tmpobj;
+               }
+               
+               if( op2->Integer >= op1->Array.Length ) {
+                       AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
+                               op2->Integer, op1->Array.Length);
+                       ret = ERRPTR;
+                       break;
+               }
+               
+               ret = op1->Array.Items[ op2->Integer ];
+               Object_Reference(ret);
+               
+               Object_Dereference(op1);
+               Object_Dereference(op2);
                break;
 
        // TODO: Implement runtime constants
        case NODETYPE_CONSTANT:
+               // TODO: Scan namespace for function
                AST_RuntimeError(Node, "TODO - Runtime Constants");
                ret = ERRPTR;
                break;
+       
        // Constant Values
        case NODETYPE_STRING:   ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data );      break;
        case NODETYPE_INTEGER:  ret = SpiderScript_CreateInteger( Node->Integer );      break;
index 6ebd277..20554f5 100644 (file)
@@ -10,7 +10,6 @@
 
 // === IMPORTS ===
 extern tAST_Script     *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
-extern tSpiderFunction *gpExports_First;
 extern tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
 extern void    Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
 extern void    Variable_Destroy(tAST_Variable *Variable);
@@ -82,7 +81,7 @@ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filen
                if(!fp) return ret;
                
                data = malloc(size);
-               AST_WriteScript(data, ret->Script);
+               size = AST_WriteScript(data, ret->Script);
                fwrite(data, size, 1, fp);
                free(data);
                fclose(fp);
@@ -91,122 +90,6 @@ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filen
        return ret;
 }
 
-/**
- * \brief Execute a script function
- * \param Script       Script context to execute in
- * \param Function     Function name to execute
- * \param NArguments   Number of arguments to pass
- * \param Arguments    Arguments passed
- */
-tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
-       const char *Function, int NArguments, tSpiderValue **Arguments)
-{
-       char    *trueName = NULL;
-        int    bFound = 0;     // Used to keep nesting levels down
-       tSpiderValue    *ret = ERRPTR;
-       
-       // Handle namespaces
-       if( Function[0] == '.' ) {
-               trueName = (char*)&Function[1];
-       }
-       else if( !Script->CurNamespace ) {
-               trueName = (char*)Function;
-       }
-       else {
-                int    len = strlen(Script->CurNamespace) + 1 + strlen(Function);
-               trueName = malloc( len + 1 );
-               strcpy(trueName, Script->CurNamespace);
-               strcat(trueName, ".");
-               strcat(trueName, Function);
-       }
-       
-       // First: Find the function in the script
-       {
-               tAST_Function   *fcn = Script->Script->Functions;
-               for( ; fcn; fcn = fcn->Next ) {
-                       if( strcmp(fcn->Name, trueName) == 0 )
-                               break;
-               }
-               // Execute!
-               if(fcn) {
-                       tAST_BlockState bs;
-                       bs.FirstVar = NULL;
-                       bs.RetVal = NULL;
-                       bs.Parent = NULL;
-                       bs.Script = Script;
-                       {
-                               tAST_Node       *arg;
-                                int    i = 0;
-                               for( arg = fcn->Arguments; arg; arg = arg->NextSibling, i++ )
-                               {
-                                       // TODO: Type checks
-                                       Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
-                                       if( i >= NArguments )   break;  // TODO: Return gracefully
-                                       Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
-                               }
-                       }
-                       ret = AST_ExecuteNode(&bs, fcn->Code);
-                       Object_Dereference(ret);
-                       ret = bs.RetVal;
-                       bFound = 1;
-                       
-                       while(bs.FirstVar)
-                       {
-                               tAST_Variable   *nextVar = bs.FirstVar->Next;
-                               Variable_Destroy( bs.FirstVar );
-                               bs.FirstVar = nextVar;
-                       }
-               }
-       }
-       
-       // Didn't find it in script?
-       if(!bFound)
-       {
-               tSpiderFunction *fcn;
-               // Second: Search the variant's exports
-               for( fcn = Script->Variant->Functions; fcn; fcn = fcn->Next )
-               {
-                       if( strcmp( fcn->Name, trueName ) == 0 )
-                               break;
-               }
-               // Execute!
-               if(fcn) {
-                       // TODO: Type Checking
-                       ret = fcn->Handler( Script, NArguments, Arguments );
-                       bFound = 1;
-               }
-       }
-       
-       // Not in variant exports? Search the language internal ones
-       if(!bFound)
-       {
-               tSpiderFunction *fcn;
-               // Third: Search language exports
-               for( fcn = gpExports_First; fcn; fcn = fcn->Next )
-               {
-                       if( strcmp( fcn->Name, trueName ) == 0 )
-                               break;
-               }
-               // Execute!
-               if(fcn) {
-                       ret = fcn->Handler( Script, NArguments, Arguments );
-                       bFound = 1;
-               }
-       }
-       
-       // Not found?
-       if(!bFound)
-       {
-               fprintf(stderr, "Undefined reference to '%s'\n", trueName);
-       }
-       
-       if( trueName != Function && trueName != &Function[1] )
-               free(trueName);
-       
-       return ret;
-       
-}
-
 /**
  * \brief Free a script
  */
index 6e1696e..907c729 100644 (file)
@@ -32,7 +32,7 @@ tAST_Node     *Parse_DoValue(tParser *Parser);        // Values
 tAST_Node      *Parse_GetString(tParser *Parser);
 tAST_Node      *Parse_GetNumeric(tParser *Parser);
 tAST_Node      *Parse_GetVariable(tParser *Parser);
-tAST_Node      *Parse_GetIdent(tParser *Parser);
+tAST_Node      *Parse_GetIdent(tParser *Parser, int bObjectCreate);
 
 void   SyntaxAssert(tParser *Parser, int Have, int Want);
 
@@ -67,7 +67,7 @@ tAST_Script   *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
        parser.CurPos = Buffer;
        
        ret = AST_NewScript();
-       mainCode = AST_NewCodeBlock();
+       mainCode = AST_NewCodeBlock(&parser);
        
        // Give us an error fallback
        if( setjmp( parser.JmpTarget ) != 0 )
@@ -173,7 +173,7 @@ tAST_Node *Parse_DoCodeBlock(tParser *Parser)
                return Parse_DoBlockLine(Parser);
        }
        
-       ret = AST_NewCodeBlock();
+       ret = AST_NewCodeBlock(Parser);
        
        while( LookAhead(Parser) != TOK_BRACE_CLOSE )
        {
@@ -543,8 +543,11 @@ tAST_Node *Parse_DoValue(tParser *Parser)
        {
        case TOK_STR:   return Parse_GetString(Parser);
        case TOK_INTEGER:       return Parse_GetNumeric(Parser);
-       case TOK_IDENT: return Parse_GetIdent(Parser);
+       case TOK_IDENT: return Parse_GetIdent(Parser, 0);
        case TOK_VARIABLE:      return Parse_GetVariable(Parser);
+       case TOK_RWD_NEW:
+               GetToken(Parser);       // Omnomnom
+               return Parse_GetIdent(Parser, 1);
 
        default:
                fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
@@ -658,32 +661,70 @@ tAST_Node *Parse_GetVariable(tParser *Parser)
                printf("Parse_GetVariable: name = '%s'\n", name);
                #endif
        }
-       // Handle array references
-       while( LookAhead(Parser) == TOK_SQUARE_OPEN )
+       for(;;)
        {
                GetToken(Parser);
-               ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
-               SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+               if( Parser->Token == TOK_SQUARE_OPEN )
+               {
+                       ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+                       continue ;
+               }
+               if( Parser->Token == TOK_ELEMENT )
+               {
+                       SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
+                       // Method Call
+                       if( LookAhead(Parser) == TOK_PAREN_OPEN )
+                       {
+                               char    name[Parser->TokenLen+1];
+                               memcpy(name, Parser->TokenStr, Parser->TokenLen);
+                               name[Parser->TokenLen] = 0;
+                               ret = AST_NewMethodCall(Parser, ret, name);
+                               GetToken(Parser);       // Eat the '('
+                               // Read arguments
+                               if( GetToken(Parser) != TOK_PAREN_CLOSE )
+                               {
+                                       PutBack(Parser);
+                                       do {
+                                               AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
+                                       } while(GetToken(Parser) == TOK_COMMA);
+                                       SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
+                               }
+                               
+                       }
+                       // Attribute
+                       else
+                       {
+                               char    name[Parser->TokenLen];
+                               memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
+                               name[Parser->TokenLen-1] = 0;
+                               ret = AST_NewClassElement(Parser, ret, name);
+                       }
+                       continue ;
+               }
+               
+               break ;
        }
+       PutBack(Parser);
        return ret;
 }
 
 /**
  * \brief Get an identifier (constant or function call)
  */
-tAST_Node *Parse_GetIdent(tParser *Parser)
+tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate)
 {
        tAST_Node       *ret = NULL;
        char    *name;
        SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
        name = strndup( Parser->TokenStr, Parser->TokenLen );
        
-       #if 0
-       while( GetToken(Parser) == TOK_SCOPE )
+       #if USE_SCOPE_CHAR
+       if( GetToken(Parser) == TOK_SCOPE )
        {
-               ret = AST_NewScopeDereference( Parser, ret, name );
-               SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
-               name = strndup( Parser->TokenStr, Parser->TokenLen );
+               ret = AST_NewScopeDereference( Parser, Parse_GetIdent(Parser, bObjectCreate), name );
+               free(name);
+               return ret;
        }
        PutBack(Parser);
        #endif
@@ -694,7 +735,10 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
                printf("Parse_GetIdent: Calling '%s'\n", name);
                #endif
                // Function Call
-               ret = AST_NewFunctionCall( Parser, name );
+               if( bObjectCreate )
+                       ret = AST_NewCreateObject( Parser, name );
+               else
+                       ret = AST_NewFunctionCall( Parser, name );
                // Read arguments
                if( GetToken(Parser) != TOK_PAREN_CLOSE )
                {
@@ -711,13 +755,17 @@ tAST_Node *Parse_GetIdent(tParser *Parser)
                        #endif
                }
        }
-       else {
+       else
+       {
                // Runtime Constant / Variable (When implemented)
                #if DEBUG >= 2
                printf("Parse_GetIdent: Referencing '%s'\n", name);
                #endif
                PutBack(Parser);
-               ret = AST_NewConstant( Parser, name );
+               if( bObjectCreate )     // Void constructor (TODO: Should this be an error?)
+                       ret = AST_NewCreateObject( Parser, name );
+               else
+                       ret = AST_NewConstant( Parser, name );
        }
        
        free(name);
index dc62a23..e6fdaab 100644 (file)
@@ -14,6 +14,7 @@
 typedef struct sSpiderScript   tSpiderScript;
 
 typedef struct sSpiderVariant  tSpiderVariant;
+typedef struct sSpiderNamespace        tSpiderNamespace;
 typedef struct sSpiderFunction tSpiderFunction;
 typedef struct sSpiderValue    tSpiderValue;
 typedef struct sSpiderObjectDef        tSpiderObjectDef;
@@ -64,6 +65,25 @@ enum eSpiderScript_DataTypes
        NUM_SS_DATATYPES
 };
 
+/**
+ * \brief Namespace definition
+ */
+struct sSpiderNamespace
+{
+       tSpiderNamespace        *Next;
+       
+       tSpiderNamespace        *FirstChild;
+       
+       tSpiderFunction *Functions;
+       
+       tSpiderObjectDef        *Classes;
+       
+        int    NConstants;     //!< Number of constants
+       tSpiderValue    *Constants;     //!< Number of constants
+       
+       const char      Name[];
+};
+
 /**
  * \brief Variant of SpiderScript
  */
@@ -71,12 +91,15 @@ struct sSpiderVariant
 {
        const char      *Name;  // Just for debug
        
-        int    bDyamicTyped;   //!< Use static typing
+        int    bDyamicTyped;   //!< Use dynamic typing
+        int    bImplicitCasts; //!< Allow implicit casts (casts to lefthand side)
        
        tSpiderFunction *Functions;     //!< Functions (Linked List)
        
         int    NConstants;     //!< Number of constants
        tSpiderValue    *Constants;     //!< Number of constants
+       
+       tSpiderNamespace        RootNamespace;
 };
 
 /**
@@ -133,16 +156,16 @@ struct sSpiderObjectDef
        /**
         * \brief Object type name
         */
-       const char*     const Name;
+       const char * const      Name;
        /**
         * \brief Construct an instance of the object
         * \param NArgs Number of arguments
-        * \param Args  Argument count
+        * \param Args  Argument array
         * \return Pointer to an object instance (which must be fully valid)
         * \retval NULL Invalid parameter (usually, actually just a NULL value)
         * \retval ERRPTR       Invalid parameter count
         */
-       tSpiderObject   *(*Constructor)(int NArgs, tSpiderValue *Args);
+       tSpiderObject   *(*Constructor)(int NArgs, tSpiderValue **Args);
        
        /**
         * \brief Clean up and destroy the object
@@ -152,17 +175,15 @@ struct sSpiderObjectDef
         */
        void    (*Destructor)(tSpiderObject *This);
        
+       tSpiderFunction *Methods;       //!< Method Definitions (linked list)
+       
         int    NAttributes;    //!< Number of attributes
        
        //! Attribute definitions
        struct {
                const char      *Name;  //!< Attribute Name
                 int    bReadOnly;      //!< Allow writes to the attribute?
-       }       *AttributeDefs;
-       
-       
-        int    NMethods;       //!< Number of methods
-       tSpiderFunction *Methods;       //!< Method Definitions
+       }       AttributeDefs[];
 };
 
 /**
@@ -171,7 +192,7 @@ struct sSpiderObjectDef
 struct sSpiderObject
 {
        tSpiderObjectDef        *Type;  //!< Object Type
-        int    NReferences;    //!< Number of references
+        int    ReferenceCount; //!< Number of references
        void    *OpaqueData;    //!< Pointer to the end of the \a Attributes array
        tSpiderValue    *Attributes[];  //!< Attribute Array
 };
@@ -215,13 +236,13 @@ struct sSpiderFunction
  */
 extern tSpiderScript   *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filename);
 /**
- * \brief Execute a method from a script
+ * \brief Execute a function from a script
  * \param Script       Script to run
  * \param Function     Name of function to run ("" for the 'main')
  * \return Return value
  */
-extern tSpiderValue    *SpiderScript_ExecuteMethod(tSpiderScript *Script,
-       const char *Function,
+extern tSpiderValue    *SpiderScript_ExecuteFunction(tSpiderScript *Script,
+       tSpiderNamespace *Namespace, const char *Function,
        int NArguments, tSpiderValue **Arguments
        );
 
@@ -231,6 +252,8 @@ extern tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script,
  */
 extern void    SpiderScript_Free(tSpiderScript *Script);
 
+extern tSpiderObject   *SpiderScript_AllocateObject(tSpiderObjectDef *Class, int ExtraBytes);
+
 /**
  * \name tSpiderValue Manipulation functions
  * \{
@@ -240,6 +263,7 @@ extern tSpiderValue *SpiderScript_CreateReal(double Value);
 extern tSpiderValue    *SpiderScript_CreateString(int Length, const char *Data);
 extern tSpiderValue    *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
 extern int     SpiderScript_IsValueTrue(tSpiderValue *Value);
+extern void    SpiderScript_FreeValue(tSpiderValue *Value);
 extern char    *SpiderScript_DumpValue(tSpiderValue *Value);
 /**
  * \}

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