Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix arrow function body parsing #1

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/Language/JavaScript/Parser/AST.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module Language.JavaScript.Parser.AST
( JSExpression (..)
, JSAnnot (..)
, JSConciseBody(..)
, JSBinOp (..)
, JSUnaryOp (..)
, JSSemi (..)
Expand Down Expand Up @@ -188,7 +189,7 @@ data JSExpression
| JSExpressionParen !JSAnnot !JSExpression !JSAnnot -- ^lb,expression,rb
| JSExpressionPostfix !JSExpression !JSUnaryOp -- ^expression, operator
| JSExpressionTernary !JSExpression !JSAnnot !JSExpression !JSAnnot !JSExpression -- ^cond, ?, trueval, :, falseval
| JSArrowExpression !JSArrowParameterList !JSAnnot !JSStatement -- ^parameter list,arrow,block`
| JSArrowExpression !JSArrowParameterList !JSAnnot !JSConciseBody -- ^parameter list,arrow,body`
| JSFunctionExpression !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^fn,name,lb, parameter list,rb,block`
| JSGeneratorExpression !JSAnnot !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^fn,*,name,lb, parameter list,rb,block`
| JSMemberDot !JSExpression !JSAnnot !JSExpression -- ^firstpart, dot, name
Expand All @@ -205,6 +206,11 @@ data JSExpression
| JSYieldFromExpression !JSAnnot !JSAnnot !JSExpression -- ^yield, *, expr
deriving (Data, Eq, Show, Typeable)

data JSConciseBody
= JSConciseFunctionBody !JSBlock
| JSConciseExpressionBody !JSExpression
deriving (Data, Eq, Show, Typeable)

data JSArrowParameterList
= JSUnparenthesizedArrowParameter !JSIdent
| JSParenthesizedArrowParameterList !JSAnnot !(JSCommaList JSExpression) !JSAnnot
Expand Down Expand Up @@ -455,6 +461,10 @@ instance ShowStripped JSArrowParameterList where
ss (JSUnparenthesizedArrowParameter x) = ss x
ss (JSParenthesizedArrowParameterList _ xs _) = ss xs

instance ShowStripped JSConciseBody where
ss (JSConciseFunctionBody b) = ss b
ss (JSConciseExpressionBody e) = ss e

instance ShowStripped JSModuleItem where
ss (JSModuleExportDeclaration _ x1) = "JSModuleExportDeclaration (" ++ ss x1 ++ ")"
ss (JSModuleImportDeclaration _ x1) = "JSModuleImportDeclaration (" ++ ss x1 ++ ")"
Expand Down
16 changes: 12 additions & 4 deletions src/Language/JavaScript/Parser/Grammar7.y
Original file line number Diff line number Diff line change
Expand Up @@ -1238,18 +1238,26 @@ FunctionExpression : ArrowFunctionExpression { $1 {- 'ArrowFunctionExpressio
| LambdaExpression { $1 {- 'FunctionExpression1' -} }
| NamedFunctionExpression { $1 {- 'FunctionExpression2' -} }

-- ArrowFunctionExpression :
-- ( ArrowParameterList ) => ConciseBody See clause 14.2
ArrowFunctionExpression :: { AST.JSExpression }
ArrowFunctionExpression : ArrowParameterList Arrow StatementOrBlock
ArrowFunctionExpression : ArrowParameterList Arrow ConciseBody
{ AST.JSArrowExpression $1 $2 $3 }

ArrowParameterList :: { AST.JSArrowParameterList }
ArrowParameterList : PrimaryExpression {%^ toArrowParameterList $1 }
| LParen RParen
{ AST.JSParenthesizedArrowParameterList $1 AST.JSLNil $2 }

StatementOrBlock :: { AST.JSStatement }
StatementOrBlock : Block MaybeSemi { blockToStatement $1 $2 }
| Expression MaybeSemi { expressionToStatement $1 $2 }
-- ConciseBody :
-- { FunctionBody }
-- ExpressionBody
ConciseBody :: { AST.JSConciseBody }
ConciseBody : FunctionBody { AST.JSConciseFunctionBody $1 }
| ExpressionBody { AST.JSConciseExpressionBody $1 }

ExpressionBody :: { AST.JSExpression }
ExpressionBody : AssignmentExpression { $1 }

-- StatementListItem :
-- Statement
Expand Down
4 changes: 4 additions & 0 deletions src/Language/JavaScript/Pretty/Printer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ instance RenderJS JSExpression where
instance RenderJS JSArrowParameterList where
(|>) pacc (JSUnparenthesizedArrowParameter p) = pacc |> p
(|>) pacc (JSParenthesizedArrowParameterList lb ps rb) = pacc |> lb |> "(" |> ps |> ")" |> rb

instance RenderJS JSConciseBody where
(|>) pacc (JSConciseExpressionBody e) = pacc |> e
(|>) pacc (JSConciseFunctionBody b) = pacc |> b
-- -----------------------------------------------------------------------------
-- Need an instance of RenderJS for every component of every JSExpression or JSAnnot
-- constuctor.
Expand Down
6 changes: 5 additions & 1 deletion src/Language/JavaScript/Process/Minify.hs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ instance MinifyJS JSExpression where

-- Non-Terminals
fix _ (JSArrayLiteral _ xs _) = JSArrayLiteral emptyAnnot (map fixEmpty xs) emptyAnnot
fix a (JSArrowExpression ps _ ss) = JSArrowExpression (fix a ps) emptyAnnot (fixStmt emptyAnnot noSemi ss)
fix a (JSArrowExpression ps _ fb) = JSArrowExpression (fix a ps) emptyAnnot (fixEmpty fb)
fix a (JSAssignExpression lhs op rhs) = JSAssignExpression (fix a lhs) (fixEmpty op) (fixEmpty rhs)
fix a (JSAwaitExpression _ ex) = JSAwaitExpression a (fixSpace ex)
fix a (JSCallExpression ex _ xs _) = JSCallExpression (fix a ex) emptyAnnot (fixEmpty xs) emptyAnnot
Expand Down Expand Up @@ -187,6 +187,10 @@ instance MinifyJS JSArrowParameterList where
fix _ (JSUnparenthesizedArrowParameter p) = JSUnparenthesizedArrowParameter (fixEmpty p)
fix _ (JSParenthesizedArrowParameterList _ ps _) = JSParenthesizedArrowParameterList emptyAnnot (fixEmpty ps) emptyAnnot

instance MinifyJS JSConciseBody where
fix _ (JSConciseExpressionBody e) = JSConciseExpressionBody (fixEmpty e)
fix _ (JSConciseFunctionBody b) = JSConciseFunctionBody (fixEmpty b)

fixVarList :: JSCommaList JSExpression -> JSCommaList JSExpression
fixVarList (JSLCons h _ v) = JSLCons (fixVarList h) emptyAnnot (fixEmpty v)
fixVarList (JSLOne a) = JSLOne (fixSpace a)
Expand Down
10 changes: 6 additions & 4 deletions test/Test/Language/Javascript/ExpressionParser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,16 @@ testExpressionParser = describe "Parse expressions:" $ do
testExpr "function([a,b]){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b']) (JSBlock [])))"
testExpr "function([a,...b]){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSArrayLiteral [JSIdentifier 'a',JSComma,JSSpreadExpression (JSIdentifier 'b')]) (JSBlock [])))"
testExpr "function({a,b}){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSObjectLiteral [JSPropertyIdentRef 'a',JSPropertyIdentRef 'b']) (JSBlock [])))"
testExpr "a => {}" `shouldBe` "Right (JSAstExpression (JSArrowExpression (JSIdentifier 'a') => JSStatementBlock []))"
testExpr "(a) => { a + 2 }" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a')) => JSStatementBlock [JSExpressionBinary ('+',JSIdentifier 'a',JSDecimal '2')]))"
testExpr "(a, b) => {}" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSIdentifier 'b')) => JSStatementBlock []))"
testExpr "a => {}" `shouldBe` "Right (JSAstExpression (JSArrowExpression (JSIdentifier 'a') => JSBlock []))"
testExpr "(a) => { a + 2 }" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a')) => JSBlock [JSExpressionBinary ('+',JSIdentifier 'a',JSDecimal '2')]))"
testExpr "(a, b) => {}" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSIdentifier 'b')) => JSBlock []))"
testExpr "(a, b) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSIdentifier 'b')) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))"
testExpr "() => { 42 }" `shouldBe` "Right (JSAstExpression (JSArrowExpression (()) => JSStatementBlock [JSDecimal '42']))"
testExpr "() => { 42 }" `shouldBe` "Right (JSAstExpression (JSArrowExpression (()) => JSBlock [JSDecimal '42']))"
testExpr "(a, ...b) => b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b'))) => JSIdentifier 'b'))"
testExpr "(a,b=1) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSOpAssign ('=',JSIdentifier 'b',JSDecimal '1'))) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))"
testExpr "([a,b]) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b'])) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))"
testExpr "{f:()=>{},y:2}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'f') [JSArrowExpression (()) => JSBlock []],JSPropertyNameandValue (JSIdentifier 'y') [JSDecimal '2']]))"
testExpr "{f:x=>x,y:2}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'f') [JSArrowExpression (JSIdentifier 'x') => JSIdentifier 'x'],JSPropertyNameandValue (JSIdentifier 'y') [JSDecimal '2']]))"

