Skip to content

Commit

Permalink
Finally able to parse the if else statement
Browse files Browse the repository at this point in the history
  • Loading branch information
alanz committed Dec 12, 2010
1 parent c2d9ea4 commit b0b1e32
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -17,3 +17,4 @@
/.ghci~
/runtests.hs~
/src/Language/JavaScript/Parser.hs~
/parse.txt
16 changes: 13 additions & 3 deletions runtests.hs
Expand Up @@ -35,7 +35,8 @@ testSuite = testGroup "Parser"
, testCase "LiteralRegex1" (testPE "/blah/" "Right (JSRegEx \"/blah/\")")
, testCase "LiteralRegex2" (testPE "/$/g" "Right (JSRegEx \"/$/g\")")
, testCase "LiteralRegex3" (testPE "/\\n/g" "Right (JSRegEx \"/\\\\n/g\")")

, testCase "LiteralRegex4" (testPE "/^\"(?:\\.|[^\"])*\"|^'(?:[^']|\\.)*'/" "Right (JSRegEx \"/^\\\"(?:\\\\.|[^\\\"])*\\\"|^'(?:[^']|\\\\.)*'/\")")

, testCase "Identifier1" (testPE "_$" "Right (JSIdentifier \"_$\")")
, testCase "Identifier2" (testPE "this_" "Right (JSIdentifier \"this_\")")

Expand All @@ -50,6 +51,8 @@ testSuite = testGroup "Parser"
, testCase "ObjectLiteral2" (testPE "{x:1}" "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"x\") [JSDecimal \"1\"]])")
, testCase "ObjectLiteral3" (testPE "{x:1,y:2}" "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"x\") [JSDecimal \"1\"],JSPropertyNameandValue (JSIdentifier \"y\") [JSDecimal \"2\"]])")

, testCase "ObjectLiteral4" (testPE "{evaluate:evaluate,load:function load(s){if(x)return s;1}}" "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"evaluate\") [JSIdentifier \"evaluate\"],JSPropertyNameandValue (JSIdentifier \"load\") [JSFunction (JSIdentifier \"load\") [JSIdentifier \"s\"] (JSFunctionBody [JSSourceElements [JSIf (JSExpression [JSIdentifier \"x\"]) (JSReturn [JSExpression [JSIdentifier \"s\"],JSLiteral \";\"]),JSExpression [JSDecimal \"1\"]]])]])")

, testCase "ExpressionParen" (testPE "(56)" "Right (JSExpressionParen (JSExpression [JSDecimal \"56\"]))")

, testCase "Statement1" (testStmt "x" "Right (JSExpression [JSIdentifier \"x\"])")
Expand Down Expand Up @@ -140,6 +143,7 @@ testSuite = testGroup "Parser"
, testCase "If1" (testStmt "if (1) {}" "Right (JSIf (JSExpression [JSDecimal \"1\"]) (JSLiteral \";\"))")

, testCase "IfElse1" (testStmt "if (1) {} else {}" "Right (JSIfElse (JSExpression [JSDecimal \"1\"]) (JSLiteral \";\") (JSLiteral \";\"))")
, testCase "IfElse2" (testStmt "if (1) x=1; else {}" "Right (JSIfElse (JSExpression [JSDecimal \"1\"]) (JSBlock (JSStatementList [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"x\",JSOperator \"=\",JSDecimal \"1\"]]])) (JSLiteral \";\"))")

, testCase "DoWhile1" (testStmt "do {x=1} while (true);" "Right (JSDoWhile (JSBlock (JSStatementList [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"x\",JSOperator \"=\",JSDecimal \"1\"]]])) (JSExpression [JSLiteral \"true\"]) (JSLiteral \";\"))")
, testCase "While1" (testStmt "while(true);" "Right (JSWhile (JSExpression [JSLiteral \"true\"]) (JSLiteral \";\"))")
Expand Down Expand Up @@ -194,8 +198,13 @@ testSuite = testGroup "Parser"

, testCase "Comment2" (testProg "/*x=1\ny=2\n*/z=2;//foo\na" "Right (JSSourceElementsTop [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"z\",JSOperator \"=\",JSDecimal \"2\"]],JSLiteral \";\",JSExpression [JSIdentifier \"a\"]])")

