Skip to content
Merged
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
8 changes: 4 additions & 4 deletions src/Language/JavaScript/Parser/AST.hs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ data JSStatement
| JSForConstOf !JSAnnot !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,var,vardecl,in,expr,rb,stmt
| JSForOf !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,expr,in,expr,rb,stmt
| JSForVarOf !JSAnnot !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,var,vardecl,in,expr,rb,stmt
| JSFunction !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSIdent) !JSAnnot !JSBlock !JSSemi -- ^fn,name, lb,parameter list,rb,block,autosemi
| JSFunction !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock !JSSemi -- ^fn,name, lb,parameter list,rb,block,autosemi
| JSIf !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement -- ^if,(,expr,),stmt
| JSIfElse !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement !JSAnnot !JSStatement -- ^if,(,expr,),stmt,else,rest
| JSLabelled !JSIdent !JSAnnot !JSStatement -- ^identifier,colon,stmt
Expand Down Expand Up @@ -181,7 +181,7 @@ data JSExpression
| JSExpressionPostfix !JSExpression !JSUnaryOp -- ^expression, operator
| JSExpressionTernary !JSExpression !JSAnnot !JSExpression !JSAnnot !JSExpression -- ^cond, ?, trueval, :, falseval
| JSArrowExpression !JSArrowParameterList !JSAnnot !JSStatement -- ^parameter list,arrow,block`
| JSFunctionExpression !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSIdent) !JSAnnot !JSBlock -- ^fn,name,lb, parameter list,rb,block`
| JSFunctionExpression !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !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
| JSMemberNew !JSAnnot !JSExpression !JSAnnot !(JSCommaList JSExpression) !JSAnnot -- ^new, name, lb, args, rb
Expand All @@ -196,7 +196,7 @@ data JSExpression

data JSArrowParameterList
= JSUnparenthesizedArrowParameter !JSIdent
| JSParenthesizedArrowParameterList !JSAnnot !(JSCommaList JSIdent) !JSAnnot
| JSParenthesizedArrowParameterList !JSAnnot !(JSCommaList JSExpression) !JSAnnot
deriving (Data, Eq, Show, Typeable)

