Added if() statement (and internal support for for,while and do{}while())
authorJohn Hodge <[email protected]>
Thu, 26 Aug 2010 03:56:21 +0000 (11:56 +0800)
committerJohn Hodge <[email protected]>
Thu, 26 Aug 2010 03:56:21 +0000 (11:56 +0800)
- Also improved return behavior

Usermode/Libraries/libspiderscript.so_src/ast.c
Usermode/Libraries/libspiderscript.so_src/ast.h
Usermode/Libraries/libspiderscript.so_src/exec_ast.c
Usermode/Libraries/libspiderscript.so_src/main.c
Usermode/Libraries/libspiderscript.so_src/parse.c

index 45b8176..8df5469 100644 (file)
@@ -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) );
index 4fa98ca..05ed68b 100644 (file)
@@ -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);
index 0421686..b918608 100644 (file)
@@ -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
index a6b1bde..0c3cb07 100644 (file)
@@ -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;
                }
        }
index 5622123..b25dd21 100644 (file)
@@ -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:

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