From: John Hodge Date: Sat, 2 Apr 2011 06:17:34 +0000 (+0800) Subject: SpiderScript - Implementing objects and classes, fixing bugs X-Git-Tag: rel0.10~135 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=5e007006d5b007c29268e4c949a8c9d472233257;p=tpg%2Facess2.git SpiderScript - Implementing objects and classes, fixing bugs --- diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.c b/Usermode/Libraries/libspiderscript.so_src/ast.c index 1453a926..36568e69 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast.c @@ -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; +} + /** * \} */ diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.h b/Usermode/Libraries/libspiderscript.so_src/ast.h index 1118130e..c6593acf 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.h +++ b/Usermode/Libraries/libspiderscript.so_src/ast.h @@ -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); diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index b6b569fc..e0de9ff0 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -6,6 +6,9 @@ #include #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; diff --git a/Usermode/Libraries/libspiderscript.so_src/main.c b/Usermode/Libraries/libspiderscript.so_src/main.c index 6ebd2779..20554f55 100644 --- a/Usermode/Libraries/libspiderscript.so_src/main.c +++ b/Usermode/Libraries/libspiderscript.so_src/main.c @@ -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 */ diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 6e1696e9..907c7291 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -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); diff --git a/Usermode/include/spiderscript.h b/Usermode/include/spiderscript.h index dc62a23d..e6fdaab2 100644 --- a/Usermode/include/spiderscript.h +++ b/Usermode/include/spiderscript.h @@ -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); /** * \}