-- , testCase "min_100_animals" (testProg "function Animal(name){if(!name)throw new Error('Must specify an animal name');this.name=name};Animal.prototype.toString=function(){return this.name};o=new Animal(\"bob\");o.toString()==\"bob\"" "")
, testCase "min_100_animals" (testProg "Animal=function(){return this.name};" "Right (JSSourceElementsTop [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"Animal\",JSOperator \"=\",JSFunctionExpression [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])]],JSLiteral \";\"])")
, testCase "min_100_animals1" (testProg "function Animal(name){if(!name)throw new Error('Must specify an animal name');this.name=name};Animal.prototype.toString=function(){return this.name};o=new Animal(\"bob\");o.toString()==\"bob\"" "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"Animal\") [JSIdentifier \"name\"] (JSFunctionBody [JSSourceElements [JSIf (JSExpression [JSUnary \"!\",JSIdentifier \"name\"]) (JSBlock (JSStatementList [JSThrow (JSExpression [JSLiteral \"new \",JSIdentifier \"Error\",JSArguments [[JSStringLiteral '\\'' \"Must specify an animal name\"]]])])),JSExpression [JSElement \"assignmentExpression\" [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\"),JSOperator \"=\",JSIdentifier \"name\"]]]]),JSLiteral \";\",JSExpression [JSElement \"assignmentExpression\" [JSMemberDot [JSMemberDot [JSIdentifier \"Animal\"] (JSIdentifier \"prototype\")] (JSIdentifier \"toString\"),JSOperator \"=\",JSFunctionExpression [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])]],JSLiteral \";\",JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"o\",JSOperator \"=\",JSLiteral \"new \",JSIdentifier \"Animal\",JSArguments [[JSStringLiteral '\"' \"bob\"]]]],JSLiteral \";\",JSExpression [JSExpressionBinary \"==\" [JSMemberDot [JSIdentifier \"o\"] (JSIdentifier \"toString\"),JSArguments []] [JSStringLiteral '\"' \"bob\"]]])")

, testCase "min_100_animals2" (testProg "Animal=function(){return this.name};" "Right (JSSourceElementsTop [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"Animal\",JSOperator \"=\",JSFunctionExpression [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])]],JSLiteral \";\"])")

, testCase "min_100_animals3" (testProg "if(a)x=1;y=2" "Right (JSSourceElementsTop [JSIf (JSExpression [JSIdentifier \"a\"]) (JSBlock (JSStatementList [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"x\",JSOperator \"=\",JSDecimal \"1\"]]])),JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"y\",JSOperator \"=\",JSDecimal \"2\"]]])")

, testCase "min_100_animals4" (testProg "if(a)x=a()y=2" "Right (JSSourceElementsTop [JSIf (JSExpression [JSIdentifier \"a\"]) (JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"x\",JSOperator \"=\",JSIdentifier \"a\",JSArguments []]]),JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"y\",JSOperator \"=\",JSDecimal \"2\"]]])")

, testCase "05_regex" (testProg "newlines=spaces.match(/\\n/g)" "Right (JSSourceElementsTop [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"newlines\",JSOperator \"=\",JSMemberDot [JSIdentifier \"spaces\"] (JSIdentifier \"match\"),JSArguments [[JSRegEx \"/\\\\n/g\"]]]]])")

Expand All @@ -205,6 +214,7 @@ testSuite = testGroup "Parser"

, testCase "05_regex4" (testProg "x=i(/^$/g,\"\\\\$&\")" "Right (JSSourceElementsTop [JSExpression [JSElement \"assignmentExpression\" [JSIdentifier \"x\",JSOperator \"=\",JSIdentifier \"i\",JSArguments [[JSRegEx \"/^$/g\"],[JSStringLiteral '\"' \"\\\\\\\\$&\"]]]]])")


]

srcHelloWorld = "Hello"
Expand Down
71 changes: 56 additions & 15 deletions src/Language/JavaScript/Parser/Grammar.y
Expand Up @@ -230,10 +230,15 @@ ObjectLiteral : '{' PropertyNameandValueList '}' { AST.JSObjectLiteral $2 }

-- <Property Name and Value List> ::= <Property Name> ':' <Assignment Expression>
-- | <Property Name and Value List> ',' <Property Name> ':' <Assignment Expression>

-- Seems we can have function declarations in the value part too
PropertyNameandValueList :: { [ AST.JSNode ] }
PropertyNameandValueList : PropertyName ':' AssignmentExpression { [(AST.JSPropertyNameandValue $1 $3)] }
| PropertyName ':' FunctionDeclaration { [(AST.JSPropertyNameandValue $1 [$3])] }
| PropertyNameandValueList ',' PropertyName ':' AssignmentExpression
{ ($1 ++ [(AST.JSPropertyNameandValue $3 $5)]) }
| PropertyNameandValueList ',' PropertyName ':' FunctionDeclaration
{ ($1 ++ [(AST.JSPropertyNameandValue $3 [$5])]) }


-- <Property Name> ::= Identifier
Expand Down Expand Up @@ -437,21 +442,24 @@ ExpressionOpt : Expression { [$1] {- ExpressionOpt -}}
-- | <Throw Statement>
-- | <Try Statement>
-- | <Expression>
Statement : StatementBlock { $1 {- Statement1 -}}
| VariableStatement { $1 {- Statement2 -}}
Statement : StatementNoEmpty { $1 {- Statement1 -}}
| EmptyStatement { $1 {- Statement3 -}}
| IfStatement { $1 {- Statement4 -}}
| IfElseStatement { $1 {- Statement5 -}}
| IterationStatement { $1 {- Statement6 -}}
| ContinueStatement { $1 {- Statement7 -}}
| BreakStatement { $1 {- Statement8 -}}
| ReturnStatement { $1 {- Statement9 -}}
| WithStatement { $1 {- Statement10 -}}
| LabelledStatement { $1 {- Statement11 -}}
| SwitchStatement { $1 {- Statement12 -}}
| ThrowStatement { $1 {- Statement13 -}}
| TryStatement { $1 {- Statement14 -}}
| Expression { $1 {- Statement15 -}}