data JSBinOp
Expand Down Expand Up @@ -394,7 +394,7 @@ instance ShowStripped JSExpression where
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 ps _ e) = "JSArrowExpression (" ++ ss ps ++ ") => " ++ ss e
ss (JSFunctionExpression _ n _lb pl _rb x3) = "JSFunctionExpression " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ "))"
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
ss (JSIdentifier _ s) = "JSIdentifier " ++ singleQuote s
Expand Down
26 changes: 16 additions & 10 deletions src/Language/JavaScript/Parser/Grammar7.y
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,6 @@ PrimaryExpression : 'this' { AST.JSLiteral (mkJSAnnot $1) "thi
| Literal { $1 {- 'PrimaryExpression2' -} }
| ArrayLiteral { $1 {- 'PrimaryExpression3' -} }
| ObjectLiteral { $1 {- 'PrimaryExpression4' -} }
| SpreadExpression { $1 {- 'PrimaryExpression5' -} }
| TemplateLiteral { mkJSTemplateLiteral Nothing $1 {- 'PrimaryExpression6' -} }
| LParen Expression RParen { AST.JSExpressionParen $1 $2 $3 }

Expand All @@ -499,7 +498,7 @@ Identifier : 'ident' { AST.JSIdentifier (mkJSAnnot $1) (tokenLiteral $1) }


SpreadExpression :: { AST.JSExpression }
SpreadExpression : Spread Expression { AST.JSSpreadExpression $1 $2 {- 'SpreadExpression' -} }
SpreadExpression : Spread AssignmentExpression { AST.JSSpreadExpression $1 $2 {- 'SpreadExpression' -} }

TemplateLiteral :: { JSUntaggedTemplate }
TemplateLiteral : 'tmplnosub' { JSUntaggedTemplate (mkJSAnnot $1) (tokenLiteral $1) [] }
Expand Down Expand Up @@ -584,7 +583,7 @@ PropertyName : IdentifierName { propName $1 {- 'PropertyName1' -} }
-- PropertySetParameterList : See 11.1.5
-- Identifier
PropertySetParameterList :: { AST.JSExpression }
PropertySetParameterList : Identifier { $1 {- 'PropertySetParameterList' -} }
PropertySetParameterList : AssignmentExpression { $1 {- 'PropertySetParameterList' -} }

-- MemberExpression : See 11.2
-- PrimaryExpression
Expand Down Expand Up @@ -861,6 +860,7 @@ AssignmentExpression :: { AST.JSExpression }
AssignmentExpression : ConditionalExpression { $1 {- 'AssignmentExpression1' -} }
| LeftHandSideExpression AssignmentOperator AssignmentExpression
{ AST.JSAssignExpression $1 $2 $3 {- 'AssignmentExpression2' -} }
| SpreadExpression { $1 }

-- AssignmentExpressionNoIn : See 11.13
-- ConditionalExpressionNoIn
Expand Down Expand Up @@ -1167,12 +1167,9 @@ ArrowFunctionExpression : ArrowParameterList Arrow StatementOrBlock
{ AST.JSArrowExpression $1 $2 $3 }

ArrowParameterList :: { AST.JSArrowParameterList }
ArrowParameterList : Identifier
{ AST.JSUnparenthesizedArrowParameter (identName $1) }
ArrowParameterList : PrimaryExpression {%^ toArrowParameterList $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 }
Expand Down Expand Up @@ -1204,9 +1201,9 @@ IdentifierOpt : Identifier { identName $1 {- 'IdentifierOpt1' -} }
-- FormalParameterList : See clause 13
-- Identifier
-- FormalParameterList , Identifier
FormalParameterList :: { AST.JSCommaList AST.JSIdent }
FormalParameterList : Identifier { AST.JSLOne (identName $1) {- 'FormalParameterList1' -} }
| FormalParameterList Comma Identifier { AST.JSLCons $1 $2 (identName $3) {- 'FormalParameterList2' -} }
FormalParameterList :: { AST.JSCommaList AST.JSExpression }
FormalParameterList : AssignmentExpression { AST.JSLOne $1 {- 'FormalParameterList1' -} }
| FormalParameterList Comma AssignmentExpression { AST.JSLCons $1 $2 $3 {- 'FormalParameterList2' -} }

-- FunctionBody : See clause 13
-- SourceElementsopt
Expand Down Expand Up @@ -1414,4 +1411,13 @@ identifierToProperty :: AST.JSExpression -> AST.JSObjectProperty
identifierToProperty (AST.JSIdentifier a s) = AST.JSPropertyIdentRef a s
identifierToProperty x = error $ "Cannot convert '" ++ show x ++ "' to a JSObjectProperty."

toArrowParameterList :: AST.JSExpression -> Token -> Alex AST.JSArrowParameterList
toArrowParameterList (AST.JSIdentifier a s) = const . return $ AST.JSUnparenthesizedArrowParameter (AST.JSIdentName a s)
toArrowParameterList (AST.JSExpressionParen lb x rb) = const . return $ AST.JSParenthesizedArrowParameterList lb (commasToCommaList x) rb
toArrowParameterList _ = parseError

commasToCommaList :: AST.JSExpression -> AST.JSCommaList AST.JSExpression
commasToCommaList (AST.JSCommaExpression l c r) = AST.JSLCons (commasToCommaList l) c r
commasToCommaList x = AST.JSLOne x

}
17 changes: 13 additions & 4 deletions test/Test/Language/Javascript/ExpressionParser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ testExpressionParser = describe "Parse expressions:" $ do
testExpr "{x:1,}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1'],JSComma]))"
testExpr "{x}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyIdentRef 'x']))"
testExpr "{x,}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyIdentRef 'x',JSComma]))"
testExpr "{set x([a,b]=y) {this.a=a;this.b=b}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyAccessor JSAccessorSet (JSIdentifier 'x') [JSOpAssign ('=',JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b'],JSIdentifier 'y')] (JSBlock [JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'a'),JSIdentifier 'a'),JSSemicolon,JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'b'),JSIdentifier 'b')])]))"
testExpr "a={if:1,interface:2}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'a',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'if') [JSDecimal '1'],JSPropertyNameandValue (JSIdentifier 'interface') [JSDecimal '2']])))"
testExpr "a={\n values: 7,\n}\n" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'a',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'values') [JSDecimal '7'],JSComma])))"
testExpr "x={get foo() {return 1},set foo(a) {x=a}}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'x',JSObjectLiteral [JSPropertyAccessor JSAccessorGet (JSIdentifier 'foo') [] (JSBlock [JSReturn JSDecimal '1' ]),JSPropertyAccessor JSAccessorSet (JSIdentifier 'foo') [JSIdentifier 'a'] (JSBlock [JSOpAssign ('=',JSIdentifier 'x',JSIdentifier 'a')])])))"
testExpr "{evaluate:evaluate,load:function load(s){if(x)return s;1}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'evaluate') [JSIdentifier 'evaluate'],JSPropertyNameandValue (JSIdentifier 'load') [JSFunctionExpression 'load' (JSIdentifier 's') (JSBlock [JSIf (JSIdentifier 'x') (JSReturn JSIdentifier 's' JSSemicolon),JSDecimal '1']))]]))"
testExpr "{evaluate:evaluate,load:function load(s){if(x)return s;1}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'evaluate') [JSIdentifier 'evaluate'],JSPropertyNameandValue (JSIdentifier 'load') [JSFunctionExpression 'load' (JSIdentifier 's') (JSBlock [JSIf (JSIdentifier 'x') (JSReturn JSIdentifier 's' JSSemicolon),JSDecimal '1'])]]))"
testExpr "obj = { name : 'A', 'str' : 'B', 123 : 'C', }" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'obj',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'name') [JSStringLiteral 'A'],JSPropertyNameandValue (JSIdentifier ''str'') [JSStringLiteral 'B'],JSPropertyNameandValue (JSIdentifier '123') [JSStringLiteral 'C'],JSComma])))"
testExpr "{[x]:1}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSPropertyComputed (JSIdentifier 'x')) [JSDecimal '1']]))"

