diff --git a/src/Language/JavaScript/Parser/AST.hs b/src/Language/JavaScript/Parser/AST.hs index ea280632..be1f27d9 100644 --- a/src/Language/JavaScript/Parser/AST.hs +++ b/src/Language/JavaScript/Parser/AST.hs @@ -22,6 +22,7 @@ module Language.JavaScript.Parser.AST , JSArrayElement (..) , JSCommaList (..) , JSCommaTrailingList (..) + , JSArrowParameterList (..) -- Modules , JSModuleItem (..) @@ -170,7 +171,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 !JSAnnot !(JSCommaList JSIdent) !JSAnnot !JSAnnot !JSStatement -- ^parameter list,arrow,block` + | JSArrowExpression !JSArrowParameterList !JSAnnot !JSStatement -- ^parameter list,arrow,block` | JSFunctionExpression !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSIdent) !JSAnnot !JSBlock -- ^fn,name,lb, parameter list,rb,block` | JSMemberDot !JSExpression !JSAnnot !JSExpression -- ^firstpart, dot, name | JSMemberExpression !JSExpression !JSAnnot !(JSCommaList JSExpression) !JSAnnot -- expr, lb, args, rb @@ -183,6 +184,11 @@ data JSExpression | JSVarInitExpression !JSExpression !JSVarInitializer -- ^identifier, initializer deriving (Data, Eq, Show, Typeable) +data JSArrowParameterList + = JSUnparenthesizedArrowParameter !JSIdent + | JSParenthesizedArrowParameterList !JSAnnot !(JSCommaList JSIdent) !JSAnnot + deriving (Data, Eq, Show, Typeable) + data JSBinOp = JSBinOpAnd !JSAnnot | JSBinOpAs !JSAnnot @@ -369,7 +375,7 @@ instance ShowStripped JSExpression where ss (JSExpressionParen _lp x _rp) = "JSExpressionParen (" ++ ss x ++ ")" ss (JSExpressionPostfix xs op) = "JSExpressionPostfix (" ++ ss op ++ "," ++ ss xs ++ ")" ss (JSExpressionTernary x1 _q x2 _c x3) = "JSExpressionTernary (" ++ ss x1 ++ "," ++ ss x2 ++ "," ++ ss x3 ++ ")" - ss (JSArrowExpression _ n _ _ e) = "JSArrowExpression (" ++ ss n ++ ") => " ++ ss e + ss (JSArrowExpression ps _ e) = "JSArrowExpression (" ++ ss ps ++ ") => " ++ ss e ss (JSFunctionExpression _ n _lb pl _rb x3) = "JSFunctionExpression " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ "))" ss (JSHexInteger _ s) = "JSHexInteger " ++ singleQuote s ss (JSOctal _ s) = "JSOctal " ++ singleQuote s @@ -388,6 +394,10 @@ instance ShowStripped JSExpression where ss (JSVarInitExpression x1 x2) = "JSVarInitExpression (" ++ ss x1 ++ ") " ++ ss x2 ss (JSSpreadExpression _ x1) = "JSSpreadExpression (" ++ ss x1 ++ ")" +instance ShowStripped JSArrowParameterList where + ss (JSUnparenthesizedArrowParameter x) = ss x + ss (JSParenthesizedArrowParameterList _ xs _) = ss xs + instance ShowStripped JSModuleItem where ss (JSModuleExportDeclaration _ x1) = "JSModuleExportDeclaration (" ++ ss x1 ++ ")" ss (JSModuleImportDeclaration _ x1) = "JSModuleImportDeclaration (" ++ ss x1 ++ ")" diff --git a/src/Language/JavaScript/Parser/Grammar7.y b/src/Language/JavaScript/Parser/Grammar7.y index 1c2217b0..5a7c8da0 100644 --- a/src/Language/JavaScript/Parser/Grammar7.y +++ b/src/Language/JavaScript/Parser/Grammar7.y @@ -1136,10 +1136,16 @@ FunctionExpression : ArrowFunctionExpression { $1 {- 'ArrowFunctionExpressio | NamedFunctionExpression { $1 {- 'FunctionExpression2' -} } ArrowFunctionExpression :: { AST.JSExpression } -ArrowFunctionExpression : LParen RParen Arrow StatementOrBlock - { AST.JSArrowExpression $1 AST.JSLNil $2 $3 $4 {- 'ArrowFunctionExpression1' -} } - | LParen FormalParameterList RParen Arrow StatementOrBlock - { AST.JSArrowExpression $1 $2 $3 $4 $5 {- 'ArrowFunctionExpression3' -} } +ArrowFunctionExpression : ArrowParameterList Arrow StatementOrBlock + { AST.JSArrowExpression $1 $2 $3 } + +ArrowParameterList :: { AST.JSArrowParameterList } +ArrowParameterList : Identifier + { AST.JSUnparenthesizedArrowParameter (identName $1) } + | LParen RParen + { AST.JSParenthesizedArrowParameterList $1 AST.JSLNil $2 } + | LParen FormalParameterList RParen + { AST.JSParenthesizedArrowParameterList $1 $2 $3 } StatementOrBlock :: { AST.JSStatement } StatementOrBlock : Block MaybeSemi { blockToStatement $1 $2 } diff --git a/src/Language/JavaScript/Pretty/Printer.hs b/src/Language/JavaScript/Pretty/Printer.hs index 5b420d4f..30a4c328 100644 --- a/src/Language/JavaScript/Pretty/Printer.hs +++ b/src/Language/JavaScript/Pretty/Printer.hs @@ -72,7 +72,7 @@ instance RenderJS JSExpression where -- Non-Terminals (|>) pacc (JSArrayLiteral als xs ars) = pacc |> als |> "[" |> xs |> ars |> "]" - (|>) pacc (JSArrowExpression lp xs rp a x) = pacc |> lp |> "(" |> xs |> rp |> ")" |> a |> "=>" |> x + (|>) pacc (JSArrowExpression xs a x) = pacc |> xs |> a |> "=>" |> x (|>) pacc (JSAssignExpression lhs op rhs) = pacc |> lhs |> op |> rhs (|>) pacc (JSCallExpression ex lb xs rb) = pacc |> ex |> lb |> "(" |> xs |> rb |> ")" (|>) pacc (JSCallExpressionDot ex os xs) = pacc |> ex |> os |> "." |> xs @@ -93,6 +93,9 @@ instance RenderJS JSExpression where (|>) pacc (JSVarInitExpression x1 x2) = pacc |> x1 |> x2 (|>) pacc (JSSpreadExpression a e) = pacc |> a |> "..." |> e +instance RenderJS JSArrowParameterList where + (|>) pacc (JSUnparenthesizedArrowParameter p) = pacc |> p + (|>) pacc (JSParenthesizedArrowParameterList lb ps rb) = pacc |> lb |> "(" |> ps |> ")" |> rb -- ----------------------------------------------------------------------------- -- Need an instance of RenderJS for every component of every JSExpression or JSAnnot -- constuctor. diff --git a/src/Language/JavaScript/Process/Minify.hs b/src/Language/JavaScript/Process/Minify.hs index c3f94117..0bf76748 100644 --- a/src/Language/JavaScript/Process/Minify.hs +++ b/src/Language/JavaScript/Process/Minify.hs @@ -148,7 +148,7 @@ instance MinifyJS JSExpression where -- Non-Terminals fix _ (JSArrayLiteral _ xs _) = JSArrayLiteral emptyAnnot (map fixEmpty xs) emptyAnnot - fix _ (JSArrowExpression _ ps _ _ ss) = JSArrowExpression emptyAnnot (fixEmpty ps) emptyAnnot emptyAnnot (fixStmt emptyAnnot noSemi ss) + fix a (JSArrowExpression ps _ ss) = JSArrowExpression (fix a ps) emptyAnnot (fixStmt emptyAnnot noSemi ss) fix a (JSAssignExpression lhs op rhs) = JSAssignExpression (fix a lhs) (fixEmpty op) (fixEmpty rhs) fix a (JSCallExpression ex _ xs _) = JSCallExpression (fix a ex) emptyAnnot (fixEmpty xs) emptyAnnot fix a (JSCallExpressionDot ex _ xs) = JSCallExpressionDot (fix a ex) emptyAnnot (fixEmpty xs) @@ -169,6 +169,9 @@ instance MinifyJS JSExpression where fix a (JSVarInitExpression x1 x2) = JSVarInitExpression (fix a x1) (fixEmpty x2) fix a (JSSpreadExpression _ e) = JSSpreadExpression a (fixEmpty e) +instance MinifyJS JSArrowParameterList where + fix _ (JSUnparenthesizedArrowParameter p) = JSUnparenthesizedArrowParameter (fixEmpty p) + fix _ (JSParenthesizedArrowParameterList _ ps _) = JSParenthesizedArrowParameterList emptyAnnot (fixEmpty ps) emptyAnnot fixVarList :: JSCommaList JSExpression -> JSCommaList JSExpression fixVarList (JSLCons h _ v) = JSLCons (fixVarList h) emptyAnnot (fixEmpty v) @@ -302,7 +305,7 @@ instance MinifyJS JSImportNameSpace where fix a (JSImportNameSpace _ _ ident) = JSImportNameSpace (JSBinOpTimes a) (JSBinOpAs spaceAnnot) (fixSpace ident) instance MinifyJS JSImportsNamed where - fix _ (JSImportsNamed _ imps _) = JSImportsNamed emptyAnnot (fixEmpty imps) emptyAnnot + fix _ (JSImportsNamed _ imps _) = JSImportsNamed emptyAnnot (fixEmpty imps) emptyAnnot instance MinifyJS JSImportSpecifier where fix _ (JSImportSpecifier x1) = JSImportSpecifier (fixEmpty x1) diff --git a/test/Test/Language/Javascript/ExpressionParser.hs b/test/Test/Language/Javascript/ExpressionParser.hs index 5fdb4eab..22377c00 100644 --- a/test/Test/Language/Javascript/ExpressionParser.hs +++ b/test/Test/Language/Javascript/ExpressionParser.hs @@ -123,6 +123,7 @@ testExpressionParser = describe "Parse expressions:" $ do testExpr "function(){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' () (JSBlock []))))" testExpr "function(a){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSIdentifier 'a') (JSBlock []))))" testExpr "function(a,b){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSIdentifier 'a',JSIdentifier '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, b) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSIdentifier 'b')) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))" diff --git a/test/Test/Language/Javascript/Minify.hs b/test/Test/Language/Javascript/Minify.hs index f40ee79c..e385e241 100644 --- a/test/Test/Language/Javascript/Minify.hs +++ b/test/Test/Language/Javascript/Minify.hs @@ -106,6 +106,7 @@ testMinifyExpr = describe "Minify expressions:" $ do minifyExpr " function ( a ) { } " `shouldBe` "function(a){}" minifyExpr " function ( a , b ) { return a + b ; } " `shouldBe` "function(a,b){return a+b}" + minifyExpr "a => {}" `shouldBe` "a=>{}" minifyExpr "(a) => {}" `shouldBe` "(a)=>{}" minifyExpr "( a ) => { a + 2 }" `shouldBe` "(a)=>a+2" minifyExpr "(a, b) => a + b" `shouldBe` "(a,b)=>a+b" diff --git a/test/Test/Language/Javascript/RoundTrip.hs b/test/Test/Language/Javascript/RoundTrip.hs index e71ff60c..7877a70b 100644 --- a/test/Test/Language/Javascript/RoundTrip.hs +++ b/test/Test/Language/Javascript/RoundTrip.hs @@ -63,6 +63,7 @@ testRoundTrip = describe "Roundtrip:" $ do testRT "/*a*/x/*b*/=/*c*/{/*d*/get/*e*/ foo/*f*/(/*g*/)/*h*/ {/*i*/return/*j*/ 1/*k*/}/*l*/,/*m*/set/*n*/ foo/*o*/(/*p*/a/*q*/) /*r*/{/*s*/x/*t*/=/*u*/a/*v*/}/*w*/}" testRT "... /*a*/ x" + testRT "a => {}" testRT "(a) => { a + 2 }" testRT "(a, b) => {}" testRT "(a, b) => a + b"