StatementNoEmpty : StatementBlock { $1 {- StatementNoEmpty1 -}}
| VariableStatement { $1 {- StatementNoEmpty2 -}}
-- | EmptyStatement { $1 {- StatementNoEmpty3 -}}
-- | IfStatement { $1 {- StatementNoEmpty4 -}}
| IfElseStatement { $1 {- StatementNoEmpty5 -}}
| IterationStatement { $1 {- StatementNoEmpty6 -}}
| ContinueStatement { $1 {- StatementNoEmpty7 -}}
| BreakStatement { $1 {- StatementNoEmpty8 -}}
| ReturnStatement { $1 {- StatementNoEmpty9 -}}
| WithStatement { $1 {- StatementNoEmpty10 -}}
| LabelledStatement { $1 {- StatementNoEmpty11 -}}
| SwitchStatement { $1 {- StatementNoEmpty12 -}}
| ThrowStatement { $1 {- StatementNoEmpty13 -}}
| TryStatement { $1 {- StatementNoEmpty14 -}}
| Expression { $1 {- StatementNoEmpty15 -}}

StatementBlock : '{' '}' { (AST.JSLiteral ";") }
| '{' StatementList '}' { (if ($2 == AST.JSStatementList [AST.JSLiteral ";"]) then (AST.JSLiteral ";") else (AST.JSBlock $2)) }
Expand Down Expand Up @@ -483,11 +491,43 @@ Initializer : '=' AssignmentExpression { $2 {- Initializer -}}
EmptyStatement : ';' { (AST.JSLiteral ";") }


{-
-- <If Statement> ::= 'if' '(' <Expression> ')' <Statement>
IfStatement : 'if' '(' Expression ')' Statement { (AST.JSIf $3 $5) }

-- <If Else Statement> ::= 'if' '(' <Expression> ')' <Statement> 'else' <Statement>
IfElseStatement : 'if' '(' Expression ')' Statement 'else' Statement { (AST.JSIfElse $3 $5 $7) }
IfElseStatement : 'if' '(' Expression ')' StatementSemi 'else' Statement { (AST.JSIfElse $3 $5 $7) }
-}

{-
IfElseStatement : 'if' '(' Expression ')' Statement ';' 'else' Statement
{ (AST.JSIfElse $3 (AST.JSBlock (AST.JSStatementList [$5])) $8) }
| 'if' '(' Expression ')' Statement 'else' Statement
{ (AST.JSIfElse $3 $5 $7) }
| 'if' '(' Expression ')' Statement { (AST.JSIf $3 $5) }
-}


IfElseStatement :: { AST.JSNode }
IfElseStatement : 'if' '(' Expression ')' StatementSemi IfElseRest
{ (if ($6 /= []) then
(if (length $6 == 1) then (AST.JSIfElse $3 $5 (head $6))
else (AST.JSIfElse $3 (AST.JSBlock (AST.JSStatementList [$5])) (last $6)))
else (AST.JSIf $3 $5)) }


IfElseRest :: { [AST.JSNode] }
IfElseRest : -- ';' 'else' Statement { [$3,$3] } -- Horrible, but a type-compliant signal nevertheless
{- | -} 'else' Statement { [$2] }
| { [] }

{-
ElsePart : 'else' { 1 }
| ';' 'else' { 2 }
-}
StatementSemi : StatementNoEmpty ';' { (AST.JSBlock (AST.JSStatementList [$1])) }
| StatementNoEmpty { $1 {- StatementSemi -}}


-- <Iteration Statement> ::= 'do' <Statement> 'while' '(' <Expression> ')' ';'
-- | 'while' '(' <Expression> ')' <Statement>
Expand Down Expand Up @@ -591,6 +631,7 @@ Finally : 'finally' Block { (AST.JSFinally $2) }

-- <Function Declaration> ::= 'function' Identifier '(' <Formal Parameter List> ')' '{' <Function Body> '}'
-- | 'function' Identifier '(' ')' '{' <Function Body> '}'
FunctionDeclaration :: { AST.JSNode }
FunctionDeclaration : 'function' Identifier '(' FormalParameterList ')' '{' FunctionBody '}'
{ (AST.JSFunction $2 $4 $7) }
| 'function' Identifier '(' ')' '{' FunctionBody '}'
Expand Down

0 comments on commit b0b1e32

Please sign in to comment.