Expand Down Expand Up @@ -123,14 +124,22 @@ testExpressionParser = describe "Parse expressions:" $ do
testExpr "x|=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('|=',JSIdentifier 'x',JSDecimal '1')))"

it "function expression" $ 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 "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 "function(...a){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSSpreadExpression (JSIdentifier 'a')) (JSBlock [])))"
testExpr "function(a=1){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSOpAssign ('=',JSIdentifier 'a',JSDecimal '1')) (JSBlock [])))"
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, 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 "(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')))"

it "member expression" $ do
testExpr "x[y]" `shouldBe` "Right (JSAstExpression (JSMemberSquare (JSIdentifier 'x',JSIdentifier 'y')))"
Expand Down
13 changes: 13 additions & 0 deletions test/Test/Language/Javascript/Minify.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,20 @@ testMinifyExpr = describe "Minify expressions:" $ do
minifyExpr " function ( ) { } " `shouldBe` "function(){}"
minifyExpr " function ( a ) { } " `shouldBe` "function(a){}"
minifyExpr " function ( a , b ) { return a + b ; } " `shouldBe` "function(a,b){return a+b}"
minifyExpr " function ( a , ...b ) { return b ; } " `shouldBe` "function(a,...b){return b}"
minifyExpr " function ( a = 1 , b = 2 ) { return a + b ; } " `shouldBe` "function(a=1,b=2){return a+b}"
minifyExpr " function ( [ a , b ] ) { return b ; } " `shouldBe` "function([a,b]){return b}"
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"
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"
minifyExpr "( { a , b , } ) => a + b" `shouldBe` "({a,b})=>a+b"

it "calls" $ do
minifyExpr " a ( ) " `shouldBe` "a()"
Expand All @@ -123,6 +131,7 @@ testMinifyExpr = describe "Minify expressions:" $ do
it "property accessor" $ do
minifyExpr " { get foo ( ) { return x } } " `shouldBe` "{get foo(){return x}}"
minifyExpr " { set foo ( a ) { x = a } } " `shouldBe` "{set foo(a){x=a}}"
minifyExpr " { set foo ( [ a , b ] ) { x = a } } " `shouldBe` "{set foo([a,b]){x=a}}"

it "string concatenation" $ do
minifyExpr " 'ab' + \"cd\" " `shouldBe` "'abcd'"
Expand Down Expand Up @@ -203,6 +212,10 @@ testMinifyStmt = describe "Minify statements:" $ do
minifyStmt " function f ( ) { } ; " `shouldBe` "function f(){}"
minifyStmt " function f ( a ) { } ; " `shouldBe` "function f(a){}"
minifyStmt " function f ( a , b ) { return a + b ; } ; " `shouldBe` "function f(a,b){return a+b}"
minifyStmt " function f ( a , ... b ) { return b ; } ; " `shouldBe` "function f(a,...b){return b}"
minifyStmt " function f ( a = 1 , b = 2 ) { return a + b ; } ; " `shouldBe` "function f(a=1,b=2){return a+b}"
minifyStmt " function f ( [ a , b ] ) { return a + b ; } ; " `shouldBe` "function f([a,b]){return a+b}"
minifyStmt " function f ( { a , b , } ) { return a + b ; } ; " `shouldBe` "function f({a,b}){return a+b}"

it "with" $ do
minifyStmt " with ( x ) { } ; " `shouldBe` "with(x){}"
Expand Down
Loading