diff --git a/src/Language/JavaScript/Parser/AST.hs b/src/Language/JavaScript/Parser/AST.hs index 53e6b31..897179d 100644 --- a/src/Language/JavaScript/Parser/AST.hs +++ b/src/Language/JavaScript/Parser/AST.hs @@ -74,6 +74,7 @@ data JSStatement | JSVariable !JSAnnot !(JSCommaList JSExpression) !JSSemi -- ^var|const, decl, autosemi | JSWhile !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement -- ^while,lb,expr,rb,stmt | JSWith !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement !JSSemi -- ^with,lb,expr,rb,stmt list + | JSExport !JSAnnot !(Maybe JSAnnot) !JSStatement !JSSemi -- ^export deriving (Data, Eq, Show, Typeable) data JSExpression @@ -271,6 +272,10 @@ instance ShowStripped JSStatement where ss (JSReturn _ (Just me) s) = "JSReturn " ++ ss me ++ " " ++ ss s ss (JSReturn _ Nothing s) = "JSReturn " ++ ss s ss (JSSwitch _ _lp x _rp _lb x2 _rb _) = "JSSwitch (" ++ ss x ++ ") " ++ ss x2 + ss (JSExport _ df x1 _) = "JSExport " ++ exportDefault df ++ "(" ++ ss x1 ++ ")" + where + exportDefault (Just _) = "default " + exportDefault Nothing = "" ss (JSThrow _ x _) = "JSThrow (" ++ ss x ++ ")" ss (JSTry _ xt1 xtc xtf) = "JSTry (" ++ ss xt1 ++ "," ++ ss xtc ++ "," ++ ss xtf ++ ")" ss (JSVariable _ xs _as) = "JSVariable " ++ ss xs diff --git a/src/Language/JavaScript/Parser/Lexer.x b/src/Language/JavaScript/Parser/Lexer.x index 723c21b..0f81f29 100644 --- a/src/Language/JavaScript/Parser/Lexer.x +++ b/src/Language/JavaScript/Parser/Lexer.x @@ -566,6 +566,7 @@ keywordNames = , ( "export", FutureToken ) , ( "extends", FutureToken ) + , ( "export", ExportToken ) , ( "import", FutureToken ) , ( "super", FutureToken ) diff --git a/src/Language/JavaScript/Parser/Token.hs b/src/Language/JavaScript/Parser/Token.hs index b2f7c4d..9b847b5 100644 --- a/src/Language/JavaScript/Parser/Token.hs +++ b/src/Language/JavaScript/Parser/Token.hs @@ -88,6 +88,7 @@ data Token | VoidToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | WhileToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } | WithToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } + | ExportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } -- Future reserved words | FutureToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } -- Needed, not sure what they are though. diff --git a/src/Language/JavaScript/Pretty/Printer.hs b/src/Language/JavaScript/Pretty/Printer.hs index fd9dc89..eeb5cef 100644 --- a/src/Language/JavaScript/Pretty/Printer.hs +++ b/src/Language/JavaScript/Pretty/Printer.hs @@ -102,6 +102,10 @@ instance RenderJS JSAnnot where (|>) pacc JSNoAnnot = pacc (|>) pacc JSAnnotSpace = pacc |> " " +instance RenderJS (Maybe JSAnnot) where + (|>) pacc (Just e) = pacc |> e + (|>) pacc Nothing = pacc + instance RenderJS String where (|>) (PosAccum (r,c) bb) s = PosAccum (r',c') (bb <> str s) where @@ -233,6 +237,7 @@ instance RenderJS JSStatement where (|>) pacc (JSMethodCall e lp a rp s) = pacc |> e |> lp |> "(" |> a |> rp |> ")" |> s (|>) pacc (JSReturn annot me s) = pacc |> annot |> "return" |> me |> s (|>) pacc (JSSwitch annot alp x arp alb x2 arb s) = pacc |> annot |> "switch" |> alp |> "(" |> x |> arp |> ")" |> alb |> "{" |> x2 |> arb |> "}" |> s + (|>) pacc (JSExport annot df x1 s) = pacc |> annot |> "export" |> df |> "{" |> x1 |> "}" |> s (|>) pacc (JSThrow annot x s) = pacc |> annot |> "throw" |> x |> s (|>) pacc (JSTry annot tb tcs tf) = pacc |> annot |> "try" |> tb |> tcs |> tf (|>) pacc (JSVariable annot xs s) = pacc |> annot |> "var" |> xs |> s @@ -287,4 +292,3 @@ instance RenderJS JSVarInitializer where (|>) pacc JSVarInitNone = pacc -- EOF - diff --git a/src/Language/JavaScript/Process/Minify.hs b/src/Language/JavaScript/Process/Minify.hs index f4babe3..98267cc 100644 --- a/src/Language/JavaScript/Process/Minify.hs +++ b/src/Language/JavaScript/Process/Minify.hs @@ -60,6 +60,7 @@ fixStmt a s (JSMethodCall e _ args _ _) = JSMethodCall (fix a e) emptyAnnot (fix fixStmt a s (JSReturn _ me _) = JSReturn a (fixSpace me) s fixStmt a s (JSSwitch _ _ e _ _ sps _ _) = JSSwitch a emptyAnnot (fixEmpty e) emptyAnnot emptyAnnot (fixSwitchParts sps) emptyAnnot s fixStmt a s (JSThrow _ e _) = JSThrow a (fixSpace e) s +fixStmt a s (JSExport _ df x1 _) = JSExport a (fixSpace df) (fixEmpty x1) s -- unsure what I'm doing here fixStmt a _ (JSTry _ b tc tf) = JSTry a (fixEmpty b) (map fixEmpty tc) (fixEmpty tf) fixStmt a s (JSVariable _ ss _) = JSVariable a (fixVarList ss) s fixStmt a s (JSWhile _ _ e _ st) = JSWhile a emptyAnnot (fixEmpty e) emptyAnnot (fixStmt a s st) diff --git a/test/Test/Language/Javascript/StatementParser.hs b/test/Test/Language/Javascript/StatementParser.hs index e27addf..8d39967 100644 --- a/test/Test/Language/Javascript/StatementParser.hs +++ b/test/Test/Language/Javascript/StatementParser.hs @@ -26,6 +26,27 @@ testStatementParser = describe "Parse statements:" $ do it "if" $ testStmt "if (1) {}" `shouldBe` "Right (JSAstStatement (JSIf (JSDecimal '1') (JSStatementBlock [])))" + it "export" $ do + testStmt "export a;" `shouldBe` "Right (JSAstStatement (JSExport (JSIdentifier 'a',JSSemicolon)))" + testStmt "export var a = 1;" `shouldBe` "Right (JSAstStatement (JSExport (JSVariable (JSVarInitExpression (JSIdentifier 'a') [JSDecimal '1']))))" + testStmt "export function () {};" `shouldBe` "Right (JSAstStatement (JSExport (JSFunctionExpression '' () (JSBlock [])),JSSemicolon)))" + testStmt "export {};" `shouldBe` "Right (JSAstStatement (JSExport (JSStatementBlock [])))" + testStmt "export default function () {};" `shouldBe` "Right (JSAstStatement (JSExport Default (JSFunctionExpression '' () (JSBlock [])),JSSemicolon)))" + testStmt "export default var a = 1;" `shouldBe` "Right (JSAstStatement (JSExport Default (JSVariable (JSVarInitExpression (JSIdentifier 'a') [JSDecimal '1']))))" + -- Unsure about handling all these cases taken from the specs + -- export { variable1 as name1, variable2 as name2, …, nameN }; + -- export let name1, name2, …, nameN; // also var, const + -- export let name1 = …, name2 = …, …, nameN; // also var, const + -- export class ClassName {...} + -- export default expression; + -- export default function name1(…) { … } // also class, function* + -- export { name1 as default, … }; + + -- export * from …; + -- export { name1, name2, …, nameN } from …; + -- export { import1 as name1, import2 as name2, …, nameN } from …; + -- export { default } from …; + it "if/else" $ do testStmt "if (1) {} else {}" `shouldBe` "Right (JSAstStatement (JSIfElse (JSDecimal '1') (JSStatementBlock []) (JSStatementBlock [])))" testStmt "if (1) x=1; else {}" `shouldBe` "Right (JSAstStatement (JSIfElse (JSDecimal '1') (JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon) (JSStatementBlock [])))" @@ -101,4 +122,3 @@ testStatementParser = describe "Parse statements:" $ do testStmt :: String -> String testStmt str = showStrippedMaybe (parseUsing parseStatement str "src") -