diff --git a/.gitignore b/.gitignore
index f9d1730..a39cb33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,6 @@
 /unicode/uc-nl.htm
 /unicode/uc-pc.htm
 cabal.sandbox.config
+
+# stack
+/.stack-work/
diff --git a/language-javascript.cabal b/language-javascript.cabal
index b1900e5..6e0e06f 100644
--- a/language-javascript.cabal
+++ b/language-javascript.cabal
@@ -9,7 +9,9 @@ License:             BSD3
 License-file:        LICENSE
 Author:              Alan Zimmerman
 Maintainer:          Erik de Castro Lopo <erikd@mega-nerd.com>
-Copyright:           (c) 2010-2015 Alan Zimmerman, 2015 Erik de Castro Lopo
+Copyright:           (c) 2010-2015 Alan Zimmerman
+                     (c) 2015-2018 Erik de Castro Lopo
+                     (c) 2018      Daniel Gasienica
 Category:            Language
 Build-type:          Simple
 homepage:            https://github.com/erikd/language-javascript
@@ -81,6 +83,7 @@ Test-Suite testsuite
                     Test.Language.Javascript.Lexer
                     Test.Language.Javascript.LiteralParser
                     Test.Language.Javascript.Minify
+                    Test.Language.Javascript.ModuleParser
                     Test.Language.Javascript.ProgramParser
                     Test.Language.Javascript.RoundTrip
                     Test.Language.Javascript.StatementParser
diff --git a/src/Language/JavaScript/Parser.hs b/src/Language/JavaScript/Parser.hs
index a813bc9..750c0ed 100644
--- a/src/Language/JavaScript/Parser.hs
+++ b/src/Language/JavaScript/Parser.hs
@@ -1,7 +1,9 @@
 module Language.JavaScript.Parser
        (
          PA.parse
+       , PA.parseModule
        , PA.readJs
+       , PA.readJsModule
        , PA.parseFile
        , PA.parseFileUtf8
        , PA.showStripped
@@ -40,5 +42,3 @@ import Language.JavaScript.Parser.SrcLocation
 import Language.JavaScript.Pretty.Printer
 
 -- EOF
-
-
diff --git a/src/Language/JavaScript/Parser/AST.hs b/src/Language/JavaScript/Parser/AST.hs
index 53e6b31..9e157db 100644
--- a/src/Language/JavaScript/Parser/AST.hs
+++ b/src/Language/JavaScript/Parser/AST.hs
@@ -23,6 +23,11 @@ module Language.JavaScript.Parser.AST
     , JSCommaList (..)
     , JSCommaTrailingList (..)
 
+    -- Modules
+    , JSModuleItem (..)
+    , JSExportDeclaration (..)
+    , JSExportLocalSpecifier (..)
+
     , binOpEq
     , showStripped
     ) where
@@ -42,12 +47,34 @@ data JSAnnot
 
 
 data JSAST
-    = JSAstProgram ![JSStatement] !JSAnnot -- ^source elements, tailing whitespace
+    = JSAstProgram ![JSStatement] !JSAnnot -- ^source elements, trailing whitespace
+    | JSAstModule ![JSModuleItem] !JSAnnot
     | JSAstStatement !JSStatement !JSAnnot
     | JSAstExpression !JSExpression !JSAnnot
     | JSAstLiteral !JSExpression !JSAnnot
     deriving (Data, Eq, Show, Typeable)
 
+-- Shift AST
+-- https://github.com/shapesecurity/shift-spec/blob/83498b92c436180cc0e2115b225a68c08f43c53e/spec.idl#L229-L234
+data JSModuleItem
+    -- = JSImportDeclaration
+    = JSModuleExportDeclaration !JSAnnot !JSExportDeclaration -- ^export,decl
+    | JSModuleStatementListItem !JSStatement
+    deriving (Data, Eq, Show, Typeable)
+
+data JSExportDeclaration
+    -- = JSExportAllFrom
+    -- | JSExportFrom
+    = JSExportLocals !JSAnnot !(JSCommaList JSExportLocalSpecifier) !JSAnnot !JSSemi -- ^lb, specifiers, rb, autosemi
+    | JSExport !JSStatement !JSSemi -- ^body, autosemi
+    -- | JSExportDefault
+    deriving (Data, Eq, Show, Typeable)
+
+data JSExportLocalSpecifier
+    = JSExportLocalSpecifier !JSIdent -- ^ident
+    | JSExportLocalSpecifierAs !JSIdent !JSBinOp !JSIdent -- ^ident1, as, ident2
+    deriving (Data, Eq, Show, Typeable)
+
 data JSStatement
     = JSStatementBlock !JSAnnot ![JSStatement] !JSAnnot !JSSemi     -- ^lbrace, stmts, rbrace, autosemi
     | JSBreak !JSAnnot !JSIdent !JSSemi        -- ^break,optional identifier, autosemi
