From: John Hodge Date: Thu, 31 Mar 2011 14:24:01 +0000 (+0800) Subject: SpiderScript - A day of debugging and improvements X-Git-Tag: rel0.10~136 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=ec4d050568da0f3f18a20969bd118b5c67f03ee2;p=tpg%2Facess2.git SpiderScript - A day of debugging and improvements - Fixed execution bugs and memory leaks - Added support for += and friends - Added basic serialisation of the AST (no read back as yet) --- diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.c b/Usermode/Libraries/libspiderscript.so_src/ast.c index b662e320..1453a926 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast.c @@ -188,7 +188,231 @@ size_t AST_GetNodeSize(tAST_Node *Node) return ret; } -#if 0 +#if 1 + +#define WRITE_N(_buffer, _offset, _len, _dataptr) do { \ + if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\ + _offset += _len; \ +} while(0) + +#define WRITE_8(_buffer, _offset, _val) do {\ + uint8_t v = (_val);\ + WRITE_N(_buffer, _offset, 1, &v);\ +} while(0) +#define WRITE_16(_buffer, _offset, _val) do {\ + uint16_t v = (_val);\ + WRITE_N(_buffer, _offset, 2, &v);\ +} while(0) +#define WRITE_32(_buffer, _offset, _val) do {\ + uint32_t v = (_val);\ + WRITE_N(_buffer, _offset, 4, &v);\ +} while(0) +#define WRITE_64(_buffer, _offset, _val) do {\ + uint64_t v = (_val);\ + WRITE_N(_buffer, _offset, 8, &v);\ +} while(0) +#define WRITE_REAL(_buffer, _offset, _val) do {\ + double v = (_val);\ + WRITE_N(_buffer, _offset, sizeof(double), &v);\ +} while(0) + +#define WRITE_STR(_buffer, _offset, _string) do {\ + int len = strlen(_string);\ + WRITE_16(_buffer, _offset, len);\ + WRITE_N(_buffer, _offset, len, _string);\ +} while(0) +#define WRITE_NODELIST(_buffer, _offset, _listHead) do {\ + tAST_Node *node; \ + size_t ptr = -1;\ + for(node=(_listHead); node; node = node->NextSibling) {\ + ptr = _offset;\ + _offset += AST_WriteNode(_buffer, _offset, node); \ + WRITE_32(_buffer, ptr, ptr); \ + } \ + if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \ +} while(0) + +/** + * \brief Writes a script dump to a buffer + * \return Size of encoded data + * \note If \a Buffer is NULL, no write is done, but the size is still returned + */ +size_t AST_WriteScript(void *Buffer, tAST_Script *Script) +{ + tAST_Function *fcn; + size_t ret = 0, ptr; + + for( fcn = Script->Functions; fcn; fcn = fcn->Next ) + { + ptr = ret; + WRITE_32(Buffer, ret, 0); // Next + WRITE_STR(Buffer, ret, fcn->Name); + WRITE_NODELIST(Buffer, ret, fcn->Arguments); // TODO: Cheaper way + ret += AST_WriteNode(Buffer, ret, fcn->Code); + WRITE_32(Buffer, ptr, ret); // Actually set next + } + ptr -= 4; + WRITE_32(Buffer, ptr, 0); // Clear next for final + + return ret; +} + +/** + * \brief Write a node to a file + */ +size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node) +{ + off_t ptr; + typeof(Offset) baseOfs = Offset; + + if(!Node) { + fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n"); + return 0; + } + + WRITE_32(Buffer, Offset, 0); // Next + WRITE_8(Buffer, Offset, Node->Type); + //WRITE_32(Buffer, Offset, 0); // File + WRITE_16(Buffer, Offset, Node->Line); // Line + + switch(Node->Type) + { + // Block of code + case NODETYPE_BLOCK: + WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild); + break; + + // Function Call + case NODETYPE_FUNCTIONCALL: + 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); + WRITE_STR(Buffer, Offset, Node->DefVar.Name); + + WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes); + 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 + 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: + 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 + case NODETYPE_NOP: + break; + case NODETYPE_VARIABLE: + case NODETYPE_CONSTANT: + WRITE_STR(Buffer, Offset, Node->Variable.Name); + break; + case NODETYPE_STRING: + WRITE_32(Buffer, Offset, Node->String.Length); + WRITE_N(Buffer, Offset, Node->String.Length, Node->String.Data); + break; + case NODETYPE_INTEGER: + WRITE_64(Buffer, Offset, Node->Integer); + break; + case NODETYPE_REAL: + WRITE_REAL(Buffer, Offset, Node->Real); + 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 */ diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.h b/Usermode/Libraries/libspiderscript.so_src/ast.h index 565c94aa..1118130e 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.h +++ b/Usermode/Libraries/libspiderscript.so_src/ast.h @@ -187,6 +187,8 @@ struct sAST_Variable // === FUNCTIONS === extern tAST_Script *AST_NewScript(void); +extern size_t AST_WriteScript(void *Buffer, tAST_Script *Script); +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); diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index 33dbea45..b6b569fc 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -2,6 +2,7 @@ */ #include #include +#include #include #include "ast.h" @@ -13,15 +14,19 @@ tSpiderValue *SpiderScript_CreateReal(double Value); tSpiderValue *SpiderScript_CreateString(int Length, const char *Data); tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source); int SpiderScript_IsValueTrue(tSpiderValue *Value); +void SpiderScript_FreeValue(tSpiderValue *Value); char *SpiderScript_DumpValue(tSpiderValue *Value); tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node); +tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right); tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name); int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value); tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name); void Variable_Destroy(tAST_Variable *Variable); +void AST_RuntimeError(tAST_Node *Node, const char *Format, ...); + // === CODE === /** * \brief Dereference a created object @@ -31,6 +36,7 @@ void Object_Dereference(tSpiderValue *Object) if(!Object) return ; if(Object == ERRPTR) return ; Object->ReferenceCount --; +// printf("%p Dereferenced (%i)\n", Object, Object->ReferenceCount); if( Object->ReferenceCount == 0 ) { switch( (enum eSpiderScript_DataTypes) Object->Type ) { @@ -51,6 +57,7 @@ void Object_Reference(tSpiderValue *Object) { if(!Object) return ; Object->ReferenceCount ++; +// printf("%p Referenced (%i)\n", Object, Object->ReferenceCount); } /** @@ -139,7 +146,7 @@ tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source) case SS_DATATYPE_UNDEF: case SS_DATATYPE_ARRAY: case SS_DATATYPE_OPAQUE: - fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast to %i\n", Type); + AST_RuntimeError(NULL, "Invalid cast to %i", Type); return ERRPTR; case SS_DATATYPE_INTEGER: @@ -152,7 +159,7 @@ tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source) case SS_DATATYPE_STRING: ret->Integer = atoi(Source->String.Data); break; case SS_DATATYPE_REAL: ret->Integer = Source->Real; break; default: - fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type); + AST_RuntimeError(NULL, "Invalid cast from %i to Integer", Source->Type); free(ret); ret = ERRPTR; break; @@ -175,7 +182,7 @@ tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source) case SS_DATATYPE_INTEGER: sprintf(ret->String.Data, "%li", Source->Integer); break; case SS_DATATYPE_REAL: sprintf(ret->String.Data, "%f", Source->Real); break; default: - fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type); + AST_RuntimeError(NULL, "Invalid cast from %i to String", Source->Type); free(ret); ret = ERRPTR; break; @@ -183,7 +190,7 @@ tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source) break; default: - fprintf(stderr, "BUG REPORT: Unimplemented cast target\n"); + AST_RuntimeError(NULL, "BUG - BUG REPORT: Unimplemented cast target"); break; } @@ -221,12 +228,21 @@ int SpiderScript_IsValueTrue(tSpiderValue *Value) case SS_DATATYPE_ARRAY: return Value->Array.Length > 0; default: - fprintf(stderr, "Spiderscript internal error: Unknown type %i in SpiderScript_IsValueTrue\n", Value->Type); + AST_RuntimeError(NULL, "Unknown type %i in SpiderScript_IsValueTrue", Value->Type); return 0; } return 0; } +/** + * \brief Free a value + * \note Just calls Object_Dereference + */ +void SpiderScript_FreeValue(tSpiderValue *Value) +{ + Object_Dereference(Value); +} + /** * \brief Dump a value into a string * \return Heap string @@ -275,7 +291,7 @@ char *SpiderScript_DumpValue(tSpiderValue *Value) return strdup("Array"); default: - fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_Dump\n", Value->Type); + AST_RuntimeError(NULL, "Unknown type %i in Object_Dump", Value->Type); return NULL; } @@ -313,6 +329,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) break ; } if(tmpobj) Object_Dereference(tmpobj); // Free unused value + tmpobj = NULL; } // Clean up variables while(blockInfo.FirstVar) @@ -331,17 +348,28 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) // Assignment case NODETYPE_ASSIGN: if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) { - fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n"); + AST_RuntimeError(Node, "LVALUE of assignment is not a variable"); return ERRPTR; } ret = AST_ExecuteNode(Block, Node->Assign.Value); - if(ret != ERRPTR) + if(ret == ERRPTR) + return ERRPTR; + + if( Node->Assign.Operation != NODETYPE_NOP ) { - if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) { - Object_Dereference( ret ); - fprintf(stderr, "on line %i\n", Node->Line); + tSpiderValue *varVal = Variable_GetValue(Block, Node->Assign.Dest->Variable.Name); + tSpiderValue *value; + value = AST_ExecuteNode_BinOp(Block, Node->Assign.Operation, varVal, ret); + if( value == ERRPTR ) return ERRPTR; - } + if(ret) Object_Dereference(ret); + Object_Dereference(varVal); + ret = value; + } + + if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) { + Object_Dereference( ret ); + return ERRPTR; } break; @@ -382,42 +410,52 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) case NODETYPE_IF: ret = AST_ExecuteNode(Block, Node->If.Condition); if( SpiderScript_IsValueTrue(ret) ) { - AST_ExecuteNode(Block, Node->If.True); + Object_Dereference(AST_ExecuteNode(Block, Node->If.True)); } else { - AST_ExecuteNode(Block, Node->If.False); + Object_Dereference(AST_ExecuteNode(Block, Node->If.False)); } Object_Dereference(ret); + ret = NULL; break; // Loop case NODETYPE_LOOP: ret = AST_ExecuteNode(Block, Node->For.Init); - if( Node->For.bCheckAfter ) { + if( Node->For.bCheckAfter ) + { do { Object_Dereference(ret); ret = AST_ExecuteNode(Block, Node->For.Code); Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Increment); + Object_Dereference(ret); ret = AST_ExecuteNode(Block, Node->For.Condition); } while( SpiderScript_IsValueTrue(ret) ); } - else { + else + { Object_Dereference(ret); ret = AST_ExecuteNode(Block, Node->For.Condition); while( SpiderScript_IsValueTrue(ret) ) { Object_Dereference(ret); ret = AST_ExecuteNode(Block, Node->For.Code); Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Increment); + Object_Dereference(ret); ret = AST_ExecuteNode(Block, Node->For.Condition); } - Object_Dereference(ret); } + Object_Dereference(ret); + ret = NULL; break; // Return 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; // Define a variable @@ -434,21 +472,22 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) // Cast a value to another case NODETYPE_CAST: - ret = SpiderScript_CastValueTo( - Node->Cast.DataType, - AST_ExecuteNode(Block, Node->Cast.Value) - ); + { + tSpiderValue *tmp = AST_ExecuteNode(Block, Node->Cast.Value); + ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmp ); + Object_Dereference(tmp); + } break; // Index into an array case NODETYPE_INDEX: - fprintf(stderr, "TODO: Array indexing\n"); + AST_RuntimeError(Node, "TODO - Array Indexing"); ret = ERRPTR; break; // TODO: Implement runtime constants case NODETYPE_CONSTANT: - fprintf(stderr, "TODO: Runtime Constants\n"); + AST_RuntimeError(Node, "TODO - Runtime Constants"); ret = ERRPTR; break; // Constant Values @@ -515,8 +554,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) } // If statically typed, this should never happen, but catch it anyway else { - fprintf(stderr, "PARSER ERROR: Statically typed implicit cast (line %i)\n", - Node->Line); + AST_RuntimeError(Node, "Statically typed implicit cast"); ret = ERRPTR; break; } @@ -541,8 +579,18 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) cmp = -1; } break; + + // - Integer Comparisons + case SS_DATATYPE_INTEGER: + if( op1->Integer == op2->Integer ) + cmp = 0; + else if( op1->Integer < op2->Integer ) + cmp = -1; + else + cmp = 1; + break; default: - fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type); + AST_RuntimeError(Node, "TODO - Comparison of type %i", op1->Type); ret = ERRPTR; break; } @@ -562,7 +610,7 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0); break; case NODETYPE_GREATERTHAN: ret = SpiderScript_CreateInteger(cmp > 0); break; default: - fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type); + AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Node->Type); ret = ERRPTR; break; } @@ -589,104 +637,141 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) return ERRPTR; } - // Convert types - if( op1 && op2 && op1->Type != op2->Type ) { - // If dynamically typed, convert op2 to op1's type - if(Block->Script->Variant->bDyamicTyped) + ret = AST_ExecuteNode_BinOp(Block, Node->Type, op1, op2); + + // Free intermediate objects + Object_Dereference(op1); + Object_Dereference(op2); + break; + + //default: + // ret = NULL; + // AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type); + // break; + } +_return: + return ret; +} + +tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, int Operation, tSpiderValue *Left, tSpiderValue *Right) +{ + tSpiderValue *preCastValue = Right; + tSpiderValue *ret; + + // Convert types + if( Left && Right && Left->Type != Right->Type ) + { + #if 0 + // Object types + // - Operator overload functions + if( Left->Type == SS_DATATYPE_OBJECT ) + { + const char *fcnname; + switch(Operation) { - tmpobj = op2; - op2 = SpiderScript_CastValueTo(op1->Type, op2); - Object_Dereference(tmpobj); - if(op2 == ERRPTR) { - Object_Dereference(op1); - return ERRPTR; - } + case NODETYPE_ADD: fcnname = "+"; break; + case NODETYPE_SUBTRACT: fcnname = "-"; break; + case NODETYPE_MULTIPLY: fcnname = "*"; break; + case NODETYPE_DIVIDE: fcnname = "/"; break; + case NODETYPE_MODULO: fcnname = "%"; break; + case NODETYPE_BWAND: fcnname = "&"; break; + case NODETYPE_BWOR: fcnname = "|"; break; + case NODETYPE_BWXOR: fcnname = "^"; break; + case NODETYPE_BITSHIFTLEFT: fcnname = "<<"; break; + case NODETYPE_BITSHIFTRIGHT:fcnname = ">>"; break; + case NODETYPE_BITROTATELEFT:fcnname = "<<<"; break; + default: fcnname = NULL; break; } - // If statically typed, this should never happen, but catch it anyway - else { - fprintf(stderr, - "PARSER ERROR: Statically typed implicit cast (from %i to %i)\n", - op2->Type, op1->Type - ); - ret = ERRPTR; - break; + + if( fcnname ) + { + ret = Object_ExecuteMethod(Left->Object, fcnname, Right); + if( ret != ERRPTR ) + return ret; + // Fall through and try casting (which will usually fail) } } + #endif - // NULL Check - if( op1 == NULL || op2 == NULL ) { - ret = NULL; - break; + // If implicit casts are allowed, convert Right to Left's type + if(Block->Script->Variant->bImplicitCasts) + { + Right = SpiderScript_CastValueTo(Left->Type, Right); + if(Right == ERRPTR) + return ERRPTR; } - - // Do operation - switch(op1->Type) + // If statically typed, this should never happen, but catch it anyway + else { + AST_RuntimeError(NULL, "Implicit cast not allowed (from %i to %i)\n", Right->Type, Left->Type); + return ERRPTR; + } + } + + // NULL Check + if( Left == NULL || Right == NULL ) { + if(Right && Right != preCastValue) free(Right); + return NULL; + } + + // Do operation + switch(Left->Type) + { + // String Concatenation + case SS_DATATYPE_STRING: + switch(Operation) { - // String Concatenation - case SS_DATATYPE_STRING: - switch(Node->Type) - { - case NODETYPE_ADD: // Concatenate - ret = Object_StringConcat(op1, op2); - break; - default: - fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type); - ret = ERRPTR; - break; - } + case NODETYPE_ADD: // Concatenate + ret = Object_StringConcat(Left, Right); break; - // Integer Operations - case SS_DATATYPE_INTEGER: - switch(Node->Type) - { - case NODETYPE_ADD: ret = SpiderScript_CreateInteger( op1->Integer + op2->Integer ); break; - case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( op1->Integer - op2->Integer ); break; - case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( op1->Integer * op2->Integer ); break; - case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( op1->Integer / op2->Integer ); break; - case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( op1->Integer % op2->Integer ); break; - case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( op1->Integer & op2->Integer ); break; - case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( op1->Integer | op2->Integer ); break; - case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( op1->Integer ^ op2->Integer ); break; - case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( op1->Integer << op2->Integer ); break; - case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( op1->Integer >> op2->Integer ); break; - case NODETYPE_BITROTATELEFT: - ret = SpiderScript_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) ); - break; - default: - fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type); - ret = ERRPTR; - break; - } + default: + AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation); + ret = ERRPTR; break; - - // Real Numbers - case SS_DATATYPE_REAL: - switch(Node->Type) - { - default: - fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type); - ret = ERRPTR; - break; - } + } + break; + // Integer Operations + case SS_DATATYPE_INTEGER: + switch(Operation) + { + case NODETYPE_ADD: ret = SpiderScript_CreateInteger( Left->Integer + Right->Integer ); break; + case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( Left->Integer - Right->Integer ); break; + case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( Left->Integer * Right->Integer ); break; + case NODETYPE_DIVIDE: ret = SpiderScript_CreateInteger( Left->Integer / Right->Integer ); break; + case NODETYPE_MODULO: ret = SpiderScript_CreateInteger( Left->Integer % Right->Integer ); break; + case NODETYPE_BWAND: ret = SpiderScript_CreateInteger( Left->Integer & Right->Integer ); break; + case NODETYPE_BWOR: ret = SpiderScript_CreateInteger( Left->Integer | Right->Integer ); break; + case NODETYPE_BWXOR: ret = SpiderScript_CreateInteger( Left->Integer ^ Right->Integer ); break; + case NODETYPE_BITSHIFTLEFT: ret = SpiderScript_CreateInteger( Left->Integer << Right->Integer ); break; + case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( Left->Integer >> Right->Integer ); break; + case NODETYPE_BITROTATELEFT: + ret = SpiderScript_CreateInteger( (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer)) ); break; - default: - fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type); + AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Operation); ret = ERRPTR; break; } - - // Free intermediate objects - Object_Dereference(op1); - Object_Dereference(op2); break; - //default: - // ret = NULL; - // fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type); - // break; + // Real Numbers + case SS_DATATYPE_REAL: + switch(Operation) + { + default: + AST_RuntimeError(NULL, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation); + ret = ERRPTR; + break; + } + break; + + default: + AST_RuntimeError(NULL, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type); + ret = ERRPTR; + break; } -_return: + + if(Right && Right != preCastValue) free(Right); + return ret; } @@ -704,7 +789,7 @@ tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Nam for( var = Block->FirstVar; var; prev = var, var = var->Next ) { if( strcmp(var->Name, Name) == 0 ) { - fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name); + AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name); return ERRPTR; } } @@ -736,12 +821,15 @@ int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Va { for( var = bs->FirstVar; var; var = var->Next ) { - if( strcmp(var->Name, Name) == 0 ) { + if( strcmp(var->Name, Name) == 0 ) + { if( !Block->Script->Variant->bDyamicTyped - && (Value && var->Type != Value->Type) ) { - fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name); + && (Value && var->Type != Value->Type) ) + { + AST_RuntimeError(NULL, "Type mismatch assigning to '%s'", Name); return -2; } +// printf("Assign %p to '%s'\n", Value, var->Name); Object_Reference(Value); Object_Dereference(var->Object); var->Object = Value; @@ -760,7 +848,7 @@ int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Va } else { - fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name); + AST_RuntimeError(NULL, "Variable '%s' set while undefined", Name); return -1; } } @@ -784,7 +872,8 @@ tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name) } } - fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name); + + AST_RuntimeError(NULL, "Variable '%s' used undefined", Name); return ERRPTR; } @@ -794,6 +883,23 @@ tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name) */ void Variable_Destroy(tAST_Variable *Variable) { +// printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name); Object_Dereference(Variable->Object); free(Variable); } + +void AST_RuntimeError(tAST_Node *Node, const char *Format, ...) +{ + va_list args; + + fprintf(stderr, "ERROR: "); + va_start(args, Format); + vfprintf(stderr, Format, args); + va_end(args); + fprintf(stderr, "\n"); + + if(Node) + { + fprintf(stderr, " at %s:%i\n", Node->File, Node->Line); + } +} diff --git a/Usermode/Libraries/libspiderscript.so_src/lex.c b/Usermode/Libraries/libspiderscript.so_src/lex.c index fd395e0f..bd1712b4 100644 --- a/Usermode/Libraries/libspiderscript.so_src/lex.c +++ b/Usermode/Libraries/libspiderscript.so_src/lex.c @@ -165,14 +165,36 @@ int GetToken(tParser *File) case '/': ret = TOK_DIV; break; case '*': ret = TOK_MUL; break; - case '+': ret = TOK_PLUS; break; + case '+': + if( *File->CurPos == '+' ) { + File->CurPos ++; + ret = TOK_INCREMENT; + break; + } + if( *File->CurPos == '=' ) { + File->CurPos ++; + ret = TOK_ASSIGN_PLUS; + break; + } + ret = TOK_PLUS; + break; case '-': + if( *File->CurPos == '-' ) { + File->CurPos ++; + ret = TOK_DECREMENT; + break; + } + if( *File->CurPos == '=' ) { + File->CurPos ++; + ret = TOK_ASSIGN_MINUS; + break; + } if( *File->CurPos == '>' ) { File->CurPos ++; ret = TOK_ELEMENT; + break; } - else - ret = TOK_MINUS; + ret = TOK_MINUS; break; // Strings @@ -210,6 +232,28 @@ int GetToken(tParser *File) ret = TOK_ASSIGN; break; + // Less-Than + case '<': + // Less-Than or Equal + if( *File->CurPos == '=' ) { + File->CurPos ++; + ret = TOK_LTE; + break; + } + ret = TOK_LT; + break; + + // Greater-Than + case '>': + // Greater-Than or Equal + if( *File->CurPos == '=' ) { + File->CurPos ++; + ret = TOK_GTE; + break; + } + ret = TOK_GT; + break; + // Variables // \$[0-9]+ or \$[_a-zA-Z][_a-zA-Z0-9]* case '$': diff --git a/Usermode/Libraries/libspiderscript.so_src/main.c b/Usermode/Libraries/libspiderscript.so_src/main.c index 106ce232..6ebd2779 100644 --- a/Usermode/Libraries/libspiderscript.so_src/main.c +++ b/Usermode/Libraries/libspiderscript.so_src/main.c @@ -13,6 +13,7 @@ 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); // === CODE === /** @@ -28,11 +29,15 @@ int SoMain() */ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filename) { + char cacheFilename[strlen(Filename)+6+1]; char *data; int fLen; FILE *fp; tSpiderScript *ret; + strcpy(cacheFilename, Filename); + strcat(cacheFilename, ".cache"); + fp = fopen(Filename, "r"); if( !fp ) { return NULL; @@ -64,6 +69,25 @@ tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filen free(data); + + // HACK!! + { + size_t size; + + printf("Total Size: "); fflush(stdout); + size = AST_WriteScript(NULL, ret->Script); + printf("0x%x bytes\n", (unsigned)size); + + fp = fopen(cacheFilename, "wb"); + if(!fp) return ret; + + data = malloc(size); + AST_WriteScript(data, ret->Script); + fwrite(data, size, 1, fp); + free(data); + fclose(fp); + } + return ret; } @@ -125,6 +149,13 @@ tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script, Object_Dereference(ret); ret = bs.RetVal; bFound = 1; + + while(bs.FirstVar) + { + tAST_Variable *nextVar = bs.FirstVar->Next; + Variable_Destroy( bs.FirstVar ); + bs.FirstVar = nextVar; + } } } @@ -186,7 +217,9 @@ void SpiderScript_Free(tSpiderScript *Script) tAST_Node *var, *nextVar; // Free functions - while(fcn) { + while(fcn) + { + AST_FreeNode( fcn->Code ); var = fcn->Arguments; diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 0b481980..6e1696e9 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -232,11 +232,13 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) init = Parse_DoExpr0(Parser); SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON); + if(LookAhead(Parser) != TOK_SEMICOLON) cond = Parse_DoExpr0(Parser); SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON); - if(LookAhead(Parser) != TOK_SEMICOLON) + + if(LookAhead(Parser) != TOK_PAREN_CLOSE) inc = Parse_DoExpr0(Parser); SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE); @@ -320,16 +322,22 @@ tAST_Node *Parse_DoExpr0(tParser *Parser) GetToken(Parser); // Eat Token ret = AST_NewAssign(Parser, NODETYPE_NOP, ret, Parse_DoExpr0(Parser)); break; - #if 0 - case TOK_DIV_EQU: + case TOK_ASSIGN_DIV: GetToken(Parser); // Eat Token ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser)); break; - case TOK_MULT_EQU: + case TOK_ASSIGN_MUL: GetToken(Parser); // Eat Token ret = AST_NewAssign(Parser, NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser)); break; - #endif + case TOK_ASSIGN_PLUS: + GetToken(Parser); // Eat Token + ret = AST_NewAssign(Parser, NODETYPE_ADD, ret, Parse_DoExpr0(Parser)); + break; + case TOK_ASSIGN_MINUS: + GetToken(Parser); // Eat Token + ret = AST_NewAssign(Parser, NODETYPE_SUBTRACT, ret, Parse_DoExpr0(Parser)); + break; default: #if DEBUG >= 2 printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token); diff --git a/Usermode/Libraries/libspiderscript.so_src/tokens.h b/Usermode/Libraries/libspiderscript.so_src/tokens.h index 6068295c..5a529f73 100644 --- a/Usermode/Libraries/libspiderscript.so_src/tokens.h +++ b/Usermode/Libraries/libspiderscript.so_src/tokens.h @@ -38,23 +38,28 @@ enum eTokens TOK_INVAL, TOK_EOF, + // Primitives TOK_STR, TOK_INTEGER, TOK_VARIABLE, TOK_IDENT, + // Reserved Words + // - Definitions TOK_RWD_FUNCTION, TOK_RWD_NAMESPACE, - + // - Control Flow TOK_RWD_NEW, TOK_RWD_RETURN, - + TOK_RWD_BREAK, + TOK_RWD_CONTINUE, + // - Blocks TOK_RWD_IF, TOK_RWD_ELSE, TOK_RWD_DO, TOK_RWD_WHILE, TOK_RWD_FOR, - + // - Types TOK_RWD_VOID, TOK_RWD_OBJECT, TOK_RWD_OPAQUE, @@ -62,28 +67,36 @@ enum eTokens TOK_RWD_INTEGER, TOK_RWD_REAL, + // TOK_ASSIGN, TOK_SEMICOLON, TOK_COMMA, TOK_SCOPE, TOK_ELEMENT, + // Comparisons TOK_EQUALS, TOK_LT, TOK_LTE, TOK_GT, TOK_GTE, + // Operations TOK_DIV, TOK_MUL, TOK_PLUS, TOK_MINUS, TOK_SHL, TOK_SHR, TOK_LOGICAND, TOK_LOGICOR, TOK_LOGICXOR, TOK_AND, TOK_OR, TOK_XOR, - TOK_PAREN_OPEN, - TOK_PAREN_CLOSE, - TOK_BRACE_OPEN, - TOK_BRACE_CLOSE, - TOK_SQUARE_OPEN, - TOK_SQUARE_CLOSE, + // Assignment Operations + TOK_INCREMENT, TOK_DECREMENT, + TOK_ASSIGN_DIV, TOK_ASSIGN_MUL, + TOK_ASSIGN_PLUS, TOK_ASSIGN_MINUS, + TOK_ASSIGN_SHL, TOK_ASSIGN_SHR, + TOK_ASSIGN_LOGICAND, TOK_ASSIGN_LOGICOR, TOK_ASSIGN_LOGXICOR, + TOK_ASSIGN_AND, TOK_ASSIGN_OR, TOK_ASSIGN_XOR, + + TOK_PAREN_OPEN, TOK_PAREN_CLOSE, + TOK_BRACE_OPEN, TOK_BRACE_CLOSE, + TOK_SQUARE_OPEN, TOK_SQUARE_CLOSE, TOK_LAST }; @@ -123,6 +136,8 @@ const char * const csaTOKEN_NAMES[] = { "TOK_RWD_NEW", "TOK_RWD_RETURN", + "TOK_RWD_BREAK", + "TOK_RWD_CONTINUE", "TOK_RWD_IF", "TOK_RWD_ELSE", @@ -153,12 +168,16 @@ const char * const csaTOKEN_NAMES[] = { "TOK_LOGICAND", "TOK_LOGICOR", "TOK_LOGICXOR", "TOK_AND", "TOK_OR", "TOK_XOR", - "TOK_PAREN_OPEN", - "TOK_PAREN_CLOSE", - "TOK_BRACE_OPEN", - "TOK_BRACE_CLOSE", - "TOK_SQUARE_OPEN", - "TOK_SQUARE_CLOSE", + "TOK_INCREMENT", "TOK_DECREMENT", + "TOK_ASSIGN_DIV", "TOK_ASSIGN_MUL", + "TOK_ASSIGN_PLUS", "TOK_ASSIGN_MINUS", + "TOK_ASSIGN_SHL", "TOK_ASSIGN_SHR", + "TOK_ASSIGN_LOGICAND", "TOK_ASSIGN_LOGICOR", "TOK_ASSIGN_LOGICXOR", + "TOK_ASSIGN_AND", "TOK_ASSIGN_OR", "TOK_ASSIGN_XOR", + + "TOK_PAREN_OPEN", "TOK_PAREN_CLOSE", + "TOK_BRACE_OPEN", "TOK_BRACE_CLOSE", + "TOK_SQUARE_OPEN", "TOK_SQUARE_CLOSE", "TOK_LAST" };