From 1ee0d1481a98ecfea0434e0642571fbf737ab194 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 20 Apr 2012 21:58:45 +0800 Subject: [PATCH] SpiderScript - Implementing object element/attribute support --- .../Libraries/libspiderscript.so_src/ast.h | 1 + .../libspiderscript.so_src/ast_to_bytecode.c | 3 + .../libspiderscript.so_src/exec_ast.c | 78 +++++++++++++------ .../libspiderscript.so_src/exec_bytecode.c | 52 ++++++++++++- .../Libraries/libspiderscript.so_src/main.c | 4 +- Usermode/include/spiderscript.h | 20 ++++- 6 files changed, 123 insertions(+), 35 deletions(-) diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.h b/Usermode/Libraries/libspiderscript.so_src/ast.h index ad90d0f3..a6620fc2 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.h +++ b/Usermode/Libraries/libspiderscript.so_src/ast.h @@ -240,5 +240,6 @@ extern tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node); extern tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right); extern tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value); extern tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Array, int Index, tSpiderValue *SaveValue); +extern tSpiderValue *AST_ExecuteNode_Element(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Object, const char *Element, tSpiderValue *SaveValue); #endif diff --git a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c index 286869c8..c45e7a51 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast_to_bytecode.c @@ -509,10 +509,13 @@ int AST_ConvertNode(tAST_BlockInfo *Block, tAST_Node *Node, int bKeepValue) ret = AST_ConvertNode( Block, Node->Scope.Element, 1 ); if(ret) return ret; + // TODO: Support elements for non-objects ret = _StackPop(Block, Node, SS_DATATYPE_OBJECT); if(ret < 0) return -1; Bytecode_AppendElement(Block->Handle, Node->Scope.Name); + + // TODO: Somehow know this at compile time? ret = _StackPush(Block, Node, SS_DATATYPE_UNDEF); if(ret < 0) return -1; CHECK_IF_NEEDED(1); diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index 21374d67..a9970ee0 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -447,28 +447,8 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) case NODETYPE_ELEMENT: tmpobj = AST_ExecuteNode( Block, Node->Scope.Element ); if(tmpobj == ERRPTR) return ERRPTR; - if( !tmpobj || 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]; - SpiderScript_ReferenceValue(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; - } + + ret = AST_ExecuteNode_Element(Block->Script, Node, tmpobj, Node->Scope.Name, ERRPTR); break; // Cast a value to another @@ -513,7 +493,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) break; } - ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, NULL); + ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, ERRPTR); SpiderScript_DereferenceValue(op1); SpiderScript_DereferenceValue(op2); @@ -951,9 +931,9 @@ tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, return ERRPTR; } - if( SaveValue ) + if( SaveValue != ERRPTR ) { - if( SaveValue->Type != SS_DOWNARRAY(Array->Type) ) { + if( SaveValue && SaveValue->Type != SS_DOWNARRAY(Array->Type) ) { // TODO: Implicit casting AST_RuntimeError(Node, "Type mismatch assiging to array element"); return ERRPTR; @@ -977,6 +957,54 @@ tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, } } +/** + * \brief Get/Set the value of an element/attribute of a class + * \param Script Executing script + * \param Node Current execution node (only used for AST_RuntimeError) + * \param Object Object value + * \param ElementName Name of the attribute to be accessed + * \param SaveValue Value to set the element to (if ERRPTR, element value is returned) + */ +tSpiderValue *AST_ExecuteNode_Element(tSpiderScript *Script, tAST_Node *Node, + tSpiderValue *Object, const char *ElementName, tSpiderValue *SaveValue) +{ + int i; + tSpiderValue *ret; + + if( !Object ) { + AST_RuntimeError(Node, "Tried to access an element of NULL"); + return ERRPTR; + } + + switch( Object->Type ) + { + case SS_DATATYPE_OBJECT: { + tSpiderObjectDef *class = Object->Object->Type; + for( i = 0; i < class->NAttributes; i ++ ) + { + if( strcmp(ElementName, class->AttributeDefs[i].Name) == 0 ) + { + if( SaveValue != ERRPTR ) { + Object->Object->Attributes[i] = SaveValue; + SpiderScript_ReferenceValue(SaveValue); + return NULL; + } + else { + ret = Object->Object->Attributes[i]; + SpiderScript_ReferenceValue(ret); + return ret; + } + } + } + AST_RuntimeError(Node, "Unknown attribute '%s' of class '%s'", + ElementName, class->Name); + return ERRPTR; } + default: + AST_RuntimeError(Node, "Unable to get element of type %i", Object->Type); + return ERRPTR; + } +} + #if USE_AST_EXEC /** * \brief Define a variable diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c index 9382c161..9de7281e 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c @@ -577,6 +577,7 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t DEBUG_F("\n"); } break; + // Array index (get or set) case BC_OP_INDEX: case BC_OP_SETINDEX: STATE_HDR(); @@ -597,26 +598,69 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t pval2 = Bytecode_int_GetSpiderValue(&val2, NULL); Bytecode_int_DerefStackValue(&val2); + DEBUG_F("SETINDEX %i ", val1.Integer); PRINT_STACKVAL(val2); DEBUG_F("\n"); + ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, pval2); if(ret_val == ERRPTR) { nextop = NULL; break; } SpiderScript_DereferenceValue(pval2); } else { - ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, NULL); + DEBUG_F("INDEX %i ", val1.Integer); + ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, ERRPTR); if(ret_val == ERRPTR) { nextop = NULL; break; } Bytecode_int_SetSpiderValue(&val1, ret_val); SpiderScript_DereferenceValue(ret_val); PUT_STACKVAL(val1); + + DEBUG_F("[Got "); PRINT_STACKVAL(val1); DEBUG_F("]\n"); + } - // Dereference the stack + // Dereference the array (or object, ...) if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); break; + + // Object element (get or set) case BC_OP_ELEMENT: case BC_OP_SETELEMENT: STATE_HDR(); - AST_RuntimeError(NULL, "TODO: Impliment ELEMENT/SETELEMENT"); - nextop = NULL; + + GET_STACKVAL(val1); + // - Integers/Reals can't have elements :) + if( val1.Type != ET_REFERENCE ) { + nextop = NULL; + break; + } + + pval1 = Bytecode_int_GetSpiderValue(&val1, NULL); + Bytecode_int_DerefStackValue(&val1); + + if( op->Operation == BC_OP_SETELEMENT ) { + GET_STACKVAL(val2); + pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2); + Bytecode_int_DerefStackValue(&val2); + + DEBUG_F("SETELEMENT %s ", OP_STRING(op)); PRINT_STACKVAL(val2); DEBUG_F("\n"); + + ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), pval2); + if(ret_val == ERRPTR) { nextop = NULL; break; } + + if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2); + } + else { + DEBUG_F("ELEMENT %s ", OP_STRING(op)); + + ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), ERRPTR); + if(ret_val == ERRPTR) { nextop = NULL; break; } + + Bytecode_int_SetSpiderValue(&val2, ret_val); + SpiderScript_DereferenceValue(ret_val); + PUT_STACKVAL(val2); + + DEBUG_F("[Got "); PRINT_STACKVAL(val2); DEBUG_F("]\n"); + } + + SpiderScript_DereferenceValue(pval1); break; // Constants: diff --git a/Usermode/Libraries/libspiderscript.so_src/main.c b/Usermode/Libraries/libspiderscript.so_src/main.c index bd292805..17f5a3c1 100644 --- a/Usermode/Libraries/libspiderscript.so_src/main.c +++ b/Usermode/Libraries/libspiderscript.so_src/main.c @@ -100,10 +100,8 @@ int SpiderScript_SaveAST(tSpiderScript *Script, const char *Filename) size_t size; FILE *fp; void *data; - printf("Total Size: "); - fflush(stdout); + size = AST_WriteScript(NULL, Script); - printf("0x%x bytes\n", (unsigned)size); fp = fopen(Filename, "wb"); if(!fp) return 1; diff --git a/Usermode/include/spiderscript.h b/Usermode/include/spiderscript.h index b1c12ee6..3d58a8cd 100644 --- a/Usermode/include/spiderscript.h +++ b/Usermode/include/spiderscript.h @@ -199,15 +199,29 @@ struct sSpiderObjectDef * by this function. */ void (*Destructor)(tSpiderObject *This); + + + /** + * \brief Get/Set an attribute's value + */ + tSpiderValue *(*GetSetAttribute)(tSpiderObject *This, int AttibuteID, tSpiderValue *NewValue); - tSpiderFunction *Methods; //!< Method Definitions (linked list) + /** + * \brief Method Definitions (linked list) + */ + tSpiderFunction *Methods; - int NAttributes; //!< Number of attributes + /** + * \brief Number of attributes + */ + int NAttributes; //! Attribute definitions struct { const char *Name; //!< Attribute Name - int bReadOnly; //!< Allow writes to the attribute? + int Type; //!< Datatype + char bReadOnly; //!< Allow writes to the attribute? + char bMethod; //!< IO Goes via GetSetAttribute function } AttributeDefs[]; }; -- 2.20.1