diff --git a/src/Language/JavaScript/Parser/AST.hs b/src/Language/JavaScript/Parser/AST.hs index 5bd25b3..ea28063 100644 --- a/src/Language/JavaScript/Parser/AST.hs +++ b/src/Language/JavaScript/Parser/AST.hs @@ -127,6 +127,11 @@ data JSStatement | JSForIn !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,expr,in,expr,rb,stmt | JSForVar !JSAnnot !JSAnnot !JSAnnot !(JSCommaList JSExpression) !JSAnnot !(JSCommaList JSExpression) !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSStatement -- ^for,lb,var,vardecl,semi,expr,semi,expr,rb,stmt | JSForVarIn !JSAnnot !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,var,vardecl,in,expr,rb,stmt + | JSForLet !JSAnnot !JSAnnot !JSAnnot !(JSCommaList JSExpression) !JSAnnot !(JSCommaList JSExpression) !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSStatement -- ^for,lb,var,vardecl,semi,expr,semi,expr,rb,stmt + | JSForLetIn !JSAnnot !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,var,vardecl,in,expr,rb,stmt + | JSForLetOf !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 | JSIf !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement -- ^if,(,expr,),stmt | JSIfElse !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement !JSAnnot !JSStatement -- ^if,(,expr,),stmt,else,rest @@ -196,6 +201,7 @@ data JSBinOp | JSBinOpMinus !JSAnnot | JSBinOpMod !JSAnnot | JSBinOpNeq !JSAnnot + | JSBinOpOf !JSAnnot | JSBinOpOr !JSAnnot | JSBinOpPlus !JSAnnot | JSBinOpRsh !JSAnnot @@ -328,6 +334,11 @@ instance ShowStripped JSStatement where ss (JSForIn _ _lb x1s _i x2 _rb x3) = "JSForIn " ++ ss x1s ++ " (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" ss (JSForVar _ _lb _v x1s _s1 x2s _s2 x3s _rb x4) = "JSForVar " ++ ss x1s ++ " " ++ ss x2s ++ " " ++ ss x3s ++ " (" ++ ss x4 ++ ")" ss (JSForVarIn _ _lb _v x1 _i x2 _rb x3) = "JSForVarIn (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" + ss (JSForLet _ _lb _v x1s _s1 x2s _s2 x3s _rb x4) = "JSForLet " ++ ss x1s ++ " " ++ ss x2s ++ " " ++ ss x3s ++ " (" ++ ss x4 ++ ")" + ss (JSForLetIn _ _lb _v x1 _i x2 _rb x3) = "JSForLetIn (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" + ss (JSForLetOf _ _lb _v x1 _i x2 _rb x3) = "JSForLetOf (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" + ss (JSForOf _ _lb x1s _i x2 _rb x3) = "JSForOf " ++ ss x1s ++ " (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" + ss (JSForVarOf _ _lb _v x1 _i x2 _rb x3) = "JSForVarOf (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" ss (JSFunction _ n _lb pl _rb x3 _) = "JSFunction " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ ")" ss (JSIf _ _lb x1 _rb x2) = "JSIf (" ++ ss x1 ++ ") (" ++ ss x2 ++ ")" ss (JSIfElse _ _lb x1 _rb x2 _e x3) = "JSIfElse (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")" @@ -463,6 +474,7 @@ instance ShowStripped JSBinOp where ss (JSBinOpMinus _) = "'-'" ss (JSBinOpMod _) = "'%'" ss (JSBinOpNeq _) = "'!='" + ss (JSBinOpOf _) = "'of'" ss (JSBinOpOr _) = "'||'" ss (JSBinOpPlus _) = "'+'" ss (JSBinOpRsh _) = "'>>'" @@ -559,6 +571,7 @@ deAnnot (JSBinOpLt _) = JSBinOpLt JSNoAnnot deAnnot (JSBinOpMinus _) = JSBinOpMinus JSNoAnnot deAnnot (JSBinOpMod _) = JSBinOpMod JSNoAnnot deAnnot (JSBinOpNeq _) = JSBinOpNeq JSNoAnnot +deAnnot (JSBinOpOf _) = JSBinOpOf JSNoAnnot deAnnot (JSBinOpOr _) = JSBinOpOr JSNoAnnot deAnnot (JSBinOpPlus _) = JSBinOpPlus JSNoAnnot deAnnot (JSBinOpRsh _) = JSBinOpRsh JSNoAnnot diff --git a/src/Language/JavaScript/Parser/Grammar7.y b/src/Language/JavaScript/Parser/Grammar7.y index fa5e62d..1c2217b 100644 --- a/src/Language/JavaScript/Parser/Grammar7.y +++ b/src/Language/JavaScript/Parser/Grammar7.y @@ -110,6 +110,7 @@ import qualified Language.JavaScript.Parser.AST as AST 'let' { LetToken {} } 'new' { NewToken {} } 'null' { NullToken {} } + 'of' { OfToken {} } 'return' { ReturnToken {} } 'set' { SetToken {} } 'switch' { SwitchToken {} } @@ -271,6 +272,9 @@ StrictNe : '!==' { AST.JSBinOpStrictNeq (mkJSAnnot $1) } Ne :: { AST.JSBinOp } Ne : '!=' { AST.JSBinOpNeq (mkJSAnnot $1)} +Of :: { AST.JSBinOp } +Of : 'of' { AST.JSBinOpOf (mkJSAnnot $1) } + Or :: { AST.JSBinOp } Or : '||' { AST.JSBinOpOr (mkJSAnnot $1) } @@ -470,6 +474,7 @@ IdentifierName : Identifier {$1} | 'let' { AST.JSIdentifier (mkJSAnnot $1) "let" } | 'new' { AST.JSIdentifier (mkJSAnnot $1) "new" } | 'null' { AST.JSIdentifier (mkJSAnnot $1) "null" } + | 'of' { AST.JSIdentifier (mkJSAnnot $1) "of" } | 'return' { AST.JSIdentifier (mkJSAnnot $1) "return" } | 'set' { AST.JSIdentifier (mkJSAnnot $1) "set" } | 'switch' { AST.JSIdentifier (mkJSAnnot $1) "switch" } @@ -1005,9 +1010,19 @@ IterationStatement : Do StatementNoEmpty While LParen Expression RParen MaybeSem | For LParen Var VariableDeclarationListNoIn Semi ExpressionOpt Semi ExpressionOpt RParen Statement { AST.JSForVar $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 {- 'IterationStatement4' -} } | For LParen LeftHandSideExpression In Expression RParen Statement - { AST.JSForIn $1 $2 $3 $4 $5 $6 $7 {- 'IterationStatement 5-} } + { AST.JSForIn $1 $2 $3 $4 $5 $6 $7 {- 'IterationStatement 5' -} } | For LParen Var VariableDeclarationNoIn In Expression RParen Statement { AST.JSForVarIn $1 $2 $3 $4 $5 $6 $7 $8 {- 'IterationStatement6' -} } + | For LParen Let VariableDeclarationListNoIn Semi ExpressionOpt Semi ExpressionOpt RParen Statement + { AST.JSForLet $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 {- 'IterationStatement 7' -} } + | For LParen Let VariableDeclarationNoIn In Expression RParen Statement + { AST.JSForLetIn $1 $2 $3 $4 $5 $6 $7 $8 {- 'IterationStatement 8' -} } + | For LParen Let VariableDeclarationNoIn Of Expression RParen Statement + { AST.JSForLetOf $1 $2 $3 $4 $5 $6 $7 $8 {- 'IterationStatement 9' -} } + | For LParen LeftHandSideExpression Of Expression RParen Statement + { AST.JSForOf $1 $2 $3 $4 $5 $6 $7 {- 'IterationStatement 10'-} } + | For LParen Var VariableDeclarationNoIn Of Expression RParen Statement + { AST.JSForVarOf $1 $2 $3 $4 $5 $6 $7 $8 {- 'IterationStatement 11' -} } -- ContinueStatement : See 12.7 -- continue [no LineTerminator here] Identifieropt ; diff --git a/src/Language/JavaScript/Parser/Lexer.x b/src/Language/JavaScript/Parser/Lexer.x index 43aaf7e..3e3cc76 100644 --- a/src/Language/JavaScript/Parser/Lexer.x +++ b/src/Language/JavaScript/Parser/Lexer.x @@ -535,6 +535,7 @@ keywordNames = , ( "null", NullToken ) -- null literal + , ( "of", OfToken ) , ( "return", ReturnToken ) , ( "switch", SwitchToken ) , ( "this", ThisToken ) diff --git a/src/Language/JavaScript/Parser/Token.hs b/src/Language/JavaScript/Parser/Token.hs index 7de69bd..0ace205 100644 --- a/src/Language/JavaScript/Parser/Token.hs +++ b/src/Language/JavaScript/Parser/Token.hs @@ -79,6 +79,7 @@ data Token | InstanceofToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | NewToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | NullToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } + | OfToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | ReturnToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | SwitchToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | ThisToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } diff --git a/src/Language/JavaScript/Pretty/Printer.hs b/src/Language/JavaScript/Pretty/Printer.hs index 7c360c2..5b420d4 100644 --- a/src/Language/JavaScript/Pretty/Printer.hs +++ b/src/Language/JavaScript/Pretty/Printer.hs @@ -155,6 +155,7 @@ instance RenderJS JSBinOp where (|>) pacc (JSBinOpMinus annot) = pacc |> annot |> "-" (|>) pacc (JSBinOpMod annot) = pacc |> annot |> "%" (|>) pacc (JSBinOpNeq annot) = pacc |> annot |> "!=" + (|>) pacc (JSBinOpOf annot) = pacc |> annot |> "of" (|>) pacc (JSBinOpOr annot) = pacc |> annot |> "||" (|>) pacc (JSBinOpPlus annot) = pacc |> annot |> "+" (|>) pacc (JSBinOpRsh annot) = pacc |> annot |> ">>" @@ -225,6 +226,11 @@ instance RenderJS JSStatement where (|>) pacc (JSForIn af alb x1s i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> x1s |> i |> x2 |> arb |> ")" |> x3 (|>) pacc (JSForVar af alb v x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4 (|>) pacc (JSForVarIn af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 + (|>) pacc (JSForLet af alb v x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> "let" |> v |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4 + (|>) pacc (JSForLetIn af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "let" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 + (|>) pacc (JSForLetOf af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "let" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 + (|>) pacc (JSForOf af alb x1s i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> x1s |> i |> x2 |> arb |> ")" |> x3 + (|>) pacc (JSForVarOf af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 (|>) pacc (JSFunction af n alb x2s arb x3 s) = pacc |> af |> "function" |> n |> alb |> "(" |> x2s |> arb |> ")" |> x3 |> s (|>) pacc (JSIf annot alb x1 arb x2s) = pacc |> annot |> "if" |> alb |> "(" |> x1 |> arb |> ")" |> x2s (|>) pacc (JSIfElse annot alb x1 arb x2s ea x3s) = pacc |> annot |> "if" |> alb |> "(" |> x1 |> arb |> ")" |> x2s |> ea |> "else" |> x3s diff --git a/src/Language/JavaScript/Process/Minify.hs b/src/Language/JavaScript/Process/Minify.hs index a2d27f5..c3f9411 100644 --- a/src/Language/JavaScript/Process/Minify.hs +++ b/src/Language/JavaScript/Process/Minify.hs @@ -48,6 +48,11 @@ fixStmt a s (JSFor _ _ el1 _ el2 _ el3 _ st) = JSFor a emptyAnnot (fixEmpty el1) fixStmt a s (JSForIn _ _ e1 op e2 _ st) = JSForIn a emptyAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) fixStmt a s (JSForVar _ _ _ el1 _ el2 _ el3 _ st) = JSForVar a emptyAnnot spaceAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st) fixStmt a s (JSForVarIn _ _ _ e1 op e2 _ st) = JSForVarIn a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) +fixStmt a s (JSForLet _ _ _ el1 _ el2 _ el3 _ st) = JSForLet a emptyAnnot spaceAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st) +fixStmt a s (JSForLetIn _ _ _ e1 op e2 _ st) = JSForLetIn a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) +fixStmt a s (JSForLetOf _ _ _ e1 op e2 _ st) = JSForLetOf a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) +fixStmt a s (JSForOf _ _ e1 op e2 _ st) = JSForOf a emptyAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) +fixStmt a s (JSForVarOf _ _ _ e1 op e2 _ st) = JSForVarOf a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) fixStmt a s (JSFunction _ n _ ps _ blk _) = JSFunction a (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty blk) s fixStmt a s (JSIf _ _ e _ st) = JSIf a emptyAnnot (fixEmpty e) emptyAnnot (fixIfElseBlock emptyAnnot s st) fixStmt a s (JSIfElse _ _ e _ (JSEmptyStatement _) _ sf) = JSIfElse a emptyAnnot (fixEmpty e) emptyAnnot (JSEmptyStatement emptyAnnot) emptyAnnot (fixStmt spaceAnnot s sf) @@ -226,6 +231,7 @@ instance MinifyJS JSBinOp where fix _ (JSBinOpMinus _) = JSBinOpMinus emptyAnnot fix _ (JSBinOpMod _) = JSBinOpMod emptyAnnot fix _ (JSBinOpNeq _) = JSBinOpNeq emptyAnnot + fix a (JSBinOpOf _) = JSBinOpOf a fix _ (JSBinOpOr _) = JSBinOpOr emptyAnnot fix _ (JSBinOpPlus _) = JSBinOpPlus emptyAnnot fix _ (JSBinOpRsh _) = JSBinOpRsh emptyAnnot diff --git a/test/Test/Language/Javascript/Lexer.hs b/test/Test/Language/Javascript/Lexer.hs index 465a8ab..edaca02 100644 --- a/test/Test/Language/Javascript/Lexer.hs +++ b/test/Test/Language/Javascript/Lexer.hs @@ -61,6 +61,14 @@ testLexer = describe "Lexer:" $ do testLex "continue\nx=1" `shouldBe` "[ContinueToken,WsToken,IdentifierToken 'x',SimpleAssignToken,DecimalToken 1]" testLex "return\nx=1" `shouldBe` "[ReturnToken,WsToken,IdentifierToken 'x',SimpleAssignToken,DecimalToken 1]" + it "var/let" $ do + testLex "var\n" `shouldBe` "[VarToken,WsToken]" + testLex "let\n" `shouldBe` "[LetToken,WsToken]" + + it "in/of" $ do + testLex "in\n" `shouldBe` "[InToken,WsToken]" + testLex "of\n" `shouldBe` "[OfToken,WsToken]" + testLex :: String -> String testLex str = diff --git a/test/Test/Language/Javascript/Minify.hs b/test/Test/Language/Javascript/Minify.hs index 3358799..f40ee79 100644 --- a/test/Test/Language/Javascript/Minify.hs +++ b/test/Test/Language/Javascript/Minify.hs @@ -180,7 +180,11 @@ testMinifyStmt = describe "Minify statements:" $ do minifyStmt " for (var x ; y ; z) { } " `shouldBe` "for(var x;y;z){}" minifyStmt " for ( x in 5 ) foo (x) ;" `shouldBe` "for(x in 5)foo(x)" minifyStmt " for ( var x in 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(var x in 5){foo(x++);y++}" - + minifyStmt " for (let x ; y ; z) { } " `shouldBe` "for(let x;y;z){}" + minifyStmt " for ( let x in 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(let x in 5){foo(x++);y++}" + minifyStmt " for ( let x of 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(let x of 5){foo(x++);y++}" + minifyStmt " for ( x of 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(x of 5){foo(x++);y++}" + minifyStmt " for ( var x of 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(var x of 5){foo(x++);y++}" it "labelled" $ do minifyStmt " start : while ( true ) { if ( i ++ < 3 ) continue start ; break ; } ; " `shouldBe` "start:while(true){if(i++<3)continue start;break}" minifyStmt " { k ++ ; start : while ( true ) { if ( i ++ < 3 ) continue start ; break ; } ; } ; " `shouldBe` "{k++;start:while(true){if(i++<3)continue start;break}}" diff --git a/test/Test/Language/Javascript/RoundTrip.hs b/test/Test/Language/Javascript/RoundTrip.hs index 27c2026..e71ff60 100644 --- a/test/Test/Language/Javascript/RoundTrip.hs +++ b/test/Test/Language/Javascript/RoundTrip.hs @@ -59,7 +59,7 @@ testRoundTrip = describe "Roundtrip:" $ do testRT "/*a*/x/*b*/>/*c*/y" testRT "/*a*/x/*b*/<=/*c*/y" testRT "/*a*/x/*b*/>=/*c*/y" - testRT "/*a*/x /*b*/instance of /*c*/y" + testRT "/*a*/x /*b*/instanceof /*c*/y" 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" @@ -83,6 +83,11 @@ testRoundTrip = describe "Roundtrip:" $ do testRT "for(var x;y;z){}" testRT "for(x in 5){}" testRT "for(var x in 5){}" + testRT "for(let x;y;z){}" + testRT "for(let x in 5){}" + testRT "for(let x of 5){}" + testRT "for(x of 5){}" + testRT "for(var x of 5){}" testRT "var x=1;" testRT "const x=1,y=2;" testRT "continue;" diff --git a/test/Test/Language/Javascript/StatementParser.hs b/test/Test/Language/Javascript/StatementParser.hs index 8f3a7fa..cd54550 100644 --- a/test/Test/Language/Javascript/StatementParser.hs +++ b/test/Test/Language/Javascript/StatementParser.hs @@ -51,6 +51,12 @@ testStatementParser = describe "Parse statements:" $ do testStmt "for(var x in 5){}" `shouldBe` "Right (JSAstStatement (JSForVarIn (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" + testStmt "for(let x;y;z){}" `shouldBe` "Right (JSAstStatement (JSForLet (JSVarInitExpression (JSIdentifier 'x') ) (JSIdentifier 'y') (JSIdentifier 'z') (JSStatementBlock [])))" + testStmt "for(let x in 5){}" `shouldBe` "Right (JSAstStatement (JSForLetIn (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" + testStmt "for(let x of 5){}" `shouldBe` "Right (JSAstStatement (JSForLetOf (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" + testStmt "for(x of 5){}" `shouldBe` "Right (JSAstStatement (JSForOf JSIdentifier 'x' (JSDecimal '5') (JSStatementBlock [])))" + testStmt "for(var x of 5){}" `shouldBe` "Right (JSAstStatement (JSForVarOf (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" + it "variable/constant/let declaration" $ do testStmt "var x=1;" `shouldBe` "Right (JSAstStatement (JSVariable (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1'])))" testStmt "const x=1,y=2;" `shouldBe` "Right (JSAstStatement (JSConstant (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1'],JSVarInitExpression (JSIdentifier 'y') [JSDecimal '2'])))"