@@ -71,7 +98,7 @@ data JSStatement
     | JSSwitch !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSAnnot ![JSSwitchParts] !JSAnnot !JSSemi -- ^switch,lb,expr,rb,caseblock,autosemi
     | JSThrow !JSAnnot !JSExpression !JSSemi -- ^throw val autosemi
     | JSTry !JSAnnot !JSBlock ![JSTryCatch] !JSTryFinally -- ^try,block,catches,finally
-    | JSVariable !JSAnnot !(JSCommaList JSExpression) !JSSemi -- ^var|const, decl, autosemi
+    | JSVariable !JSAnnot !(JSCommaList JSExpression) !JSSemi -- ^var, 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
     deriving (Data, Eq, Show, Typeable)
@@ -112,6 +139,7 @@ data JSExpression
 
 data JSBinOp
     = JSBinOpAnd !JSAnnot
+    | JSBinOpAs !JSAnnot
     | JSBinOpBitAnd !JSAnnot
     | JSBinOpBitOr !JSAnnot
     | JSBinOpBitXor !JSAnnot
@@ -233,11 +261,12 @@ data JSCommaTrailingList a
     deriving (Data, Eq, Show, Typeable)
 
 -- -----------------------------------------------------------------------------
--- | Show the AST elements stipped of their JSAnnot data.
+-- | Show the AST elements stripped of their JSAnnot data.
 
 -- Strip out the location info
 showStripped :: JSAST -> String
 showStripped (JSAstProgram xs _) = "JSAstProgram " ++ ss xs
+showStripped (JSAstModule xs _) = "JSAstModule " ++ ss xs
 showStripped (JSAstStatement s _) = "JSAstStatement (" ++ ss s ++ ")"
 showStripped (JSAstExpression e _) = "JSAstExpression (" ++ ss e ++ ")"
 showStripped (JSAstLiteral s _)  = "JSAstLiteral (" ++ ss s ++ ")"
@@ -246,7 +275,6 @@ showStripped (JSAstLiteral s _)  = "JSAstLiteral (" ++ ss s ++ ")"
 class ShowStripped a where
     ss :: a -> String
 
-
 instance ShowStripped JSStatement where
     ss (JSStatementBlock _ xs _ _) = "JSStatementBlock " ++ ss xs
     ss (JSBreak _ JSIdentNone s) = "JSBreak" ++ commaIf (ss s)
@@ -308,6 +336,18 @@ instance ShowStripped JSExpression where
     ss (JSVarInitExpression x1 x2) = "JSVarInitExpression (" ++ ss x1 ++ ") " ++ ss x2
     ss (JSSpreadExpression _ x1) = "JSSpreadExpression (" ++ ss x1 ++ ")"
 
+instance ShowStripped JSModuleItem where
+    ss (JSModuleExportDeclaration _ x1) = "JSModuleExportDeclaration (" ++ ss x1 ++ ")"
+    ss (JSModuleStatementListItem x1) = "JSModuleStatementListItem (" ++ ss x1 ++ ")"
+
+instance ShowStripped JSExportDeclaration where
+    ss (JSExportLocals _ xs _ _) = "JSExportLocals (" ++ ss xs ++ ")"
+    ss (JSExport x1 _) = "JSExport (" ++ ss x1 ++ ")"
+
+instance ShowStripped JSExportLocalSpecifier where
+    ss (JSExportLocalSpecifier x1) = "JSExportLocalSpecifier (" ++ ss x1 ++ ")"
+    ss (JSExportLocalSpecifierAs x1 _ x2) = "JSExportLocalSpecifierAs (" ++ ss x1 ++ "," ++ ss x2 ++ ")"
+
 instance ShowStripped JSTryCatch where
     ss (JSCatch _ _lb x1 _rb x3) = "JSCatch (" ++ ss x1 ++ "," ++ ss x3 ++ ")"
     ss (JSCatchIf _ _lb x1 _ ex _rb x3) = "JSCatch (" ++ ss x1 ++ ") if " ++ ss ex ++ " (" ++ ss x3 ++ ")"
@@ -342,6 +382,7 @@ instance ShowStripped JSSwitchParts where
 
 instance ShowStripped JSBinOp where
     ss (JSBinOpAnd _) = "'&&'"
+    ss (JSBinOpAs _) = "'as'"
     ss (JSBinOpBitAnd _) = "'&'"
     ss (JSBinOpBitOr _) = "'|'"
     ss (JSBinOpBitXor _) = "'^'"
@@ -437,6 +478,7 @@ commaIf xs = ',' : xs
 
 deAnnot :: JSBinOp -> JSBinOp
 deAnnot (JSBinOpAnd _) = JSBinOpAnd JSNoAnnot
+deAnnot (JSBinOpAs _) = JSBinOpAs JSNoAnnot
 deAnnot (JSBinOpBitAnd _) = JSBinOpBitAnd JSNoAnnot
 deAnnot (JSBinOpBitOr _) = JSBinOpBitOr JSNoAnnot
 deAnnot (JSBinOpBitXor _) = JSBinOpBitXor JSNoAnnot
