From: John Hodge Date: Thu, 26 Aug 2010 03:56:21 +0000 (+0800) Subject: Added if() statement (and internal support for for,while and do{}while()) X-Git-Tag: rel0.06~40 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;ds=sidebyside;h=ec6f426069129f0a3d207f743ecddceddb57db8e;p=tpg%2Facess2.git Added if() statement (and internal support for for,while and do{}while()) - Also improved return behavior --- diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.c b/Usermode/Libraries/libspiderscript.so_src/ast.c index 45b8176a..8df54697 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/ast.c @@ -71,6 +71,9 @@ void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root) void AST_FreeNode(tAST_Node *Node) { tAST_Node *node; + + if(!Node) return ; + switch(Node->Type) { // Block of code @@ -93,6 +96,21 @@ void AST_FreeNode(tAST_Node *Node) } break; + // If node + case NODETYPE_IF: + AST_FreeNode(Node->If.Condition); + AST_FreeNode(Node->If.True); + AST_FreeNode(Node->If.False); + break; + + // Looping Construct (For loop node) + case NODETYPE_LOOP: + AST_FreeNode(Node->For.Init); + AST_FreeNode(Node->For.Condition); + AST_FreeNode(Node->For.Increment); + AST_FreeNode(Node->For.Code); + break; + // Asignment case NODETYPE_ASSIGN: AST_FreeNode(Node->Assign.Dest); @@ -191,6 +209,30 @@ void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child) } } +tAST_Node *AST_NewIf(tAST_Node *Condition, tAST_Node *True, tAST_Node *False) +{ + tAST_Node *ret = malloc( sizeof(tAST_Node) ); + ret->NextSibling = NULL; + ret->Type = NODETYPE_IF; + ret->If.Condition = Condition; + ret->If.True = True; + ret->If.False = False; + return ret; +} + +tAST_Node *AST_NewLoop(tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code) +{ + tAST_Node *ret = malloc( sizeof(tAST_Node) ); + ret->NextSibling = NULL; + ret->Type = NODETYPE_LOOP; + ret->For.Init = Init; + ret->For.bCheckAfter = !!bPostCheck; + ret->For.Condition = Condition; + ret->For.Increment = Increment; + ret->For.Code = Code; + return ret; +} + tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value) { tAST_Node *ret = malloc( sizeof(tAST_Node) ); diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.h b/Usermode/Libraries/libspiderscript.so_src/ast.h index 4fa98ca0..05ed68bf 100644 --- a/Usermode/Libraries/libspiderscript.so_src/ast.h +++ b/Usermode/Libraries/libspiderscript.so_src/ast.h @@ -34,6 +34,9 @@ enum eAST_NodeTypes NODETYPE_ASSIGN, //!< Variable assignment operator NODETYPE_FUNCTIONCALL, //!< Call a function + NODETYPE_IF, //!< Conditional + NODETYPE_LOOP, //!< Looping Construct + NODETYPE_INDEX, //!< Index into an array NODETYPE_LOGICALAND, //!< Logical AND operator @@ -119,6 +122,20 @@ struct sAST_Node char Name[]; } FunctionCall; + struct { + tAST_Node *Condition; + tAST_Node *True; + tAST_Node *False; + } If; + + struct { + tAST_Node *Init; + int bCheckAfter; + tAST_Node *Condition; + tAST_Node *Increment; + tAST_Node *Code; + } For; + /** * \note Used for \a NODETYPE_VARIABLE and \a NODETYPE_CONSTANT */ @@ -153,6 +170,7 @@ struct sAST_BlockState tAST_BlockState *Parent; tSpiderScript *Script; //!< Script tAST_Variable *FirstVar; //!< First variable in the list + tSpiderValue *RetVal; }; struct sAST_Variable @@ -180,6 +198,9 @@ extern void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg); extern tAST_Node *AST_NewCodeBlock(void); extern void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child); + +extern tAST_Node *AST_NewIf(tAST_Node *Condition, tAST_Node *True, tAST_Node *False); + extern tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value); extern tAST_Node *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right); extern tAST_Node *AST_NewUniOp(int Operation, tAST_Node *Value); diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c index 0421686f..b9186087 100644 --- a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c +++ b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c @@ -166,6 +166,9 @@ tSpiderValue *Object_CastTo(int Type, tSpiderValue *Source) */ int Object_IsTrue(tSpiderValue *Value) { + if( Value == ERRPTR ) return 0; + if( Value == NULL ) return 0; + switch( (enum eSpiderScript_DataTypes)Value->Type ) { case SS_DATATYPE_UNDEF: @@ -216,23 +219,18 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) { tAST_BlockState blockInfo; blockInfo.FirstVar = NULL; + blockInfo.RetVal = NULL; blockInfo.Parent = Block; blockInfo.Script = Block->Script; ret = NULL; - for(node = Node->Block.FirstChild; node; node = node->NextSibling ) + for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling ) { - if(node->Type == NODETYPE_RETURN) { - ret = AST_ExecuteNode(&blockInfo, node); + tmpobj = AST_ExecuteNode(&blockInfo, node); + if(tmpobj == ERRPTR) { // Error check + ret = ERRPTR; break ; } - else { - tmpobj = AST_ExecuteNode(&blockInfo, node); - if(tmpobj == ERRPTR) { // Error check - ret = ERRPTR; - break ; - } - if(tmpobj) Object_Dereference(tmpobj); // Free unused value - } + if(tmpobj) Object_Dereference(tmpobj); // Free unused value } // Clean up variables while(blockInfo.FirstVar) @@ -241,6 +239,9 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) Variable_Destroy( blockInfo.FirstVar ); blockInfo.FirstVar = nextVar; } + + if( blockInfo.RetVal ) + Block->RetVal = blockInfo.RetVal; } break; @@ -289,9 +290,46 @@ tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node) } break; - // Return's special handling happens elsewhere + // Conditional + case NODETYPE_IF: + ret = AST_ExecuteNode(Block, Node->If.Condition); + if( Object_IsTrue(ret) ) { + AST_ExecuteNode(Block, Node->If.True); + } + else { + AST_ExecuteNode(Block, Node->If.False); + } + Object_Dereference(ret); + break; + + // Loop + case NODETYPE_LOOP: + ret = AST_ExecuteNode(Block, Node->For.Init); + if( Node->For.bCheckAfter ) { + do { + Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Code); + Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Condition); + } while( Object_IsTrue(ret) ); + } + else { + Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Condition); + while( Object_IsTrue(ret) ) { + Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Code); + Object_Dereference(ret); + ret = AST_ExecuteNode(Block, Node->For.Condition); + } + Object_Dereference(ret); + } + break; + + // Return case NODETYPE_RETURN: ret = AST_ExecuteNode(Block, Node->UniOp.Value); + Block->RetVal = ret; // Return value set break; // Define a variable diff --git a/Usermode/Libraries/libspiderscript.so_src/main.c b/Usermode/Libraries/libspiderscript.so_src/main.c index a6b1bde5..0c3cb072 100644 --- a/Usermode/Libraries/libspiderscript.so_src/main.c +++ b/Usermode/Libraries/libspiderscript.so_src/main.c @@ -107,7 +107,8 @@ tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script, // Execute! if(fcn) { tAST_BlockState bs; - bs.FirstVar = NULL; //< TODO: Parameters + bs.FirstVar = NULL; + bs.RetVal = NULL; bs.Parent = NULL; bs.Script = Script; { @@ -122,6 +123,8 @@ tSpiderValue *SpiderScript_ExecuteMethod(tSpiderScript *Script, } } ret = AST_ExecuteNode(&bs, fcn->Code); + //Object_Dereference(ret); + ret = bs.RetVal; bFound = 1; } } diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c index 5622123e..b25dd212 100644 --- a/Usermode/Libraries/libspiderscript.so_src/parse.c +++ b/Usermode/Libraries/libspiderscript.so_src/parse.c @@ -36,6 +36,11 @@ tAST_Node *Parse_GetIdent(tParser *Parser); void SyntaxAssert(tParser *Parser, int Have, int Want); +#define TODO(Parser, message...) do {\ + fprintf(stderr, "TODO: "message);\ + longjmp(Parser->JmpTarget, -1);\ +}while(0) + // === CODE === /** * \brief Parse a buffer into a syntax tree @@ -64,12 +69,14 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer) ret = AST_NewScript(); mainCode = AST_NewCodeBlock(); + // Give us an error fallback if( setjmp( parser.JmpTarget ) != 0 ) { AST_FreeNode( mainCode ); return NULL; } + // Parse the file! while(Parser->Token != TOK_EOF) { switch( GetToken(Parser) ) @@ -159,7 +166,12 @@ tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer) tAST_Node *Parse_DoCodeBlock(tParser *Parser) { tAST_Node *ret; - SyntaxAssert(Parser, GetToken(Parser), TOK_BRACE_OPEN ); + + // Check if we are being called for a one-liner + if( GetToken(Parser) != TOK_BRACE_OPEN ) { + PutBack(Parser); + return Parse_DoBlockLine(Parser); + } ret = AST_NewCodeBlock(); @@ -191,8 +203,26 @@ tAST_Node *Parse_DoBlockLine(tParser *Parser) break; // Control Statements - //case TOK_RWD_IF: - // break; + case TOK_RWD_IF: + { + tAST_Node *cond, *true, *false = NULL; + GetToken(Parser); // eat the if + SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN); + cond = Parse_DoExpr0(Parser); // Get condition + SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE); + true = Parse_DoCodeBlock(Parser); + if( LookAhead(Parser) == TOK_RWD_ELSE ) { + GetToken(Parser); + false = Parse_DoCodeBlock(Parser); + } + ret = AST_NewIf(cond, true, false); + } + return ret; + case TOK_RWD_FOR: + case TOK_RWD_DO: + case TOK_RWD_WHILE: + TODO(Parser, "Implement if, for, do and while\n"); + break; // Define Variables case TOKEN_GROUP_TYPES: