SpiderScript - Fixed array behaviour, removed memory leaks
authorJohn Hodge <[email protected]>
Fri, 20 Apr 2012 05:22:49 +0000 (13:22 +0800)
committerJohn Hodge <[email protected]>
Fri, 20 Apr 2012 05:22:49 +0000 (13:22 +0800)
Usermode/Libraries/libspiderscript.so_src/ast.c
Usermode/Libraries/libspiderscript.so_src/ast.h
Usermode/Libraries/libspiderscript.so_src/bytecode_gen.c
Usermode/Libraries/libspiderscript.so_src/exec.c
Usermode/Libraries/libspiderscript.so_src/exec_ast.c
Usermode/Libraries/libspiderscript.so_src/exec_bytecode.c
Usermode/Libraries/libspiderscript.so_src/exports.c
Usermode/Libraries/libspiderscript.so_src/parse.c
Usermode/Libraries/libspiderscript.so_src/values.c
Usermode/include/spiderscript.h

index d37dc31..eb83996 100644 (file)
@@ -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);
        
index 4109fb7..ad90d0f 100644 (file)
@@ -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
index e4437c3..aad172d 100644 (file)
@@ -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;
 }
index c7fed03..5822d9d 100644 (file)
@@ -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!
index c26d887..21374d6 100644 (file)
@@ -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
index 82444b8..9382c16 100644 (file)
@@ -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
index b114c9c..edf6439 100644 (file)
@@ -2,6 +2,7 @@
  * Acess2 - SpiderScript
  * - Script Exports (Lang. Namespace)
  */
+#define _GNU_SOURCE    // HACK!
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -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)
index 321c15f..45eafb2 100644 (file)
@@ -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);
+       }
+}
index 15afe1a..019ff5f 100644 (file)
@@ -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
  */
index e049730..b1c12ee 100644 (file)
@@ -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);

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