diff --git a/src/Language/JavaScript/Parser/Grammar7.y b/src/Language/JavaScript/Parser/Grammar7.y
index 1d4b2b9..f2e9406 100644
--- a/src/Language/JavaScript/Parser/Grammar7.y
+++ b/src/Language/JavaScript/Parser/Grammar7.y
@@ -1,11 +1,12 @@
 {
 {-# LANGUAGE BangPatterns #-}
 module Language.JavaScript.Parser.Grammar7
-	( parseProgram
-	, parseStatement
-	, parseExpression
-	, parseLiteral
-	) where
+    ( parseProgram
+    , parseModule
+    , parseStatement
+    , parseExpression
+    , parseLiteral
+    ) where
 
 import Data.Char
 import Language.JavaScript.Parser.Lexer
@@ -18,8 +19,9 @@ import qualified Language.JavaScript.Parser.AST as AST
 
 -- The name of the generated function to be exported from the module
 %name parseProgram           Program
+%name parseModule            Module
 %name parseLiteral           LiteralMain
-%name parseExpression		 ExpressionMain
+%name parseExpression        ExpressionMain
 %name parseStatement         StatementMain
 
 %tokentype { Token }
@@ -81,6 +83,7 @@ import qualified Language.JavaScript.Parser.AST as AST
      '('    { LeftParenToken {} }
      ')'    { RightParenToken {} }
 
+     'as'         { AsToken {} }
      'autosemi'   { AutoSemiToken {} }
      'break'      { BreakToken {} }
      'case'       { CaseToken {} }
@@ -93,6 +96,7 @@ import qualified Language.JavaScript.Parser.AST as AST
      'do'         { DoToken {} }
      'else'       { ElseToken {} }
      'enum'       { EnumToken {} }
+     'export'     { ExportToken {} }
      'false'      { FalseToken {} }
      'finally'    { FinallyToken {} }
      'for'        { ForToken {} }
@@ -244,6 +248,9 @@ Ge : '>=' { AST.JSBinOpGe (mkJSAnnot $1) }
 Gt :: { AST.JSBinOp }
 Gt : '>' { AST.JSBinOpGt (mkJSAnnot $1) }
 
+As :: { AST.JSBinOp }
+As : 'as' { AST.JSBinOpAs (mkJSAnnot $1) }
+
 In :: { AST.JSBinOp }
 In : 'in' { AST.JSBinOpIn (mkJSAnnot $1) }
 
@@ -305,6 +312,9 @@ Let : 'let' { mkJSAnnot $1 }
 Const :: { AST.JSAnnot }
 Const : 'const' { mkJSAnnot $1 }
 
+Export :: { AST.JSAnnot }
+Export : 'export' { mkJSAnnot $1 }
+
 If :: { AST.JSAnnot }
 If : 'if' { mkJSAnnot $1 }
 
@@ -426,6 +436,7 @@ Identifier : 'ident' { AST.JSIdentifier (mkJSAnnot $1) (tokenLiteral $1) }
 -- TODO: make this include any reserved word too, including future ones
 IdentifierName :: { AST.JSExpression }
 IdentifierName : Identifier {$1}
+             | 'as'         { AST.JSIdentifier (mkJSAnnot $1) "as" }
              | 'break'      { AST.JSIdentifier (mkJSAnnot $1) "break" }
              | 'case'       { AST.JSIdentifier (mkJSAnnot $1) "case" }
              | 'catch'      { AST.JSIdentifier (mkJSAnnot $1) "catch" }
@@ -437,6 +448,7 @@ IdentifierName : Identifier {$1}
              | 'do'         { AST.JSIdentifier (mkJSAnnot $1) "do" }
              | 'else'       { AST.JSIdentifier (mkJSAnnot $1) "else" }
              | 'enum'       { AST.JSIdentifier (mkJSAnnot $1) "enum" }
+             | 'export'     { AST.JSIdentifier (mkJSAnnot $1) "export" }
              | 'false'      { AST.JSIdentifier (mkJSAnnot $1) "false" }
              | 'finally'    { AST.JSIdentifier (mkJSAnnot $1) "finally" }
              | 'for'        { AST.JSIdentifier (mkJSAnnot $1) "for" }
@@ -498,9 +510,9 @@ Elision : Comma             { [AST.JSArrayComma $1]     {- 'Elision1' -} }
 --        { PropertyNameAndValueList }
 --        { PropertyNameAndValueList , }
 ObjectLiteral :: { AST.JSExpression }
-ObjectLiteral : LBrace RBrace                                { AST.JSObjectLiteral $1 (AST.JSCTLNone AST.JSLNil) $2     {- 'ObjectLiteal1' -} }
-              | LBrace PropertyNameandValueList RBrace       { AST.JSObjectLiteral $1 (AST.JSCTLNone $2) $3             {- 'ObjectLiteal2' -} }
-              | LBrace PropertyNameandValueList Comma RBrace { AST.JSObjectLiteral $1 (AST.JSCTLComma $2 $3) $4         {- 'ObjectLiteal3' -} }
+ObjectLiteral : LBrace RBrace                                { AST.JSObjectLiteral $1 (AST.JSCTLNone AST.JSLNil) $2     {- 'ObjectLiteral1' -} }
+              | LBrace PropertyNameandValueList RBrace       { AST.JSObjectLiteral $1 (AST.JSCTLNone $2) $3             {- 'ObjectLiteral2' -} }
+              | LBrace PropertyNameandValueList Comma RBrace { AST.JSObjectLiteral $1 (AST.JSCTLComma $2 $3) $4         {- 'ObjectLiteral3' -} }
 
 -- <Property Name and Value List> ::= <Property Name> ':' <Assignment Expression>
 --                                  | <Property Name and Value List> ',' <Property Name> ':' <Assignment Expression>
@@ -1108,6 +1120,11 @@ StatementOrBlock :: { AST.JSStatement }
 StatementOrBlock : Block MaybeSemi		{ blockToStatement $1 $2 }
                  | Expression MaybeSemi { expressionToStatement $1 $2 }
 
+-- StatementListItem :
+--        Statement
+--        Declaration
+StatementListItem :: { AST.JSStatement }
+StatementListItem : Statement           { $1 }
 
 NamedFunctionExpression :: { AST.JSExpression }
 NamedFunctionExpression : Function Identifier LParen RParen FunctionBody
@@ -1145,6 +1162,75 @@ Program :: { AST.JSAST }
 Program : StatementList Eof     	{ AST.JSAstProgram $1 $2   	{- 'Program1' -} }
         | Eof                   	{ AST.JSAstProgram [] $1 	{- 'Program2' -} }
 
+-- Module :                                                                   See 15.2
+--        ModuleBody[opt]
+--
+-- ModuleBody :
+--        ModuleItemList
+Module :: { AST.JSAST }
+Module : ModuleItemList Eof     	{ AST.JSAstModule $1 $2   	{- 'Module1' -} }
+        | Eof                   	{ AST.JSAstModule [] $1 	{- 'Module2' -} }
+
+-- ModuleItemList :
+--         ModuleItem
+--         ModuleItemList ModuleItem
+ModuleItemList :: { [AST.JSModuleItem] }
+ModuleItemList : ModuleItem                  { [$1]         {- 'ModuleItemList1' -} }
+               | ModuleItemList ModuleItem   { ($1++[$2])   {- 'ModuleItemList2' -} }
+
+-- ModuleItem :
+--        ImportDeclaration
+--        ExportDeclaration
+--        StatementListItem
+ModuleItem :: { AST.JSModuleItem }
+ModuleItem : Export ExportDeclaration
+                    { AST.JSModuleExportDeclaration $1 $2   {- 'ModuleItem1' -} }
+           | StatementListItem
+                    { AST.JSModuleStatementListItem $1      {- 'ModuleItem2' -} }
+
+-- ExportDeclaration :                                                        See 15.2.3
+-- [ ]    export * FromClause ;
+-- [ ]    export ExportClause FromClause ;
+-- [x]    export ExportClause ;
+-- [x]    export VariableStatement
+-- [ ]    export Declaration
+-- [ ]    export default HoistableDeclaration[Default]
+-- [ ]    export default ClassDeclaration[Default]
+-- [ ]    export default [lookahead ∉ { function, class }] AssignmentExpression[In] ;
+ExportDeclaration :: { AST.JSExportDeclaration }
+ExportDeclaration : ExportClause AutoSemi
+                         { $1                    {- 'ExportDeclaration1' -} }
+                  | VariableStatement AutoSemi
+                         { AST.JSExport $1 $2    {- 'ExportDeclaration2' -} }
+
+-- ExportClause :
+--           { }
+--           { ExportsList }
+--           { ExportsList , }
+ExportClause :: { AST.JSExportDeclaration }
+ExportClause : LBrace RBrace AutoSemi
+                    { AST.JSExportLocals $1 AST.JSLNil $2 $3     {- 'ExportClause1' -} }
+             | LBrace ExportsList RBrace AutoSemi
+                    { AST.JSExportLocals $1 $2 $3 $4             {- 'ExportClause2' -} }
+
+-- ExportsList :
+--           ExportSpecifier
+--           ExportsList , ExportSpecifier
+ExportsList :: { AST.JSCommaList AST.JSExportLocalSpecifier }
+ExportsList : ExportSpecifier
+                    { AST.JSLOne $1          {- 'ExportsList1' -} }
+            | ExportsList Comma ExportSpecifier
+                    { AST.JSLCons $1 $2 $3   {- 'ExportsList2' -} }
+
+-- ExportSpecifier :
+--           IdentifierName
+--           IdentifierName as IdentifierName
+ExportSpecifier :: { AST.JSExportLocalSpecifier }
+ExportSpecifier : IdentifierName
+                    { AST.JSExportLocalSpecifier (identName $1)                      {- 'ExportSpecifier1' -} }
+                | IdentifierName As IdentifierName
+                    { AST.JSExportLocalSpecifierAs (identName $1) $2 (identName $3)  {- 'ExportSpecifier2' -} }
+
 -- For debugging/other entry points
 LiteralMain :: { AST.JSAST }
 LiteralMain : Literal Eof			{ AST.JSAstLiteral $1 $2	{- 'LiteralMain' -} }
@@ -1155,7 +1241,6 @@ ExpressionMain : Expression Eof					{ AST.JSAstExpression $1 $2 {- 'ExpressionMa
 StatementMain :: { AST.JSAST }
 StatementMain : StatementNoEmpty Eof	{ AST.JSAstStatement $1 $2   	{- 'StatementMain' -} }
 
-
 {
 
 -- Need this type while build the AST, but is not actually part of the AST.
diff --git a/src/Language/JavaScript/Parser/Lexer.x b/src/Language/JavaScript/Parser/Lexer.x
index 723c21b..863fabd 100644
--- a/src/Language/JavaScript/Parser/Lexer.x
+++ b/src/Language/JavaScript/Parser/Lexer.x
@@ -503,7 +503,8 @@ keywords = Map.fromList keywordNames
 
 keywordNames :: [(String, TokenPosn -> String -> [CommentAnnotation] -> Token)]
 keywordNames =
-    [ ( "break", BreakToken )
+    [ ( "as", AsToken )
+    , ( "break", BreakToken )
     , ( "case", CaseToken )
     , ( "catch", CatchToken )
 
@@ -517,6 +518,7 @@ keywordNames =
     , ( "else", ElseToken )
 
     , ( "enum", EnumToken )  -- not a keyword,  nominally a future reserved word, but actually in use
+    , ( "export", ExportToken )
 
     , ( "false", FalseToken ) -- boolean literal
 
@@ -563,7 +565,6 @@ keywordNames =
     -- ( "code",    FutureToken ) **** not any more
     -- ( "const",   FutureToken ) **** an actual token, used in productions
     -- enum                    **** an actual token, used in productions
-    , ( "export",   FutureToken )
     , ( "extends",  FutureToken )
 
     , ( "import",   FutureToken )
diff --git a/src/Language/JavaScript/Parser/Parser.hs b/src/Language/JavaScript/Parser/Parser.hs
index d36b5bc..10757a3 100644
--- a/src/Language/JavaScript/Parser/Parser.hs
+++ b/src/Language/JavaScript/Parser/Parser.hs
@@ -1,7 +1,9 @@
 module Language.JavaScript.Parser.Parser (
    -- * Parsing
      parse
+   , parseModule
    , readJs
+   , readJsModule
    -- , readJsKeepComments
    , parseFile
    , parseFileUtf8
@@ -12,28 +14,44 @@ module Language.JavaScript.Parser.Parser (
    , showStrippedMaybe
    ) where
 
-import Language.JavaScript.Parser.Grammar7
+import qualified Language.JavaScript.Parser.Grammar7 as P
 import Language.JavaScript.Parser.Lexer
 import qualified Language.JavaScript.Parser.AST as AST
 import System.IO
 
--- | Parse one compound statement, or a sequence of simple statements.
+-- | Parse JavaScript Program (Script)
+-- Parse one compound statement, or a sequence of simple statements.
 -- Generally used for interactive input, such as from the command line of an interpreter.
 -- Return comments in addition to the parsed statements.
 parse :: String -- ^ The input stream (Javascript source code).
       -> String -- ^ The name of the Javascript source (filename or input device).
-      -> Either String  AST.JSAST
+      -> Either String AST.JSAST
          -- ^ An error or maybe the abstract syntax tree (AST) of zero
          -- or more Javascript statements, plus comments.
-parse input _srcName = runAlex input parseProgram
+parse = parseUsing P.parseProgram
 
+-- | Parse JavaScript module
+parseModule :: String -- ^ The input stream (JavaScript source code).
+            -> String -- ^ The name of the JavaScript source (filename or input device).
+            -> Either String AST.JSAST
+            -- ^ An error or maybe the abstract syntax tree (AST) of zero
+            -- or more JavaScript statements, plus comments.
+parseModule = parseUsing P.parseModule
 
-readJs :: String -> AST.JSAST
-readJs input =
-  case parse input "src" of
+readJsWith :: (String -> String -> Either String AST.JSAST)
+           -> String
+           -> AST.JSAST
+readJsWith f input =
+  case f input "src" of
     Left msg -> error (show msg)
     Right p -> p
 
+readJs :: String -> AST.JSAST
+readJs = readJsWith parse
+
+readJsModule :: String -> AST.JSAST
+readJsModule = readJsWith parseModule
+
 -- | Parse the given file.
 -- For UTF-8 support, make sure your locale is set such that
 -- "System.IO.localeEncoding" returns "utf8"
@@ -74,4 +92,3 @@ parseUsing ::
          -- or more Javascript statements, plus comments.
 
 parseUsing p input _srcName = runAlex input p
-
diff --git a/src/Language/JavaScript/Parser/Token.hs b/src/Language/JavaScript/Parser/Token.hs
index b2f7c4d..4a5a97c 100644
--- a/src/Language/JavaScript/Parser/Token.hs
+++ b/src/Language/JavaScript/Parser/Token.hs
@@ -56,6 +56,7 @@ data Token
     -- ^ Literal: Regular Expression
 
     -- Keywords
+    | AsToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | BreakToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | CaseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | CatchToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
@@ -88,6 +89,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..3ccc30c 100644
--- a/src/Language/JavaScript/Pretty/Printer.hs
+++ b/src/Language/JavaScript/Pretty/Printer.hs
@@ -55,6 +55,7 @@ class RenderJS a where
 
 instance RenderJS JSAST where
     (|>) pacc (JSAstProgram xs a)   = pacc |> xs |> a
+    (|>) pacc (JSAstModule xs a)    = pacc |> xs |> a
     (|>) pacc (JSAstStatement s a)  = pacc |> s |> a
     (|>) pacc (JSAstExpression e a) = pacc |> e |> a
     (|>) pacc (JSAstLiteral x a)    = pacc |> x |> a
@@ -138,6 +139,7 @@ instance RenderJS [JSExpression] where
 
 instance RenderJS JSBinOp where
     (|>) pacc (JSBinOpAnd        annot)  = pacc |> annot |> "&&"
+    (|>) pacc (JSBinOpAs         annot)  = pacc |> annot |> "as"
     (|>) pacc (JSBinOpBitAnd     annot)  = pacc |> annot |> "&"
     (|>) pacc (JSBinOpBitOr      annot)  = pacc |> annot |> "|"
     (|>) pacc (JSBinOpBitXor     annot)  = pacc |> annot |> "^"
@@ -242,6 +244,13 @@ instance RenderJS JSStatement where
 instance RenderJS [JSStatement] where
     (|>) = foldl' (|>)
 
+instance RenderJS [JSModuleItem] where
+    (|>) = foldl' (|>)
+
+instance RenderJS JSModuleItem where
+    (|>) pacc (JSModuleExportDeclaration annot decl) = pacc |> annot |> "export" |> decl
+    (|>) pacc (JSModuleStatementListItem s) = pacc |> s
+
 instance RenderJS JSBlock where
     (|>) pacc (JSBlock alb ss arb) = pacc |> alb |> "{" |> ss |> arb |> "}"
 
@@ -265,6 +274,15 @@ instance RenderJS JSArrayElement where
 instance RenderJS [JSArrayElement] where
     (|>) = foldl' (|>)
 
+instance RenderJS JSExportDeclaration where
+    (|>) pacc (JSExport x1 s) = pacc |> " " |> x1 |> s
+    (|>) pacc (JSExportLocals alb JSLNil arb semi) = pacc |> alb |> "{" |> arb |> "}" |> semi
+    (|>) pacc (JSExportLocals alb s arb semi) = pacc |> alb |> "{" |> s |> arb |> "}" |> semi
+
+instance RenderJS JSExportLocalSpecifier where
+    (|>) pacc (JSExportLocalSpecifier i) = pacc |> i
+    (|>) pacc (JSExportLocalSpecifierAs x1 as x2) = pacc |> x1 |> as |> x2
+
 instance RenderJS a => RenderJS (JSCommaList a) where
     (|>) pacc (JSLCons pl a i) = pacc |> pl |> a |> "," |> i
     (|>) pacc (JSLOne i)       = pacc |> i
@@ -287,4 +305,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..7e16b99 100644
--- a/src/Language/JavaScript/Process/Minify.hs
+++ b/src/Language/JavaScript/Process/Minify.hs
@@ -15,6 +15,7 @@ import Language.JavaScript.Parser.Token
 
 minifyJS :: JSAST -> JSAST
 minifyJS (JSAstProgram xs _) = JSAstProgram (fixStatementList noSemi xs) emptyAnnot
+minifyJS (JSAstModule xs _) = JSAstModule (map (fix emptyAnnot) xs) emptyAnnot
 minifyJS (JSAstStatement (JSStatementBlock _ [s] _ _) _) = JSAstStatement (fixStmtE noSemi s) emptyAnnot
 minifyJS (JSAstStatement s _) = JSAstStatement (fixStmtE noSemi s) emptyAnnot
 minifyJS (JSAstExpression e _) =  JSAstExpression (fixEmpty e) emptyAnnot
@@ -209,6 +210,7 @@ normalizeToSQ str =
 
 instance MinifyJS JSBinOp where
     fix _ (JSBinOpAnd        _) = JSBinOpAnd emptyAnnot
+    fix a (JSBinOpAs         _) = JSBinOpAs a
     fix _ (JSBinOpBitAnd     _) = JSBinOpBitAnd emptyAnnot
     fix _ (JSBinOpBitOr      _) = JSBinOpBitOr emptyAnnot
     fix _ (JSBinOpBitXor     _) = JSBinOpBitXor emptyAnnot
@@ -265,6 +267,17 @@ instance MinifyJS JSAssignOp where
     fix a (JSBwXorAssign  _) = JSBwXorAssign a
     fix a (JSBwOrAssign   _) = JSBwOrAssign a
 
+instance MinifyJS JSModuleItem where
+    fix _ (JSModuleExportDeclaration _ x1) = JSModuleExportDeclaration emptyAnnot (fixEmpty x1)
+    fix a (JSModuleStatementListItem s) = JSModuleStatementListItem (fixStmt a noSemi s)
+
+instance MinifyJS JSExportDeclaration where
+    fix _ (JSExportLocals _ x1 _ _) = JSExportLocals emptyAnnot (fixEmpty x1) emptyAnnot noSemi
+    fix _ (JSExport x1 _) = JSExport (fixStmt emptyAnnot noSemi x1) noSemi
+
+instance MinifyJS JSExportLocalSpecifier where
+    fix _ (JSExportLocalSpecifier x1) = JSExportLocalSpecifier (fixEmpty x1)
+    fix _ (JSExportLocalSpecifierAs x1 as x2) = JSExportLocalSpecifierAs (fixEmpty x1) (fixSpace as) (fixSpace x2)
 
 instance MinifyJS JSTryCatch where
     fix a (JSCatch _ _ x1 _ x3) = JSCatch a emptyAnnot (fixEmpty x1) emptyAnnot (fixEmpty x3)
diff --git a/test/Test/Language/Javascript/Minify.hs b/test/Test/Language/Javascript/Minify.hs
index 2e63b7e..f8f8eca 100644
--- a/test/Test/Language/Javascript/Minify.hs
+++ b/test/Test/Language/Javascript/Minify.hs
@@ -2,15 +2,18 @@ module Test.Language.Javascript.Minify
     ( testMinifyExpr
     , testMinifyStmt
     , testMinifyProg
+    , testMinifyModule
     ) where
 
 import Control.Monad (forM_)
 import Test.Hspec
 
-import Language.JavaScript.Parser
+import Language.JavaScript.Parser hiding (parseModule)
 import Language.JavaScript.Parser.Grammar7
-import Language.JavaScript.Parser.Parser
+import Language.JavaScript.Parser.Lexer (Alex)
+import Language.JavaScript.Parser.Parser hiding (parseModule)
 import Language.JavaScript.Process.Minify
+import qualified Language.JavaScript.Parser.AST as AST
 
 
 testMinifyExpr :: Spec
@@ -251,14 +254,29 @@ testMinifyProg = describe "Minify programs:" $ do
     it "try/catch/finally" $
         minifyProg " try { } catch (a) {} finally {} ; try { } catch ( b ) { } ; " `shouldBe` "try{}catch(a){}finally{}try{}catch(b){}"
 
+testMinifyModule :: Spec
+testMinifyModule = describe "Minify modules:" $
+    it "export" $ do
+        minifyModule " export { } ; " `shouldBe` "export{}"
+        minifyModule " export { a } ; " `shouldBe` "export{a}"
+        minifyModule " export { a, b } ; " `shouldBe` "export{a,b}"
+        minifyModule " export { a, b as c , d } ; " `shouldBe` "export{a,b as c,d}"
+        minifyModule " export const a = 1 ; " `shouldBe` "export const a=1"
+
 -- -----------------------------------------------------------------------------
 -- Minify test helpers.
 
 minifyExpr :: String -> String
-minifyExpr str = either id (renderToString . minifyJS) (parseUsing parseExpression str "src")
+minifyExpr = minifyWith parseExpression
 
 minifyStmt :: String -> String
-minifyStmt str = either id (renderToString . minifyJS) (parseUsing parseStatement str "src")
+minifyStmt = minifyWith parseStatement
 
 minifyProg :: String -> String
-minifyProg str = either id (renderToString . minifyJS) (parseUsing parseProgram str "src")
+minifyProg = minifyWith parseProgram
+
+minifyModule :: String -> String
+minifyModule = minifyWith parseModule
+
+minifyWith :: (Alex AST.JSAST) -> String -> String
+minifyWith p str = either id (renderToString . minifyJS) (parseUsing p str "src")
diff --git a/test/Test/Language/Javascript/ModuleParser.hs b/test/Test/Language/Javascript/ModuleParser.hs
new file mode 100644
index 0000000..9b9dfad
--- /dev/null
+++ b/test/Test/Language/Javascript/ModuleParser.hs
@@ -0,0 +1,30 @@
+module Test.Language.Javascript.ModuleParser
+    ( testModuleParser
+    ) where
+
+import Test.Hspec
+
+import Language.JavaScript.Parser
+
+
+testModuleParser :: Spec
+testModuleParser = describe "Parse modules:" $
+    it "export" $ do
+        test "export {}"
+            `shouldBe`
+            "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals (()))])"
+        test "export {};"
+            `shouldBe`
+            "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals (()))])"
+        test "export const a = 1;"
+            `shouldBe`
+            "Right (JSAstModule [JSModuleExportDeclaration (JSExport (JSConstant (JSVarInitExpression (JSIdentifier 'a') [JSDecimal '1'])))])"
+        test "export { a };"
+            `shouldBe`
+            "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals ((JSExportLocalSpecifier (JSIdentifier 'a'))))])"
+        test "export { a as b };"
+            `shouldBe`
+            "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals ((JSExportLocalSpecifierAs (JSIdentifier 'a',JSIdentifier 'b'))))])"
+
+test :: String -> String
+test str = showStrippedMaybe (parseModule str "src")
diff --git a/test/Test/Language/Javascript/RoundTrip.hs b/test/Test/Language/Javascript/RoundTrip.hs
index b55efb0..2e2704d 100644
--- a/test/Test/Language/Javascript/RoundTrip.hs
+++ b/test/Test/Language/Javascript/RoundTrip.hs
@@ -5,6 +5,7 @@ module Test.Language.Javascript.RoundTrip
 import Test.Hspec
 
 import Language.JavaScript.Parser
+import qualified Language.JavaScript.Parser.AST as AST
 
 
 testRoundTrip :: Spec
@@ -99,7 +100,18 @@ testRoundTrip = describe "Roundtrip:" $ do
         testRT "switch (x) {default:\ncase 1:break;}"
         testRT "var x=1;let y=2;"
 
+    it "module" $ do
+        testRTModule "export   {};"
+        testRTModule "  export {}   ;  "
+        testRTModule "export {  a  ,  b  ,  c  };"
+        testRTModule "export {  a, X   as B,   c }"
+
 
 testRT :: String -> Expectation
-testRT str = str `shouldBe` renderToString (readJs str)
+testRT = testRTWith readJs
+
+testRTModule :: String -> Expectation
+testRTModule = testRTWith readJsModule
 
+testRTWith :: (String -> AST.JSAST) -> String -> Expectation
+testRTWith f str = renderToString (f str) `shouldBe` str
diff --git a/test/Test/Language/Javascript/StatementParser.hs b/test/Test/Language/Javascript/StatementParser.hs
index e27addf..8f3a7fa 100644
--- a/test/Test/Language/Javascript/StatementParser.hs
+++ b/test/Test/Language/Javascript/StatementParser.hs
@@ -16,6 +16,7 @@ testStatementParser = describe "Parse statements:" $ do
         testStmt "x"        `shouldBe` "Right (JSAstStatement (JSIdentifier 'x'))"
         testStmt "null"     `shouldBe` "Right (JSAstStatement (JSLiteral 'null'))"
         testStmt "true?1:2" `shouldBe` "Right (JSAstStatement (JSExpressionTernary (JSLiteral 'true',JSDecimal '1',JSDecimal '2')))"
+
     it "block" $ do
         testStmt "{}"           `shouldBe` "Right (JSAstStatement (JSStatementBlock []))"
         testStmt "{x=1}"        `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')]))"
@@ -101,4 +102,3 @@ testStatementParser = describe "Parse statements:" $ do
 
 testStmt :: String -> String
 testStmt str = showStrippedMaybe (parseUsing parseStatement str "src")
-
diff --git a/test/testsuite.hs b/test/testsuite.hs
index 7ba14d2..fac4d8d 100644
--- a/test/testsuite.hs
+++ b/test/testsuite.hs
@@ -5,10 +5,11 @@ import Test.Hspec
 import Test.Hspec.Runner
 
 
+import Test.Language.Javascript.ExpressionParser
 import Test.Language.Javascript.Lexer
 import Test.Language.Javascript.LiteralParser
-import Test.Language.Javascript.ExpressionParser
 import Test.Language.Javascript.Minify
+import Test.Language.Javascript.ModuleParser
 import Test.Language.Javascript.ProgramParser
 import Test.Language.Javascript.RoundTrip
 import Test.Language.Javascript.StatementParser
@@ -29,8 +30,9 @@ testAll = do
     testExpressionParser
     testStatementParser
     testProgramParser
+    testModuleParser
     testRoundTrip
     testMinifyExpr
     testMinifyStmt
     testMinifyProg
-
+    testMinifyModule