From 83e18dd699042a1104ea56dfdaf71ba014048e6e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 20 Apr 2012 13:22:49 +0800 Subject: [PATCH] SpiderScript - Fixed array behaviour, removed memory leaks --- .../Libraries/libspiderscript.so_src/ast.c | 21 +--- .../Libraries/libspiderscript.so_src/ast.h | 3 +- .../libspiderscript.so_src/bytecode_gen.c | 1 + .../Libraries/libspiderscript.so_src/exec.c | 19 ++- .../libspiderscript.so_src/exec_ast.c | 69 +++++++---- .../libspiderscript.so_src/exec_bytecode.c | 79 ++++++++++++- .../libspiderscript.so_src/exports.c | 76 +++++++++++- .../Libraries/libspiderscript.so_src/parse.c | 111 +++++++++++------- .../Libraries/libspiderscript.so_src/values.c | 53 ++++++--- Usermode/include/spiderscript.h | 1 + 10 files changed, 326 insertions(+), 107 deletions(-) diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.c b/Usermode/Libraries/libspiderscript.so_src/ast.c index d37dc31e..eb839961 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast.c @@ -216,11 +216,9 @@ size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node) // Define a variable case NODETYPE_DEFVAR: - WRITE_8(Buffer, Offset, Node->DefVar.DataType); + WRITE_32(Buffer, Offset, Node->DefVar.DataType); // TODO: Duplicate compress the strings WRITE_STR(Buffer, Offset, Node->DefVar.Name); - - WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes); Offset += AST_WriteNode(Buffer, Offset, Node->DefVar.InitialValue); break; @@ -364,12 +362,6 @@ void AST_FreeNode(tAST_Node *Node) // Define a variable case NODETYPE_DEFVAR: - for( node = Node->DefVar.LevelSizes; node; ) - { - tAST_Node *savedNext = node->NextSibling; - AST_FreeNode(node); - node = savedNext; - } AST_FreeNode(Node->DefVar.InitialValue); break; @@ -465,15 +457,6 @@ void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child) Parent->Block.LastChild = Child; } break; - case NODETYPE_DEFVAR: - if(Parent->DefVar.LevelSizes == NULL) { - Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child; - } - else { - Parent->DefVar.LevelSizes_Last->NextSibling = Child; - Parent->DefVar.LevelSizes_Last = Child; - } - break; default: fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type); break; @@ -645,8 +628,6 @@ tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name) tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_DEFVAR, strlen(Name) + 1 ); ret->DefVar.DataType = Type; - ret->DefVar.LevelSizes = NULL; - ret->DefVar.LevelSizes_Last = NULL; ret->DefVar.InitialValue = NULL; strcpy(ret->DefVar.Name, Name); diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.h b/Usermode/Libraries/libspiderscript.so_src/ast.h index 4109fb70..ad90d0f3 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.h +++ b/Usermode/Libraries/libspiderscript.so_src/ast.h @@ -156,8 +156,6 @@ struct sAST_Node struct { int DataType; - tAST_Node *LevelSizes; - tAST_Node *LevelSizes_Last; tAST_Node *InitialValue; char Name[]; } DefVar; @@ -241,5 +239,6 @@ extern void Object_Reference(tSpiderValue *Object); 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); #endif diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c index e4437c3c..aad172d8 100644 --- a/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c +++ b/Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c @@ -35,6 +35,7 @@ tBC_Op *Bytecode_int_AllocateOp(int Operation, int ExtraBytes) ret->Operation = Operation; ret->bUseInteger = 0; ret->bUseString = (ExtraBytes > 0); + ret->CacheEnt = NULL; return ret; } diff --git a/Usermode/Libraries/libspiderscript.so_src/exec.c b/Usermode/Libraries/libspiderscript.so_src/exec.c index c7fed035..5822d9d5 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec.c @@ -64,7 +64,7 @@ void *SpiderScript_int_GetNamespace(tSpiderScript *Script, tSpiderNamespace *Roo // Check for this level for( ns = lastns->FirstChild; ns; ns = ns->Next ) { - printf("%p %.*s == %s\n", lastns, len, name, ns->Name); +// printf("%p %.*s == %s\n", lastns, len, name, ns->Name); if( strncmp(name, ns->Name, len) == 0 && ns->Name[len] == 0 ) break ; } @@ -141,8 +141,20 @@ tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script, { tSpiderValue *ret = ERRPTR; tSpiderFunction *fcn = NULL; + tScript_Function *sfcn; int i; + if( FunctionIdent && *FunctionIdent ) { + if( *(intptr_t*)FunctionIdent & 1 ) { + sfcn = (void*)( *(intptr_t*)FunctionIdent & ~1 ); + goto _exec_sfcn; + } + else { + fcn = *FunctionIdent; + goto _exec_fcn; + } + } + // Scan list, Last item should always be NULL, so abuse that to check non-prefixed for( i = 0; i == 0 || (DefaultNamespaces && DefaultNamespaces[i-1]); i ++ ) { @@ -180,12 +192,12 @@ tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script, // TODO: Script namespacing if( !fcn && strchr(Function, BC_NS_SEPARATOR) == NULL ) { - tScript_Function *sfcn; for( sfcn = Script->Functions; sfcn; sfcn = sfcn->Next ) { if( strcmp(sfcn->Name, Function) == 0 ) break; } + _exec_sfcn: // Execute! if(sfcn) { @@ -203,7 +215,8 @@ tSpiderValue *SpiderScript_ExecuteFunction(tSpiderScript *Script, return ret; } } - + +_exec_fcn: if(fcn) { // Execute! diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index c26d8876..21374d67 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -21,6 +21,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node); tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right); tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value); +tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Array, int Index, tSpiderValue *SaveValue); // - Variables tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value); int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value); @@ -512,27 +513,8 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) break; } - switch( op1->Type ) - { - case SS_DATATYPE_ARRAY: - 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 ]; - SpiderScript_ReferenceValue(ret); - break; - - default: - // TODO: Implement "operator []" on objects - AST_RuntimeError(Node, "Indexing non-array"); - ret = ERRPTR; - break; - } - + ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, NULL); + SpiderScript_DereferenceValue(op1); SpiderScript_DereferenceValue(op2); break; @@ -950,6 +932,51 @@ tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int return ret; } +tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, + tSpiderValue *Array, int Index, tSpiderValue *SaveValue) +{ + // Quick sanity check + if( !Array ) + { + AST_RuntimeError(Node, "Indexing NULL, not a good idea"); + return ERRPTR; + } + + // Array? + if( SS_GETARRAYDEPTH(Array->Type) ) + { + if( Index < 0 || Index >= Array->Array.Length ) { + AST_RuntimeError(Node, "Array index out of bounds %i not in (0, %i]", + Index, Array->Array.Length); + return ERRPTR; + } + + if( SaveValue ) + { + if( SaveValue->Type != SS_DOWNARRAY(Array->Type) ) { + // TODO: Implicit casting + AST_RuntimeError(Node, "Type mismatch assiging to array element"); + return ERRPTR; + } + SpiderScript_DereferenceValue( Array->Array.Items[Index] ); + Array->Array.Items[Index] = SaveValue; + SpiderScript_ReferenceValue( Array->Array.Items[Index] ); + return NULL; + } + else + { + SpiderScript_ReferenceValue( Array->Array.Items[Index] ); + return Array->Array.Items[Index]; + } + } + else + { + AST_RuntimeError(Node, "TODO - Implement indexing on non-arrays (type = %x)", + Array->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 82444b8d..9382c161 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c @@ -105,6 +105,7 @@ tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp) tmp = malloc(sizeof(tSpiderValue)); tmp->ReferenceCount = 1; } else { + // Stops a stack value from having free() called on it tmp->ReferenceCount = 2; } break; @@ -222,7 +223,10 @@ void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent) printf("Obj %p", Ent->Object); break; default: - printf("*%p", Ent->Reference); + if( Ent->Reference ) + printf("*%p (%i refs)", Ent->Reference, Ent->Reference->ReferenceCount); + else + printf("NULL"); break; } } @@ -278,6 +282,8 @@ tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function * if(ret == &tmpsval) { ret = malloc(sizeof(tSpiderValue)); memcpy(ret, &tmpsval, sizeof(tSpiderValue)); + // Set to 2 in _GetSpiderValue, so stack doesn't have free() called + ret->ReferenceCount = 1; } return ret; @@ -370,8 +376,18 @@ int Bytecode_int_CallExternFunction(tSpiderScript *Script, tBC_Stack *Stack, tSp PUT_STACKVAL(val1); // Deref return SpiderScript_DereferenceValue(rv); - - return ret; + + #if 0 + if(!rv) { + printf("%s returned NULL\n", name); + } + if( rv && rv != ERRPTR && rv->ReferenceCount != 1 ) { + printf("Return value from %s reference count fail (%i)\n", + name, rv->ReferenceCount); + } + #endif + + return 0; } int Bytecode_int_LocalBinOp_Integer(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2) @@ -552,13 +568,57 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t AST_RuntimeError(NULL, "Loading from invalid slot %i", slot); return -1; } + // Remove whatever was in there before DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] "); Bytecode_int_DerefStackValue( &local_vars[slot] ); + // Place new in GET_STACKVAL(local_vars[slot]); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("\n"); } break; + case BC_OP_INDEX: + case BC_OP_SETINDEX: + STATE_HDR(); + GET_STACKVAL(val1); // Index + // TODO: Check that index is an integer + if( val1.Type != SS_DATATYPE_INTEGER ) { + nextop = NULL; + break; + } + + // Get array as raw spider value + GET_STACKVAL(val2); // Array + pval1 = Bytecode_int_GetSpiderValue(&val2, &tmpVal1); + Bytecode_int_DerefStackValue(&val2); + + if( op->Operation == BC_OP_SETINDEX ) { + GET_STACKVAL(val2); + pval2 = Bytecode_int_GetSpiderValue(&val2, NULL); + Bytecode_int_DerefStackValue(&val2); + + 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); + if(ret_val == ERRPTR) { nextop = NULL; break; } + + Bytecode_int_SetSpiderValue(&val1, ret_val); + SpiderScript_DereferenceValue(ret_val); + PUT_STACKVAL(val1); + } + // Dereference the stack + if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); + break; + case BC_OP_ELEMENT: + case BC_OP_SETELEMENT: + STATE_HDR(); + AST_RuntimeError(NULL, "TODO: Impliment ELEMENT/SETELEMENT"); + nextop = NULL; + break; + // Constants: case BC_OP_LOADINT: STATE_HDR(); @@ -607,9 +667,15 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t else { pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1); pval2 = SpiderScript_CastValueTo(val2.Type, pval1); - if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); + Bytecode_int_SetSpiderValue(&val2, pval2); SpiderScript_DereferenceValue(pval2); + + if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1); + Bytecode_int_DerefStackValue(&val1); +// printf("CAST (%x->%x) - Original %i references remaining\n", +// pval1->Type, OP_INDX(op), +// pval1->ReferenceCount); } PUT_STACKVAL(val2); break; @@ -843,8 +909,13 @@ int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, t { if( local_vars[i].Type != ET_NULL ) { + DEBUG_F("Var %i - ", i); + PRINT_STACKVAL(local_vars[i]); Bytecode_int_DerefStackValue(&local_vars[i]); + DEBUG_F("\n"); } + else + DEBUG_F("Var %i - empty\n", i); } // - Restore stack diff --git a/Usermode/Libraries/libspiderscript.so_src/exports.c b/Usermode/Libraries/libspiderscript.so_src/exports.c index b114c9ce..edf64391 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exports.c +++ b/Usermode/Libraries/libspiderscript.so_src/exports.c @@ -2,6 +2,7 @@ * Acess2 - SpiderScript * - Script Exports (Lang. Namespace) */ +#define _GNU_SOURCE // HACK! #include #include #include @@ -9,6 +10,7 @@ // === PROTOTYPES === tSpiderValue *Exports_sizeof(tSpiderScript *Script, int NArgs, tSpiderValue **Args); +tSpiderValue *Exports_array(tSpiderScript *Script, int NArgs, tSpiderValue **Args); tSpiderValue *Exports_Lang_Strings_Split(tSpiderScript *Script, int NArgs, tSpiderValue **Args); tSpiderValue *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderValue **Args); @@ -41,13 +43,21 @@ tSpiderNamespace gExportNamespaceRoot = { }; // -- Global Functions +tSpiderFunction gExports_array = { + .Next = NULL, + .Name = "array", + .Handler = Exports_array, + .ReturnType = SS_DATATYPE_DYNAMIC, + .ArgTypes = {SS_DATATYPE_INTEGER, -1} +}; tSpiderFunction gExports_sizeof = { + .Next = &gExports_array, .Name = "sizeof", .Handler = Exports_sizeof, .ReturnType = SS_DATATYPE_INTEGER, .ArgTypes = {SS_DATATYPE_UNDEF, -1} }; -tSpiderFunction *gpExports_First; +tSpiderFunction *gpExports_First = &gExports_sizeof; // === CODE === tSpiderValue *Exports_sizeof(tSpiderScript *Script, int NArgs, tSpiderValue **Args) @@ -65,9 +75,71 @@ tSpiderValue *Exports_sizeof(tSpiderScript *Script, int NArgs, tSpiderValue **Ar } } +tSpiderValue *Exports_array(tSpiderScript *Script, int NArgs, tSpiderValue **Args) +{ + if(NArgs != 2) return ERRPTR; + if(!Args[0] || !Args[1]) return ERRPTR; + + if(Args[0]->Type != SS_DATATYPE_INTEGER || Args[1]->Type != SS_DATATYPE_INTEGER) + return ERRPTR; + + int type = Args[1]->Integer; + int size = Args[0]->Integer; + + if( type != SS_DATATYPE_ARRAY ) + { + if( !SS_GETARRAYDEPTH(type) ) { + // ERROR - This should never happen + return ERRPTR; + } + type = SS_DOWNARRAY(type); + } + + return SpiderScript_CreateArray(type, size); +} + tSpiderValue *Exports_Lang_Strings_Split(tSpiderScript *Script, int NArgs, tSpiderValue **Args) { - return NULL; + int len, ofs, slen; + void *haystack, *end; + int nSubStrs = 0; + tSpiderValue **strings = NULL; + tSpiderValue *ret; + + // Error checking + if( NArgs != 2 ) + return ERRPTR; + if( !Args[0] || !Args[1] ) + return ERRPTR; + if( Args[0]->Type != SS_DATATYPE_STRING ) + return ERRPTR; + if( Args[1]->Type != SS_DATATYPE_STRING ) + return ERRPTR; + + // Split the string + len = Args[0]->String.Length; + haystack = Args[0]->String.Data; + ofs = 0; + do { + end = memmem(haystack + ofs, len - ofs, Args[1]->String.Data, Args[1]->String.Length); + if( end ) + slen = end - (haystack + ofs); + else + slen = len - ofs; + + strings = realloc(strings, (nSubStrs+1)*sizeof(tSpiderValue*)); + strings[nSubStrs] = SpiderScript_CreateString(slen, haystack + ofs); + nSubStrs ++; + + ofs += slen + Args[1]->String.Length; + } while(end); + + // Create output array + ret = SpiderScript_CreateArray(SS_DATATYPE_STRING, nSubStrs); + memcpy(ret->Array.Items, strings, nSubStrs*sizeof(tSpiderValue*)); + free(strings); + + return ret; } tSpiderValue *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderValue **Args) diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 321c15fd..45eafb2b 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -18,8 +18,9 @@ // === PROTOTYPES === int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename); void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type); -tAST_Node *Parse_DoCodeBlock(tParser *Parser); -tAST_Node *Parse_DoBlockLine(tParser *Parser); +tAST_Node *Parse_DoCodeBlock(tParser *Parser, tAST_Node *CodeNode); +tAST_Node *Parse_DoBlockLine(tParser *Parser, tAST_Node *CodeNode); +tAST_Node *Parse_VarDefList(tParser *Parser, tAST_Node *CodeNode, int Type); tAST_Node *Parse_GetVarDef(tParser *Parser, int Type); tAST_Node *Parse_DoExpr0(tParser *Parser); // Assignment @@ -43,14 +44,17 @@ tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate); void SyntaxAssert(tParser *Parser, int Have, int Want); void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...); -#define SyntaxAssert(_parser, _have, _want) do { \ +#if 0 +#define SyntaxAssert(_parser, _have, _want) SyntaxAssertV(_parser, _have, _want, NULL) +#define SyntaxAssertV(_parser, _have, _want, _rv) do { \ int have = (_have), want = (_want); \ if( (have) != (want) ) { \ SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n", \ csaTOKEN_NAMES[have], have, csaTOKEN_NAMES[want], want); \ - return NULL; \ + return _rv; \ } \ }while(0) +#endif #define TODO(Parser, message...) do {\ fprintf(stderr, "TODO: "message);\ @@ -119,26 +123,18 @@ int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename case TOKEN_GROUP_TYPES: TOKEN_GET_DATATYPE(type, Parser->Token); - switch(GetToken(Parser)) + switch(LookAhead(Parser)) { // Define a function (pass on to the other function definition code) case TOK_IDENT: - PutBack(Parser); if( Parse_FunctionDefinition(Script, Parser, type) == NULL ) longjmp(Parser->JmpTarget, -1); break ; - // Define a variable + // Define a variable (pass back to _DoBlockLine) case TOK_VARIABLE: - node = Parse_GetVarDef(Parser, type); - if(!node) longjmp(Parser->JmpTarget, -1); - - AST_AppendNode( mainCode, node ); - // Can't use SyntaxAssert because that returns - if(GetToken(Parser) != TOK_SEMICOLON) { - SyntaxError(Parser, 1, "Unexpected %s, expected TOK_SEMICOLON", - csaTOKEN_NAMES[Parser->Token]); - longjmp(Parser->JmpTarget, -1); - } + node = Parse_VarDefList(Parser, mainCode, type); + AST_AppendNode(mainCode, node); + SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON); break; default: SyntaxError(Parser, 1, "Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n", @@ -164,7 +160,7 @@ int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename // Ordinary Statement default: PutBack(Parser); - node = Parse_DoBlockLine(Parser); + node = Parse_DoBlockLine(Parser, mainCode); if(!node) longjmp(Parser->JmpTarget, -1); AST_AppendNode( mainCode, node ); break; @@ -218,7 +214,7 @@ void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type) GetToken(Parser); SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE ); - code = Parse_DoCodeBlock(Parser); + code = Parse_DoCodeBlock(Parser, NULL); rv = AST_AppendFunction( Script, name, Type, first_arg, code ); @@ -240,21 +236,21 @@ void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type) /** * \brief Parse a block of code surrounded by { } */ -tAST_Node *Parse_DoCodeBlock(tParser *Parser) +tAST_Node *Parse_DoCodeBlock(tParser *Parser, tAST_Node *CodeNode) { tAST_Node *ret; // Check if we are being called for a one-liner if( GetToken(Parser) != TOK_BRACE_OPEN ) { PutBack(Parser); - return Parse_DoBlockLine(Parser); + return Parse_DoBlockLine(Parser, CodeNode); } ret = AST_NewCodeBlock(Parser); while( LookAhead(Parser) != TOK_BRACE_CLOSE ) { - tAST_Node *node = Parse_DoBlockLine(Parser); + tAST_Node *node = Parse_DoBlockLine(Parser, ret); if(!node) { AST_FreeNode(ret); return NULL; @@ -268,7 +264,7 @@ tAST_Node *Parse_DoCodeBlock(tParser *Parser) /** * \brief Parse a line in a block */ -tAST_Node *Parse_DoBlockLine(tParser *Parser) +tAST_Node *Parse_DoBlockLine(tParser *Parser, tAST_Node *CodeNode) { tAST_Node *ret; @@ -278,7 +274,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) { // New block case TOK_BRACE_OPEN: - return Parse_DoCodeBlock(Parser); + return Parse_DoCodeBlock(Parser, CodeNode); // Empty statement case TOK_SEMICOLON: @@ -327,10 +323,10 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN); cond = Parse_DoExpr0(Parser); // Get condition SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE); - true = Parse_DoCodeBlock(Parser); + true = Parse_DoCodeBlock(Parser, CodeNode); if( LookAhead(Parser) == TOK_RWD_ELSE ) { GetToken(Parser); - false = Parse_DoCodeBlock(Parser); + false = Parse_DoCodeBlock(Parser, CodeNode); } else false = AST_NewNop(Parser); @@ -371,7 +367,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE); - code = Parse_DoCodeBlock(Parser); + code = Parse_DoCodeBlock(Parser, CodeNode); ret = AST_NewLoop(Parser, tag, init, 0, cond, inc, code); if(tag) free(tag); } @@ -393,7 +389,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) } #endif - code = Parse_DoCodeBlock(Parser); + code = Parse_DoCodeBlock(Parser, CodeNode); SyntaxAssert( Parser, GetToken(Parser), TOK_RWD_WHILE ); SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN ); cond = Parse_DoExpr0(Parser); @@ -420,7 +416,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN ); cond = Parse_DoExpr0(Parser); SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE ); - code = Parse_DoCodeBlock(Parser); + code = Parse_DoCodeBlock(Parser, CodeNode); ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code); } return ret; @@ -431,10 +427,7 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) int type; GetToken(Parser); TOKEN_GET_DATATYPE(type, Parser->Token); - - SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE); - - ret = Parse_GetVarDef(Parser, type); + ret = Parse_VarDefList(Parser, CodeNode, type); } break; @@ -449,6 +442,23 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) return ret; } +tAST_Node *Parse_VarDefList(tParser *Parser, tAST_Node *CodeNode, int Type) +{ + tAST_Node *ret; + + ret = NULL; + do { + if(ret) AST_AppendNode( CodeNode, ret ); + SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE); + + ret = Parse_GetVarDef(Parser, Type); + if(!ret) longjmp(Parser->JmpTarget, -1); + } while(GetToken(Parser) == TOK_COMMA); + PutBack(Parser); // Semicolon is checked by caller + + return ret; +} + /** * \brief Get a variable definition */ @@ -468,16 +478,21 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) ret = AST_NewDefineVar(Parser, Type, name); // Handle arrays level = 0; - while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + if( LookAhead(Parser) == TOK_SQUARE_OPEN ) { - tAST_Node *node; GetToken(Parser); - node = Parse_DoExpr0(Parser); - if(!node) { - AST_FreeNode(ret); - return NULL; + if( LookAhead(Parser) != TOK_SQUARE_CLOSE ) + { + ret->DefVar.InitialValue = AST_NewFunctionCall(Parser, "array"); + AST_AppendFunctionCallArg(ret->DefVar.InitialValue, Parse_DoExpr0(Parser)); } - AST_AppendNode(ret, node); + SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE); + + level ++; + } + while( LookAhead(Parser) == TOK_SQUARE_OPEN ) + { + GetToken(Parser); SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE); level ++; } @@ -493,6 +508,10 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) // Initial value if( LookAhead(Parser) == TOK_ASSIGN ) { + if( ret->DefVar.InitialValue ) + { + SyntaxError(Parser, 1, "Cannot assign and set array size at the same time"); + } GetToken(Parser); ret->DefVar.InitialValue = Parse_DoExpr0(Parser); if(!ret->DefVar.InitialValue) { @@ -500,6 +519,10 @@ tAST_Node *Parse_GetVarDef(tParser *Parser, int Type) return NULL; } } + else if( ret->DefVar.InitialValue ) + { + AST_AppendFunctionCallArg(ret->DefVar.InitialValue, AST_NewInteger(Parser, ret->DefVar.DataType)); + } return ret; } @@ -1097,3 +1120,11 @@ void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...) } } +void SyntaxAssert(tParser *Parser, int Have, int Want) +{ + if( Have != Want ) + { + SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n", + csaTOKEN_NAMES[Have], Have, csaTOKEN_NAMES[Want], Want); + } +} diff --git a/Usermode/Libraries/libspiderscript.so_src/values.c b/Usermode/Libraries/libspiderscript.so_src/values.c index 15afe1a3..019ff5f0 100644 --- a/Usermode/Libraries/libspiderscript.so_src/values.c +++ b/Usermode/Libraries/libspiderscript.so_src/values.c @@ -38,25 +38,38 @@ void SpiderScript_DereferenceValue(tSpiderValue *Object) { if(!Object || Object == ERRPTR) return ; Object->ReferenceCount --; -// if(Object->Type == SS_DATATYPE_OBJECT) { -// } if( Object->ReferenceCount == 0 ) { - switch( (enum eSpiderScript_DataTypes) Object->Type ) + int i; + + if( Object->Type == SS_DATATYPE_ARRAY || SS_GETARRAYDEPTH(Object->Type) ) { - case SS_DATATYPE_OBJECT: - Object->Object->ReferenceCount --; - if(Object->Object->ReferenceCount == 0) { - Object->Object->Type->Destructor( Object->Object ); + for( i = 0; i < Object->Array.Length; i ++ ) + { + if( Object->Array.Items[i] ) { + SpiderScript_DereferenceValue(Object->Array.Items[i]); + } + Object->Array.Items[i] = NULL; + } + } + else + { + switch( (enum eSpiderScript_DataTypes) Object->Type ) + { + case SS_DATATYPE_OBJECT: + Object->Object->ReferenceCount --; + if(Object->Object->ReferenceCount == 0) { + Object->Object->Type->Destructor( Object->Object ); + } + Object->Object = NULL; + break; + + case SS_DATATYPE_OPAQUE: + Object->Opaque.Destroy( Object->Opaque.Data ); + break; + default: + break; } - Object->Object = NULL; - break; - - case SS_DATATYPE_OPAQUE: - Object->Opaque.Destroy( Object->Opaque.Data ); - break; - default: - break; } free(Object); } @@ -128,6 +141,16 @@ tSpiderValue *SpiderScript_CreateString(int Length, const char *Data) return ret; } +tSpiderValue *SpiderScript_CreateArray(int InnerType, int ItemCount) +{ + tSpiderValue *ret = malloc( sizeof(tSpiderValue) + ItemCount*sizeof(tSpiderValue*) ); + ret->Type = SS_MAKEARRAY(InnerType); + ret->ReferenceCount = 1; + ret->Array.Length = ItemCount; + memset(ret->Array.Items, 0, ItemCount*sizeof(tSpiderValue*)); + return ret; +} + /** * \brief Concatenate two strings */ diff --git a/Usermode/include/spiderscript.h b/Usermode/include/spiderscript.h index e0497305..b1c12ee6 100644 --- a/Usermode/include/spiderscript.h +++ b/Usermode/include/spiderscript.h @@ -318,6 +318,7 @@ extern void SpiderScript_ReferenceValue(tSpiderValue *Object); extern tSpiderValue *SpiderScript_CreateInteger(uint64_t Value); extern tSpiderValue *SpiderScript_CreateReal(double Value); extern tSpiderValue *SpiderScript_CreateString(int Length, const char *Data); +extern tSpiderValue *SpiderScript_CreateArray(int InnerType, int ItemCount); extern tSpiderValue *SpiderScript_StringConcat(const tSpiderValue *Str1, const tSpiderValue *Str2); extern tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source); extern int SpiderScript_IsValueTrue(tSpiderValue *Value); -- 2.20.1