it "generator expression" $ do
testExpr "function*(){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' () (JSBlock [])))"
Expand Down
4 changes: 2 additions & 2 deletions test/Test/Language/Javascript/Minify.hs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ testMinifyExpr = describe "Minify expressions:" $ do

minifyExpr "a => {}" `shouldBe` "a=>{}"
minifyExpr "(a) => {}" `shouldBe` "(a)=>{}"
minifyExpr "( a ) => { a + 2 }" `shouldBe` "(a)=>a+2"
minifyExpr "( a ) => { a + 2 }" `shouldBe` "(a)=>{a+2}"
minifyExpr "(a, b) => a + b" `shouldBe` "(a,b)=>a+b"
minifyExpr "() => { 42 }" `shouldBe` "()=>42"
minifyExpr "() => { 42 }" `shouldBe` "()=>{42}"
minifyExpr "(a, ...b) => b" `shouldBe` "(a,...b)=>b"
minifyExpr "(a = 1, b = 2) => a + b" `shouldBe` "(a=1,b=2)=>a+b"
minifyExpr "( [ a , b ] ) => a + b" `shouldBe` "([a,b])=>a+b"
Expand Down
2 changes: 2 additions & 0 deletions test/Test/Language/Javascript/StatementParser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ testStatementParser = describe "Parse statements:" $ do
testStmt "{}" `shouldBe` "Right (JSAstStatement (JSStatementBlock []))"
testStmt "{x=1}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')]))"
testStmt "{x=1;y=2}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon,JSOpAssign ('=',JSIdentifier 'y',JSDecimal '2')]))"
testStmt "{()=>{};``}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSArrowExpression (()) => JSBlock [],JSSemicolon,JSTemplateLiteral ((),'``',[])]))"
testStmt "{x=>x;``}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSArrowExpression (JSIdentifier 'x') => JSIdentifier 'x',JSSemicolon,JSTemplateLiteral ((),'``',[])]))"
testStmt "{{}}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSStatementBlock []]))"
testStmt "{{{}}}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSStatementBlock [JSStatementBlock []]]))"

Expand Down