diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,20 @@
 # ChangeLog for `language-javascript`
 
+## 0.6.0.13 -- 2019-09-29
+
++ Add support for (Ryan Hendrickson):
+  - Destructuring in var declarations
+  - `const` in for statements
+  - ES6 property shorthand syntax
+  - Template literals
+  - Computed property names
+  - Bare import declarations
+  - Exotic parameter syntaxes
+  - Generators and `yield`
+  - Method definitions
+  - classes
+ `- super` keyword
+
 ## 0.6.0.13 -- 2019-06-17
 
 + Add support for (Cyril Sobierajewicz):
diff --git a/language-javascript.cabal b/language-javascript.cabal
--- a/language-javascript.cabal
+++ b/language-javascript.cabal
@@ -1,5 +1,5 @@
 Name:                language-javascript
-Version:             0.6.0.13
+Version:             0.6.0.14
 Synopsis:            Parser for JavaScript
 Description:         Parses Javascript into an Abstract Syntax Tree (AST).  Initially intended as frontend to hjsmin.
                      .
diff --git a/src/Language/JavaScript/Parser/AST.hs b/src/Language/JavaScript/Parser/AST.hs
--- a/src/Language/JavaScript/Parser/AST.hs
+++ b/src/Language/JavaScript/Parser/AST.hs
@@ -17,12 +17,16 @@
     , JSPropertyName (..)
     , JSObjectPropertyList
     , JSAccessor (..)
+    , JSMethodDefinition (..)
     , JSIdent (..)
     , JSVarInitializer (..)
     , JSArrayElement (..)
     , JSCommaList (..)
     , JSCommaTrailingList (..)
     , JSArrowParameterList (..)
+    , JSTemplatePart (..)
+    , JSClassHeritage (..)
+    , JSClassElement (..)
 
     -- Modules
     , JSModuleItem (..)
@@ -72,7 +76,7 @@
 
 data JSImportDeclaration
     = JSImportDeclaration !JSImportClause !JSFromClause !JSSemi -- ^imports, module, semi
-    -- | JSImportDeclarationBare -- ^ module, semi
+    | JSImportDeclarationBare !JSAnnot !String !JSSemi -- ^module, module, semi
     deriving (Data, Eq, Show, Typeable)
 
 data JSImportClause
@@ -126,6 +130,7 @@
     = JSStatementBlock !JSAnnot ![JSStatement] !JSAnnot !JSSemi     -- ^lbrace, stmts, rbrace, autosemi
     | JSBreak !JSAnnot !JSIdent !JSSemi        -- ^break,optional identifier, autosemi
     | JSLet   !JSAnnot !(JSCommaList JSExpression) !JSSemi -- ^const, decl, autosemi
+    | JSClass !JSAnnot !JSIdent !JSClassHeritage !JSAnnot ![JSClassElement] !JSAnnot !JSSemi -- ^class, name, optional extends clause, lb, body, rb, autosemi
     | JSConstant !JSAnnot !(JSCommaList JSExpression) !JSSemi -- ^const, decl, autosemi
     | JSContinue !JSAnnot !JSIdent !JSSemi     -- ^continue, optional identifier,autosemi
     | JSDoWhile !JSAnnot !JSStatement !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSSemi -- ^do,stmt,while,lb,expr,rb,autosemi
@@ -136,9 +141,13 @@
     | 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
+    | JSForConst !JSAnnot !JSAnnot !JSAnnot !(JSCommaList JSExpression) !JSAnnot !(JSCommaList JSExpression) !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSStatement -- ^for,lb,var,vardecl,semi,expr,semi,expr,rb,stmt
+    | JSForConstIn !JSAnnot !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,var,vardecl,in,expr,rb,stmt
+    | 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
+    | JSGenerator !JSAnnot !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
@@ -171,13 +180,15 @@
     | JSCallExpression !JSExpression !JSAnnot !(JSCommaList JSExpression) !JSAnnot  -- ^expr, bl, args, rb
     | JSCallExpressionDot !JSExpression !JSAnnot !JSExpression  -- ^expr, dot, expr
     | JSCallExpressionSquare !JSExpression !JSAnnot !JSExpression !JSAnnot  -- ^expr, [, expr, ]
+    | JSClassExpression !JSAnnot !JSIdent !JSClassHeritage !JSAnnot ![JSClassElement] !JSAnnot -- ^class, optional identifier, optional extends clause, lb, body, rb
     | JSCommaExpression !JSExpression !JSAnnot !JSExpression          -- ^expression components
     | JSExpressionBinary !JSExpression !JSBinOp !JSExpression -- ^lhs, op, rhs
     | JSExpressionParen !JSAnnot !JSExpression !JSAnnot -- ^lb,expression,rb
     | 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`
+    | JSGeneratorExpression !JSAnnot !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
@@ -185,13 +196,16 @@
     | JSNewExpression !JSAnnot !JSExpression -- ^new, expr
     | JSObjectLiteral !JSAnnot !JSObjectPropertyList !JSAnnot -- ^lbrace contents rbrace
     | JSSpreadExpression !JSAnnot !JSExpression
+    | JSTemplateLiteral !(Maybe JSExpression) !JSAnnot !String ![JSTemplatePart] -- ^optional tag, lquot, head, parts
     | JSUnaryExpression !JSUnaryOp !JSExpression
     | JSVarInitExpression !JSExpression !JSVarInitializer -- ^identifier, initializer
+    | JSYieldExpression !JSAnnot !(Maybe JSExpression) -- ^yield, optional expr
+    | JSYieldFromExpression !JSAnnot !JSAnnot !JSExpression -- ^yield, *, expr
     deriving (Data, Eq, Show, Typeable)
 
 data JSArrowParameterList
     = JSUnparenthesizedArrowParameter !JSIdent
-    | JSParenthesizedArrowParameterList !JSAnnot !(JSCommaList JSIdent) !JSAnnot
+    | JSParenthesizedArrowParameterList !JSAnnot !(JSCommaList JSExpression) !JSAnnot
     deriving (Data, Eq, Show, Typeable)
 
 data JSBinOp
@@ -278,14 +292,22 @@
     deriving (Data, Eq, Show, Typeable)
 
 data JSObjectProperty
-    = JSPropertyAccessor !JSAccessor !JSPropertyName !JSAnnot ![JSExpression] !JSAnnot !JSBlock -- ^(get|set), name, lb, params, rb, block
-    | JSPropertyNameandValue !JSPropertyName !JSAnnot ![JSExpression] -- ^name, colon, value
+    = JSPropertyNameandValue !JSPropertyName !JSAnnot ![JSExpression] -- ^name, colon, value
+    | JSPropertyIdentRef !JSAnnot !String
+    | JSObjectMethod !JSMethodDefinition
     deriving (Data, Eq, Show, Typeable)
 
+data JSMethodDefinition
+    = JSMethodDefinition !JSPropertyName !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- name, lb, params, rb, block
+    | JSGeneratorMethodDefinition !JSAnnot !JSPropertyName !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^*, name, lb, params, rb, block
+    | JSPropertyAccessor !JSAccessor !JSPropertyName !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^get/set, name, lb, params, rb, block
+    deriving (Data, Eq, Show, Typeable)
+
 data JSPropertyName
     = JSPropertyIdent !JSAnnot !String
     | JSPropertyString !JSAnnot !String
     | JSPropertyNumber !JSAnnot !String
+    | JSPropertyComputed !JSAnnot !JSExpression !JSAnnot -- ^lb, expr, rb
     deriving (Data, Eq, Show, Typeable)
 
 type JSObjectPropertyList = JSCommaTrailingList JSObjectProperty
@@ -317,6 +339,21 @@
     | JSCTLNone !(JSCommaList a) -- ^list
     deriving (Data, Eq, Show, Typeable)
 
+data JSTemplatePart
+    = JSTemplatePart !JSExpression !JSAnnot !String -- ^expr, rb, suffix
+    deriving (Data, Eq, Show, Typeable)
+
+data JSClassHeritage
+    = JSExtends !JSAnnot !JSExpression
+    | JSExtendsNone
+    deriving (Data, Eq, Show, Typeable)
+
+data JSClassElement
+    = JSClassInstanceMethod !JSMethodDefinition
+    | JSClassStaticMethod !JSAnnot !JSMethodDefinition
+    | JSClassSemi !JSAnnot
+    deriving (Data, Eq, Show, Typeable)
+
 -- -----------------------------------------------------------------------------
 -- | Show the AST elements stripped of their JSAnnot data.
 
@@ -336,6 +373,7 @@
     ss (JSStatementBlock _ xs _ _) = "JSStatementBlock " ++ ss xs
     ss (JSBreak _ JSIdentNone s) = "JSBreak" ++ commaIf (ss s)
     ss (JSBreak _ (JSIdentName _ n) s) = "JSBreak " ++ singleQuote n ++ commaIf (ss s)
+    ss (JSClass _ n h _lb xs _rb _) = "JSClass " ++ ssid n ++ " (" ++ ss h ++ ") " ++ ss xs
     ss (JSContinue _ JSIdentNone s) = "JSContinue" ++ commaIf (ss s)
     ss (JSContinue _ (JSIdentName _ n) s) = "JSContinue " ++ singleQuote n ++ commaIf (ss s)
     ss (JSConstant _ xs _as) = "JSConstant " ++ ss xs
@@ -347,9 +385,13 @@
     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 (JSForConst _ _lb _v x1s _s1 x2s _s2 x3s _rb x4) = "JSForConst " ++ ss x1s ++ " " ++ ss x2s ++ " " ++ ss x3s ++ " (" ++ ss x4 ++ ")"
+    ss (JSForConstIn _ _lb _v x1 _i x2 _rb x3) = "JSForConstIn (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
+    ss (JSForConstOf _ _lb _v x1 _i x2 _rb x3) = "JSForConstOf (" ++ 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 (JSGenerator _ _ n _lb pl _rb x3 _) = "JSGenerator " ++ 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 ++ ")"
     ss (JSLabelled x1 _c x2) = "JSLabelled (" ++ ss x1 ++ ") (" ++ ss x2 ++ ")"
@@ -373,6 +415,7 @@
     ss (JSCallExpression ex _ xs _) = "JSCallExpression ("++ ss ex ++ ",JSArguments " ++ ss xs ++ ")"
     ss (JSCallExpressionDot ex _os xs) = "JSCallExpressionDot (" ++ ss ex ++ "," ++ ss xs ++ ")"
     ss (JSCallExpressionSquare ex _os xs _cs) = "JSCallExpressionSquare (" ++ ss ex ++ "," ++ ss xs ++ ")"
+    ss (JSClassExpression _ n h _lb xs _rb) = "JSClassExpression " ++ ssid n ++ " (" ++ ss h ++ ") " ++ ss xs
     ss (JSDecimal _ s) = "JSDecimal " ++ singleQuote s
     ss (JSCommaExpression l _ r) = "JSExpression [" ++ ss l ++ "," ++ ss r ++ "]"
     ss (JSExpressionBinary x2 op x3) = "JSExpressionBinary (" ++ ss op ++ "," ++ ss x2 ++ "," ++ ss x3 ++ ")"
@@ -380,7 +423,8 @@
     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 (JSGeneratorExpression _ _ n _lb pl _rb x3) = "JSGeneratorExpression " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ ")"
     ss (JSHexInteger _ s) = "JSHexInteger " ++ singleQuote s
     ss (JSOctal _ s) = "JSOctal " ++ singleQuote s
     ss (JSIdentifier _ s) = "JSIdentifier " ++ singleQuote s
@@ -396,7 +440,12 @@
     ss (JSStringLiteral _ s) = "JSStringLiteral " ++ s
     ss (JSUnaryExpression op x) = "JSUnaryExpression (" ++ ss op ++ "," ++ ss x ++ ")"
     ss (JSVarInitExpression x1 x2) = "JSVarInitExpression (" ++ ss x1 ++ ") " ++ ss x2
+    ss (JSYieldExpression _ Nothing) = "JSYieldExpression ()"
+    ss (JSYieldExpression _ (Just x)) = "JSYieldExpression (" ++ ss x ++ ")"
+    ss (JSYieldFromExpression _ _ x) = "JSYieldFromExpression (" ++ ss x ++ ")"
     ss (JSSpreadExpression _ x1) = "JSSpreadExpression (" ++ ss x1 ++ ")"
+    ss (JSTemplateLiteral Nothing _ s ps) = "JSTemplateLiteral (()," ++ singleQuote s ++ "," ++ ss ps ++ ")"
+    ss (JSTemplateLiteral (Just t) _ s ps) = "JSTemplateLiteral ((" ++ ss t ++ ")," ++ singleQuote s ++ "," ++ ss ps ++ ")"
 
 instance ShowStripped JSArrowParameterList where
     ss (JSUnparenthesizedArrowParameter x) = ss x
@@ -409,6 +458,7 @@
 
 instance ShowStripped JSImportDeclaration where
     ss (JSImportDeclaration imp from _) = "JSImportDeclaration (" ++ ss imp ++ "," ++ ss from ++ ")"
+    ss (JSImportDeclarationBare _ m _) = "JSImportDeclarationBare (" ++ singleQuote m ++ ")"
 
 instance ShowStripped JSImportClause where
     ss (JSImportClauseDefault x) = "JSImportClauseDefault (" ++ ss x ++ ")"
@@ -456,12 +506,19 @@
 
 instance ShowStripped JSObjectProperty where
     ss (JSPropertyNameandValue x1 _colon x2s) = "JSPropertyNameandValue (" ++ ss x1 ++ ") " ++ ss x2s
+    ss (JSPropertyIdentRef _ s) = "JSPropertyIdentRef " ++ singleQuote s
+    ss (JSObjectMethod m) = ss m
+
+instance ShowStripped JSMethodDefinition where
+    ss (JSMethodDefinition x1 _lb1 x2s _rb1 x3) = "JSMethodDefinition (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
     ss (JSPropertyAccessor s x1 _lb1 x2s _rb1 x3) = "JSPropertyAccessor " ++ ss s ++ " (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
+    ss (JSGeneratorMethodDefinition _ x1 _lb1 x2s _rb1 x3) = "JSGeneratorMethodDefinition (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
 
 instance ShowStripped JSPropertyName where
     ss (JSPropertyIdent _ s) = "JSIdentifier " ++ singleQuote s
     ss (JSPropertyString _ s) = "JSIdentifier " ++ singleQuote s
     ss (JSPropertyNumber _ s) = "JSIdentifier " ++ singleQuote s
+    ss (JSPropertyComputed _ x _) = "JSPropertyComputed (" ++ ss x ++ ")"
 
 instance ShowStripped JSAccessor where
     ss (JSAccessorGet _) = "JSAccessorGet"
@@ -536,6 +593,18 @@
 instance ShowStripped JSArrayElement where
     ss (JSArrayElement e) = ss e
     ss (JSArrayComma _) = "JSComma"
+
+instance ShowStripped JSTemplatePart where
+    ss (JSTemplatePart e _ s) = "(" ++ ss e ++ "," ++ singleQuote s ++ ")"
+
+instance ShowStripped JSClassHeritage where
+    ss JSExtendsNone = ""
+    ss (JSExtends _ x) = ss x
+
+instance ShowStripped JSClassElement where
+    ss (JSClassInstanceMethod m) = ss m
+    ss (JSClassStaticMethod _ m) = "JSClassStaticMethod (" ++ ss m ++ ")"
+    ss (JSClassSemi _) = "JSClassSemi"
 
 instance ShowStripped a => ShowStripped (JSCommaList a) where
     ss xs = "(" ++ commaJoin (map ss $ fromCommaList xs) ++ ")"
diff --git a/src/Language/JavaScript/Parser/Grammar7.y b/src/Language/JavaScript/Parser/Grammar7.y
--- a/src/Language/JavaScript/Parser/Grammar7.y
+++ b/src/Language/JavaScript/Parser/Grammar7.y
@@ -9,6 +9,7 @@
     ) where
 
 import Data.Char
+import Data.Functor (($>))
 import Language.JavaScript.Parser.Lexer
 import Language.JavaScript.Parser.ParserMonad
 import Language.JavaScript.Parser.SrcLocation
@@ -88,6 +89,7 @@
      'break'      { BreakToken {} }
      'case'       { CaseToken {} }
      'catch'      { CatchToken {} }
+     'class'      { ClassToken {} }
      'const'      { ConstToken {} }
      'continue'   { ContinueToken {} }
      'debugger'   { DebuggerToken {} }
@@ -97,6 +99,7 @@
      'else'       { ElseToken {} }
      'enum'       { EnumToken {} }
      'export'     { ExportToken {} }
+     'extends'    { ExtendsToken {} }
      'false'      { FalseToken {} }
      'finally'    { FinallyToken {} }
      'for'        { ForToken {} }
@@ -113,6 +116,8 @@
      'of'         { OfToken {} }
      'return'     { ReturnToken {} }
      'set'        { SetToken {} }
+     'static'     { StaticToken {} }
+     'super'      { SuperToken {} }
      'switch'     { SwitchToken {} }
      'this'       { ThisToken {} }
      'throw'      { ThrowToken {} }
@@ -123,6 +128,7 @@
      'void'       { VoidToken {} }
      'while'      { WhileToken {} }
      'with'       { WithToken {} }
+     'yield'      { YieldToken {} }
 
 
      'ident'      { IdentifierToken {} }
@@ -131,6 +137,10 @@
      'octal'      { OctalToken {} }
      'string'     { StringToken {} }
      'regex'      { RegExToken {} }
+     'tmplnosub'  { NoSubstitutionTemplateToken {} }
+     'tmplhead'   { TemplateHeadToken {} }
+     'tmplmiddle' { TemplateMiddleToken {} }
+     'tmpltail'   { TemplateTailToken {} }
 
      'future'     { FutureToken {} }
 
@@ -309,6 +319,58 @@
          | '^='     { AST.JSBwXorAssign  (mkJSAnnot $1) }
          | '|='     { AST.JSBwOrAssign   (mkJSAnnot $1) }
 
+-- IdentifierName ::                                                        See 7.6
+--         IdentifierStart
+--         IdentifierName IdentifierPart
+-- Note: This production needs to precede the productions for all keyword
+-- statements and PrimaryExpression. Contra the Happy documentation, in the
+-- case of a reduce/reduce conflict, the *later* rule takes precedence, and
+-- the ambiguity of, for example, `{break}` needs to resolve in favor of
+-- `break` as a keyword and not as an identifier in property shorthand
+-- syntax.
+-- TODO: make this include any reserved word too, including future ones
+IdentifierName :: { AST.JSExpression }
+IdentifierName : Identifier {$1}
+             | 'break'      { AST.JSIdentifier (mkJSAnnot $1) "break" }
+             | 'case'       { AST.JSIdentifier (mkJSAnnot $1) "case" }
+             | 'catch'      { AST.JSIdentifier (mkJSAnnot $1) "catch" }
+             | 'class'      { AST.JSIdentifier (mkJSAnnot $1) "class" }
+             | 'const'      { AST.JSIdentifier (mkJSAnnot $1) "const" }
+             | 'continue'   { AST.JSIdentifier (mkJSAnnot $1) "continue" }
+             | 'debugger'   { AST.JSIdentifier (mkJSAnnot $1) "debugger" }
+             | 'default'    { AST.JSIdentifier (mkJSAnnot $1) "default" }
+             | 'delete'     { AST.JSIdentifier (mkJSAnnot $1) "delete" }
+             | 'do'         { AST.JSIdentifier (mkJSAnnot $1) "do" }
+             | 'else'       { AST.JSIdentifier (mkJSAnnot $1) "else" }
+             | 'enum'       { AST.JSIdentifier (mkJSAnnot $1) "enum" }
+             | 'export'     { AST.JSIdentifier (mkJSAnnot $1) "export" }
+             | 'extends'    { AST.JSIdentifier (mkJSAnnot $1) "extends" }
+             | 'false'      { AST.JSIdentifier (mkJSAnnot $1) "false" }
+             | 'finally'    { AST.JSIdentifier (mkJSAnnot $1) "finally" }
+             | 'for'        { AST.JSIdentifier (mkJSAnnot $1) "for" }
+             | 'function'   { AST.JSIdentifier (mkJSAnnot $1) "function" }
+             | 'if'         { AST.JSIdentifier (mkJSAnnot $1) "if" }
+             | 'in'         { AST.JSIdentifier (mkJSAnnot $1) "in" }
+             | 'instanceof' { AST.JSIdentifier (mkJSAnnot $1) "instanceof" }
+             | '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" }
+             | 'static'     { AST.JSIdentifier (mkJSAnnot $1) "static" }
+             | 'super'      { AST.JSIdentifier (mkJSAnnot $1) "super" }
+             | 'switch'     { AST.JSIdentifier (mkJSAnnot $1) "switch" }
+             | 'this'       { AST.JSIdentifier (mkJSAnnot $1) "this" }
+             | 'throw'      { AST.JSIdentifier (mkJSAnnot $1) "throw" }
+             | 'true'       { AST.JSIdentifier (mkJSAnnot $1) "true" }
+             | 'try'        { AST.JSIdentifier (mkJSAnnot $1) "try" }
+             | 'typeof'     { AST.JSIdentifier (mkJSAnnot $1) "typeof" }
+             | 'var'        { AST.JSIdentifier (mkJSAnnot $1) "var" }
+             | 'void'       { AST.JSIdentifier (mkJSAnnot $1) "void" }
+             | 'while'      { AST.JSIdentifier (mkJSAnnot $1) "while" }
+             | 'with'       { AST.JSIdentifier (mkJSAnnot $1) "with" }
+             | 'future'     { AST.JSIdentifier (mkJSAnnot $1) (tokenLiteral $1) }
+
 Var :: { AST.JSAnnot }
 Var : 'var' { mkJSAnnot $1 }
 
@@ -381,7 +443,19 @@
 New :: { AST.JSAnnot }
 New : 'new' { mkJSAnnot $1 }
 
+Class :: { AST.JSAnnot }
+Class : 'class' { mkJSAnnot $1 }
 
+Extends :: { AST.JSAnnot }
+Extends : 'extends' { mkJSAnnot $1 }
+
+Static :: { AST.JSAnnot }
+Static : 'static' { mkJSAnnot $1 }
+
+Super :: { AST.JSExpression }
+Super : 'super' { AST.JSLiteral (mkJSAnnot $1) "super" }
+
+
 Eof :: { AST.JSAnnot }
 Eof : 'tail' { mkJSAnnot $1 {- 'Eof' -} }
 
@@ -432,68 +506,46 @@
                   | Literal                  { $1 {- 'PrimaryExpression2' -} }
                   | ArrayLiteral             { $1 {- 'PrimaryExpression3' -} }
                   | ObjectLiteral            { $1 {- 'PrimaryExpression4' -} }
-                  | SpreadExpression         { $1 {- 'PrimaryExpression5' -} }
+                  | ClassExpression          { $1 }
+                  | GeneratorExpression      { $1 }
+                  | TemplateLiteral          { mkJSTemplateLiteral Nothing $1 {- 'PrimaryExpression6' -} }
                   | LParen Expression RParen { AST.JSExpressionParen $1 $2 $3 }
 
 -- Identifier ::                                                            See 7.6
 --         IdentifierName but not ReservedWord
--- IdentifierName ::                                                        See 7.6
---         IdentifierStart
---         IdentifierName IdentifierPart
 Identifier :: { AST.JSExpression }
 Identifier : 'ident' { AST.JSIdentifier (mkJSAnnot $1) (tokenLiteral $1) }
            | 'as'    { AST.JSIdentifier (mkJSAnnot $1) "as" }
            | 'get'   { AST.JSIdentifier (mkJSAnnot $1) "get" }
            | 'set'   { AST.JSIdentifier (mkJSAnnot $1) "set" }
            | 'from'  { AST.JSIdentifier (mkJSAnnot $1) "from" }
+           | 'yield' { AST.JSIdentifier (mkJSAnnot $1) "yield" }
 
--- 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" }
-             | 'const'      { AST.JSIdentifier (mkJSAnnot $1) "const" }
-             | 'continue'   { AST.JSIdentifier (mkJSAnnot $1) "continue" }
-             | 'debugger'   { AST.JSIdentifier (mkJSAnnot $1) "debugger" }
-             | 'default'    { AST.JSIdentifier (mkJSAnnot $1) "default" }
-             | 'delete'     { AST.JSIdentifier (mkJSAnnot $1) "delete" }
-             | '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" }
-             | 'function'   { AST.JSIdentifier (mkJSAnnot $1) "function" }
-             | 'from'       { AST.JSIdentifier (mkJSAnnot $1) "from" }
-             | 'get'        { AST.JSIdentifier (mkJSAnnot $1) "get" }
-             | 'if'         { AST.JSIdentifier (mkJSAnnot $1) "if" }
-             | 'in'         { AST.JSIdentifier (mkJSAnnot $1) "in" }
-             | 'instanceof' { AST.JSIdentifier (mkJSAnnot $1) "instanceof" }
-             | '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" }
-             | 'this'       { AST.JSIdentifier (mkJSAnnot $1) "this" }
-             | 'throw'      { AST.JSIdentifier (mkJSAnnot $1) "throw" }
-             | 'true'       { AST.JSIdentifier (mkJSAnnot $1) "true" }
-             | 'try'        { AST.JSIdentifier (mkJSAnnot $1) "try" }
-             | 'typeof'     { AST.JSIdentifier (mkJSAnnot $1) "typeof" }
-             | 'var'        { AST.JSIdentifier (mkJSAnnot $1) "var" }
-             | 'void'       { AST.JSIdentifier (mkJSAnnot $1) "void" }
-             | 'while'      { AST.JSIdentifier (mkJSAnnot $1) "while" }
-             | 'with'       { AST.JSIdentifier (mkJSAnnot $1) "with" }
-             | 'future'     { AST.JSIdentifier (mkJSAnnot $1) (tokenLiteral $1) }
+-- Must follow Identifier; when ambiguous, `yield` as a keyword should take
+-- precedence over `yield` as an identifier name.
+Yield :: { AST.JSAnnot }
+Yield : 'yield' { mkJSAnnot $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) [] }
+                | 'tmplhead' TemplateParts { JSUntaggedTemplate (mkJSAnnot $1) (tokenLiteral $1) $2 }
+
+TemplateParts :: { [AST.JSTemplatePart] }
+TemplateParts : TemplateExpression RBrace 'tmplmiddle' TemplateParts { AST.JSTemplatePart $1 $2 ('}' : tokenLiteral $3) : $4 }
+              | TemplateExpression RBrace 'tmpltail'                 { AST.JSTemplatePart $1 $2 ('}' : tokenLiteral $3) : [] }
+
+-- This production only exists to ensure that inTemplate is set to True before
+-- a tmplmiddle or tmpltail token is lexed. Since the lexer is always one token
+-- ahead of the parser, setInTemplate needs to be called during a reduction
+-- that is *two* tokens behind tmplmiddle/tmpltail. Accordingly,
+-- TemplateExpression is always followed by an RBrace, which is lexed normally.
+TemplateExpression :: { AST.JSExpression }
+TemplateExpression : Expression {% setInTemplate True \$> $1 }
+
 -- ArrayLiteral :                                                        See 11.1.4
 --        [ Elisionopt ]
 --        [ ElementList ]
@@ -545,16 +597,28 @@
 --        PropertyName : AssignmentExpression
 --        get PropertyName() { FunctionBody }
 --        set PropertyName( PropertySetParameterList ) { FunctionBody }
--- TODO: not clear if get/set are keywords, or just used in a specific context. Puzzling.
 PropertyAssignment :: { AST.JSObjectProperty }
 PropertyAssignment : PropertyName Colon AssignmentExpression { AST.JSPropertyNameandValue $1 $2 [$3] }
-                   -- Should be "get" in next, but is not a Token
-                   | 'get' PropertyName LParen RParen FunctionBody
-                       { AST.JSPropertyAccessor (AST.JSAccessorGet (mkJSAnnot $1)) $2 $3 [] $4 $5 }
-                   -- Should be "set" in next, but is not a Token
-                   | 'set' PropertyName LParen PropertySetParameterList RParen FunctionBody
-                       { AST.JSPropertyAccessor (AST.JSAccessorSet (mkJSAnnot $1)) $2 $3 [$4] $5 $6 }
+                   | IdentifierName { identifierToProperty $1 }
+                   | MethodDefinition { AST.JSObjectMethod $1 }
 
+-- TODO: not clear if get/set are keywords, or just used in a specific context. Puzzling.
+MethodDefinition :: { AST.JSMethodDefinition }
+MethodDefinition : PropertyName LParen RParen FunctionBody
+                     { AST.JSMethodDefinition $1 $2 AST.JSLNil $3 $4 }
+                 | PropertyName LParen FormalParameterList RParen FunctionBody
+                     { AST.JSMethodDefinition $1 $2 $3 $4 $5 }
+                 | '*' PropertyName LParen RParen FunctionBody
+                     { AST.JSGeneratorMethodDefinition (mkJSAnnot $1) $2 $3 AST.JSLNil $4 $5 }
+                 | '*' PropertyName LParen FormalParameterList RParen FunctionBody
+                     { AST.JSGeneratorMethodDefinition (mkJSAnnot $1) $2 $3 $4 $5 $6 }
+                 -- Should be "get" in next, but is not a Token
+                 | 'get' PropertyName LParen RParen FunctionBody
+                     { AST.JSPropertyAccessor (AST.JSAccessorGet (mkJSAnnot $1)) $2 $3 AST.JSLNil $4 $5 }
+                 -- Should be "set" in next, but is not a Token
+                 | 'set' PropertyName LParen PropertySetParameterList RParen FunctionBody
+                     { AST.JSPropertyAccessor (AST.JSAccessorSet (mkJSAnnot $1)) $2 $3 (AST.JSLOne $4) $5 $6 }
+
 -- PropertyName :                                                        See 11.1.5
 --        IdentifierName
 --        StringLiteral
@@ -563,11 +627,12 @@
 PropertyName : IdentifierName { propName $1 {- 'PropertyName1' -} }
              | StringLiteral  { propName $1 {- 'PropertyName2' -} }
              | NumericLiteral { propName $1 {- 'PropertyName3' -} }
+             | LSquare AssignmentExpression RSquare { AST.JSPropertyComputed $1 $2 $3 {- 'PropertyName4' -} }
 
 -- PropertySetParameterList :                                            See 11.1.5
 --        Identifier
 PropertySetParameterList :: { AST.JSExpression }
-PropertySetParameterList : Identifier { $1 {- 'PropertySetParameterList' -} }
+PropertySetParameterList : AssignmentExpression { $1 {- 'PropertySetParameterList' -} }
 
 -- MemberExpression :                                           See 11.2
 --        PrimaryExpression
@@ -580,6 +645,9 @@
                  | FunctionExpression  { $1 {- 'MemberExpression2' -} }
                  | MemberExpression LSquare Expression RSquare { AST.JSMemberSquare $1 $2 $3 $4 {- 'MemberExpression3' -} }
                  | MemberExpression Dot IdentifierName         { AST.JSMemberDot $1 $2 $3       {- 'MemberExpression4' -} }
+                 | MemberExpression TemplateLiteral            { mkJSTemplateLiteral (Just $1) $2 }
+                 | Super LSquare Expression RSquare            { AST.JSMemberSquare $1 $2 $3 $4 }
+                 | Super Dot IdentifierName                    { AST.JSMemberDot $1 $2 $3 }
                  | New MemberExpression Arguments              { mkJSMemberNew $1 $2 $3         {- 'MemberExpression5' -} }
 
 -- NewExpression :                                              See 11.2
@@ -597,12 +665,16 @@
 CallExpression :: { AST.JSExpression }
 CallExpression : MemberExpression Arguments
                     { mkJSMemberExpression $1 $2 {- 'CallExpression1' -} }
+               | Super Arguments
+                    { mkJSCallExpression $1 $2 }
                | CallExpression Arguments
                     { mkJSCallExpression $1 $2 {- 'CallExpression2' -} }
                | CallExpression LSquare Expression RSquare
                     { AST.JSCallExpressionSquare $1 $2 $3 $4 {- 'CallExpression3' -} }
                | CallExpression Dot IdentifierName
                     { AST.JSCallExpressionDot $1 $2 $3 {- 'CallExpression4' -} }
+               | CallExpression TemplateLiteral
+                    { mkJSTemplateLiteral (Just $1) $2 {- 'CallExpression5' -} }
 
 -- Arguments :                                                  See 11.2
 --        ()
@@ -839,14 +911,17 @@
 --        LeftHandSideExpression AssignmentOperator AssignmentExpression
 AssignmentExpression :: { AST.JSExpression }
 AssignmentExpression : ConditionalExpression { $1 {- 'AssignmentExpression1' -} }
+                     | YieldExpression { $1 }
                      | LeftHandSideExpression AssignmentOperator AssignmentExpression
                        { AST.JSAssignExpression $1 $2 $3 {- 'AssignmentExpression2' -} }
+                     | SpreadExpression { $1 }
 
 -- AssignmentExpressionNoIn :                                                            See 11.13
 --        ConditionalExpressionNoIn
 --        LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
 AssignmentExpressionNoIn :: { AST.JSExpression }
 AssignmentExpressionNoIn : ConditionalExpressionNoIn { $1 {- 'AssignmentExpressionNoIn1' -} }
+                         | YieldExpression { $1 }
                          | LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
                            { AST.JSAssignExpression $1 $2 $3 {- 'AssignmentExpressionNoIn1' -} }
 
@@ -958,14 +1033,14 @@
 -- VariableDeclaration :                                          See 12.2
 --         Identifier Initialiseropt
 VariableDeclaration :: { AST.JSExpression }
-VariableDeclaration : Identifier SimpleAssign AssignmentExpression { AST.JSVarInitExpression $1 (AST.JSVarInit $2 $3) {- 'JSVarInitExpression1' -} }
-                    | Identifier                                   { AST.JSVarInitExpression $1 AST.JSVarInitNone     {- 'JSVarInitExpression2' -} }
+VariableDeclaration : PrimaryExpression SimpleAssign AssignmentExpression { AST.JSVarInitExpression $1 (AST.JSVarInit $2 $3) {- 'JSVarInitExpression1' -} }
+                    | Identifier                                          { AST.JSVarInitExpression $1 AST.JSVarInitNone     {- 'JSVarInitExpression2' -} }
 
 -- VariableDeclarationNoIn :                                      See 12.2
 --         Identifier InitialiserNoInopt
 VariableDeclarationNoIn :: { AST.JSExpression }
-VariableDeclarationNoIn : Identifier SimpleAssign AssignmentExpression { AST.JSVarInitExpression $1 (AST.JSVarInit $2 $3) {- 'JSVarInitExpressionInit2' -} }
-                        | Identifier                                   { AST.JSVarInitExpression $1 AST.JSVarInitNone     {- 'JSVarInitExpression2' -} }
+VariableDeclarationNoIn : PrimaryExpression SimpleAssign AssignmentExpression { AST.JSVarInitExpression $1 (AST.JSVarInit $2 $3) {- 'JSVarInitExpressionInit2' -} }
+                        | Identifier                                          { AST.JSVarInitExpression $1 AST.JSVarInitNone     {- 'JSVarInitExpression2' -} }
 
 -- EmptyStatement :                                                                         See 12.3
 --         ;
@@ -1024,6 +1099,12 @@
                      { 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' -} }
+                   | For LParen Const VariableDeclarationListNoIn Semi ExpressionOpt Semi ExpressionOpt RParen Statement
+                     { AST.JSForConst $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 {- 'IterationStatement 12' -} }
+                   | For LParen Const VariableDeclarationNoIn In Expression RParen Statement
+                     { AST.JSForConstIn $1 $2 $3 $4 $5 $6 $7 $8 {- 'IterationStatement 13' -} }
+                   | For LParen Const VariableDeclarationNoIn Of Expression RParen Statement
+                     { AST.JSForConstOf $1 $2 $3 $4 $5 $6 $7 $8 {- 'IterationStatement 14' -} }
 
 -- ContinueStatement :                                                                      See 12.7
 --         continue [no LineTerminator here] Identifieropt ;
@@ -1141,12 +1222,9 @@
                            { 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 }
@@ -1170,7 +1248,39 @@
                  | Function LParen FormalParameterList RParen FunctionBody
                     { AST.JSFunctionExpression $1 AST.JSIdentNone $2 $3 $4 $5           {- 'LambdaExpression2' -} }
 
+-- GeneratorDeclaration :
+--         function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
+--         function * ( FormalParameters ) { GeneratorBody }
+GeneratorDeclaration :: { AST.JSStatement }
+GeneratorDeclaration : NamedGeneratorExpression MaybeSemi  { expressionToStatement $1 $2 }
 
+-- GeneratorExpression :
+--         function * BindingIdentifieropt ( FormalParameters ) { GeneratorBody }
+-- GeneratorBody :
+--         FunctionBody
+GeneratorExpression :: { AST.JSExpression }
+GeneratorExpression : NamedGeneratorExpression { $1 }
+                    | Function '*' LParen RParen FunctionBody
+                        { AST.JSGeneratorExpression $1 (mkJSAnnot $2) AST.JSIdentNone $3 AST.JSLNil $4 $5 }
+                    | Function '*' LParen FormalParameterList RParen FunctionBody
+                        { AST.JSGeneratorExpression $1 (mkJSAnnot $2) AST.JSIdentNone $3 $4 $5 $6 }
+
+NamedGeneratorExpression :: { AST.JSExpression }
+NamedGeneratorExpression : Function '*' Identifier LParen RParen FunctionBody
+                             { AST.JSGeneratorExpression $1 (mkJSAnnot $2) (identName $3) $4 AST.JSLNil $5 $6 }
+                         | Function '*' Identifier LParen FormalParameterList RParen FunctionBody
+                             { AST.JSGeneratorExpression $1 (mkJSAnnot $2) (identName $3) $4 $5 $6 $7 }
+
+-- YieldExpression :
+--         yield
+--         yield [no LineTerminator here] AssignmentExpression
+--         yield [no LineTerminator here] * AssignmentExpression
+YieldExpression :: { AST.JSExpression }
+YieldExpression : Yield { AST.JSYieldExpression $1 Nothing }
+                | Yield AssignmentExpression { AST.JSYieldExpression $1 (Just $2) }
+                | Yield '*' AssignmentExpression { AST.JSYieldFromExpression $1 (mkJSAnnot $2) $3 }
+
+
 IdentifierOpt :: { AST.JSIdent }
 IdentifierOpt : Identifier { identName $1     {- 'IdentifierOpt1' -} }
               |            { AST.JSIdentNone  {- 'IdentifierOpt2' -} }
@@ -1178,15 +1288,53 @@
 -- 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
 FunctionBody :: { AST.JSBlock }
 FunctionBody : Block                    { $1    {- 'FunctionBody1' -} }
 
+-- ClassDeclaration :
+--         class BindingIdentifier ClassTail
+--         class ClassTail
+-- ClassExpression :
+--         class BindingIdentifieropt ClassTail
+-- ClassTail :
+--         ClassHeritageopt { ClassBodyopt }
+ClassDeclaration :: { AST.JSStatement }
+ClassDeclaration : Class Identifier ClassHeritage LBrace ClassBody RBrace { AST.JSClass $1 (identName $2) $3 $4 $5 $6 AST.JSSemiAuto }
+
+ClassExpression :: { AST.JSExpression }
+ClassExpression : Class Identifier ClassHeritage LBrace ClassBody RBrace { AST.JSClassExpression $1 (identName $2)  $3 $4 $5 $6 }
+                | Class            ClassHeritage LBrace ClassBody RBrace { AST.JSClassExpression $1 AST.JSIdentNone $2 $3 $4 $5 }
+
+-- ClassHeritage :
+--         extends LeftHandSideExpression
+ClassHeritage :: { AST.JSClassHeritage }
+ClassHeritage : Extends LeftHandSideExpression { AST.JSExtends $1 $2 }
+              |                                { AST.JSExtendsNone }
+
+-- ClassBody :
+--         ClassElementList
+-- ClassElementList :
+--         ClassElement
+--         ClassElementList ClassElement
+ClassBody :: { [AST.JSClassElement] }
+ClassBody :                        { [] }
+          | ClassBody ClassElement { $1 ++ [$2] }
+
+-- ClassElement :
+--         MethodDefinition
+--         static MethodDefinition
+--         ;
+ClassElement :: { AST.JSClassElement }
+ClassElement : MethodDefinition        { AST.JSClassInstanceMethod $1 }
+             | Static MethodDefinition { AST.JSClassStaticMethod $1 $2 }
+             | Semi                    { AST.JSClassSemi $1 }
+
 -- Program :                                                                  See clause 14
 --        SourceElementsopt
 
@@ -1225,6 +1373,8 @@
 ImportDeclaration :: { AST.JSImportDeclaration }
 ImportDeclaration : ImportClause FromClause AutoSemi
                           { AST.JSImportDeclaration $1 $2 $3 }
+                  | 'string' AutoSemi
+                          { AST.JSImportDeclarationBare (mkJSAnnot $1) (tokenLiteral $1) $2 }
 
 ImportClause :: { AST.JSImportClause }
 ImportClause : IdentifierName
@@ -1270,11 +1420,11 @@
 -- [ ]    export Declaration
 -- [ ]    Declaration :
 -- [ ]       HoistableDeclaration
--- [ ]       ClassDeclaration
+-- [x]       ClassDeclaration
 -- [x]       LexicalDeclaration
 -- [ ]    HoistableDeclaration :
 -- [x]       FunctionDeclaration
--- [ ]       GeneratorDeclaration
+-- [x]       GeneratorDeclaration
 -- [ ]       AsyncFunctionDeclaration
 -- [ ]       AsyncGeneratorDeclaration
 -- [ ]    export default HoistableDeclaration[Default]
@@ -1289,6 +1439,10 @@
                          { AST.JSExport $1 $2         {- 'ExportDeclaration3' -} }
                   | FunctionDeclaration AutoSemi
                          { AST.JSExport $1 $2         {- 'ExportDeclaration4' -} }
+                  | GeneratorDeclaration AutoSemi
+                         { AST.JSExport $1 $2         {- 'ExportDeclaration5' -} }
+                  | ClassDeclaration AutoSemi
+                         { AST.JSExport $1 $2         {- 'ExportDeclaration6' -} }
 
 -- ExportClause :
 --           { }
@@ -1332,15 +1486,17 @@
 
 -- Need this type while build the AST, but is not actually part of the AST.
 data JSArguments = JSArguments AST.JSAnnot (AST.JSCommaList AST.JSExpression) AST.JSAnnot    -- ^lb, args, rb
-
+data JSUntaggedTemplate = JSUntaggedTemplate !AST.JSAnnot !String ![AST.JSTemplatePart] -- lquot, head, parts
 
 blockToStatement :: AST.JSBlock -> AST.JSSemi -> AST.JSStatement
 blockToStatement (AST.JSBlock a b c) s = AST.JSStatementBlock a b c s
 
 expressionToStatement :: AST.JSExpression -> AST.JSSemi -> AST.JSStatement
 expressionToStatement (AST.JSFunctionExpression a b@(AST.JSIdentName{}) c d e f) s = AST.JSFunction a b c d e f s
+expressionToStatement (AST.JSGeneratorExpression a b c@(AST.JSIdentName{}) d e f g) s = AST.JSGenerator a b c d e f g s
 expressionToStatement (AST.JSAssignExpression lhs op rhs) s = AST.JSAssignStatement lhs op rhs s
 expressionToStatement (AST.JSMemberExpression e l a r) s = AST.JSMethodCall e l a r s
+expressionToStatement (AST.JSClassExpression a b@(AST.JSIdentName{}) c d e f) s = AST.JSClass a b c d e f s
 expressionToStatement exp s = AST.JSExpressionStatement exp s
 
 
@@ -1359,6 +1515,9 @@
 mkJSAnnot :: Token -> AST.JSAnnot
 mkJSAnnot a = AST.JSAnnot (tokenSpan a) (tokenComment a)
 
+mkJSTemplateLiteral :: Maybe AST.JSExpression -> JSUntaggedTemplate -> AST.JSExpression
+mkJSTemplateLiteral tag (JSUntaggedTemplate a h ps) = AST.JSTemplateLiteral tag a h ps
+
 -- ---------------------------------------------------------------------
 -- | mkUnary : The parser detects '+' and '-' as the binary version of these
 -- operator. This function converts from the binary version to the unary
@@ -1380,5 +1539,18 @@
 propName (AST.JSOctal a s) = AST.JSPropertyNumber a s
 propName (AST.JSStringLiteral a s) = AST.JSPropertyString a s
 propName x = error $ "Cannot convert '" ++ show x ++ "' to a JSPropertyName."
+
+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
 
 }
diff --git a/src/Language/JavaScript/Parser/Lexer.x b/src/Language/JavaScript/Parser/Lexer.x
--- a/src/Language/JavaScript/Parser/Lexer.x
+++ b/src/Language/JavaScript/Parser/Lexer.x
@@ -15,6 +15,7 @@
     , alexError
     , runAlex
     , alexTestTokeniser
+    , setInTemplate
     ) where
 
 import Language.JavaScript.Parser.LexerUtils
@@ -187,12 +188,21 @@
 @IdentifierPart = @IdentifierStart | $UnicodeCombiningMark | $UnicodeDigit | UnicodeConnectorPunctuation
         [\\] @UnicodeEscapeSequence | $ZWNJ | $ZWJ
 
+-- TemplateCharacter ::
+--         $ [lookahead ≠ { ]
+--         \ EscapeSequence
+--         LineContinuation
+--         LineTerminatorSequence
+--         SourceCharacter but not one of ` or \ or $ or LineTerminator
+@TemplateCharacters = (\$* ($any_unicode_char # [\$\\`\{] | \\ $any_unicode_char) | \\ $any_unicode_char | \{)* \$*
+
 -- ! ------------------------------------------------- Terminals
 tokens :-
 
 -- State: 0 is regex allowed, 1 is / or /= allowed
+-- 2 is a special state for parsing characters inside templates
 
-<0> () ; -- { registerStates lexToken reg divide }
+<0> () ; -- { registerStates lexToken reg divide template }
 
 -- Skip Whitespace
 <reg,divide> $white_char+   { adapt (mkString wsToken) }
@@ -246,6 +256,13 @@
 
 
 
+<reg,divide> "`" @TemplateCharacters "`" { adapt (mkString' NoSubstitutionTemplateToken) }
+<reg,divide> "`" @TemplateCharacters "${" { adapt (mkString' TemplateHeadToken) }
+<template>   @TemplateCharacters "${" { adapt (mkString' TemplateMiddleToken) }
+<template>   @TemplateCharacters "`" { adapt (mkString' TemplateTailToken) }
+
+
+
 -- TODO: Work in SignedInteger
 
 -- DecimalLiteral= {Non Zero Digits}+ '.' {Digit}* ('e' | 'E' ) {Non Zero Digits}+ {Digit}*
@@ -372,8 +389,11 @@
     lt  <- getLastToken
     case lt of
         TailToken {} -> alexEOF
-        _other ->
-            case alexScan inp (classifyToken lt) of
+        _other -> do
+            isInTmpl <- getInTemplate
+            let state = if isInTmpl then template else classifyToken lt
+            setInTemplate False -- the inTemplate condition only needs to last for one token
+            case alexScan inp state of
                 AlexEOF        -> do
                     tok <- tailToken
                     setLastToken tok
@@ -476,6 +496,12 @@
 setComment :: [Token] -> Alex ()
 setComment cs = Alex $ \s -> Right (s{alex_ust=(alex_ust s){comment=cs }}, ())
 
+getInTemplate :: Alex Bool
+getInTemplate = Alex $ \s@AlexState{alex_ust=ust} -> Right (s, inTemplate ust)
+
+setInTemplate :: Bool -> Alex ()
+setInTemplate it = Alex $ \s -> Right (s{alex_ust=(alex_ust s){inTemplate=it}}, ())
+
 alexEOF :: Alex Token
 alexEOF = return (EOFToken tokenPosnEmpty [])
 
@@ -507,6 +533,7 @@
     , ( "case", CaseToken )
     , ( "catch", CatchToken )
 
+    , ( "class", ClassToken )
     , ( "const", ConstToken ) -- not a keyword, nominally a future reserved word, but actually in use
 
     , ( "continue", ContinueToken )
@@ -518,6 +545,7 @@
 
     , ( "enum", EnumToken )  -- not a keyword,  nominally a future reserved word, but actually in use
     , ( "export", ExportToken )
+    , ( "extends", ExtendsToken )
 
     , ( "false", FalseToken ) -- boolean literal
 
@@ -536,6 +564,8 @@
 
     , ( "of", OfToken )
     , ( "return", ReturnToken )
+    , ( "static", StaticToken )
+    , ( "super", SuperToken )
     , ( "switch", SwitchToken )
     , ( "this", ThisToken )
     , ( "throw", ThrowToken )
@@ -546,6 +576,7 @@
     , ( "void", VoidToken )
     , ( "while", WhileToken )
     , ( "with", WithToken )
+    , ( "yield", YieldToken )
     -- TODO: no idea if these are reserved or not, but they are needed
     --       handled in parser, in the Identifier rule
     , ( "as", AsToken ) -- not reserved
@@ -564,12 +595,12 @@
 
 
     -- Future Reserved Words
-    , ( "class",    FutureToken )
+    -- ( "class",    FutureToken ) **** an actual token, used in productions
     -- ( "code",    FutureToken ) **** not any more
     -- ( "const",   FutureToken ) **** an actual token, used in productions
     -- enum                    **** an actual token, used in productions
-    , ( "extends",  FutureToken )
-    , ( "super",    FutureToken )
+    -- ( "extends",  FutureToken ) **** an actual token, used in productions
+    -- ( "super",    FutureToken ) **** an actual token, used in productions
 
 
     -- Strict mode FutureReservedWords
@@ -584,9 +615,9 @@
     , ( "private",     FutureToken )
     , ( "protected",   FutureToken )
     , ( "public",      FutureToken )
-    , ( "static",      FutureToken )
+    -- ( "static",      FutureToken ) **** an actual token, used in productions
     -- ( "strict",     FutureToken )  *** not any more
-    , ( "yield",       FutureToken)
+    -- ( "yield",       FutureToken) **** an actual token, used in productions
    ]
 }
 
diff --git a/src/Language/JavaScript/Parser/LexerUtils.hs b/src/Language/JavaScript/Parser/LexerUtils.hs
--- a/src/Language/JavaScript/Parser/LexerUtils.hs
+++ b/src/Language/JavaScript/Parser/LexerUtils.hs
@@ -14,6 +14,7 @@
     ( StartCode
     , symbolToken
     , mkString
+    , mkString'
     , commentToken
     , wsToken
     , regExToken
@@ -36,6 +37,9 @@
 
 mkString :: (Monad m) => (TokenPosn -> String -> Token) -> TokenPosn -> Int -> String -> m Token
 mkString toToken loc len str = return (toToken loc (take len str))
+
+mkString' :: (Monad m) => (TokenPosn -> String -> [CommentAnnotation] -> Token) -> TokenPosn -> Int -> String -> m Token
+mkString' toToken loc len str = return (toToken loc (take len str) [])
 
 decimalToken :: TokenPosn -> String -> Token
 decimalToken loc str = DecimalToken loc str []
diff --git a/src/Language/JavaScript/Parser/ParserMonad.hs b/src/Language/JavaScript/Parser/ParserMonad.hs
--- a/src/Language/JavaScript/Parser/ParserMonad.hs
+++ b/src/Language/JavaScript/Parser/ParserMonad.hs
@@ -21,12 +21,14 @@
 data AlexUserState = AlexUserState
     { previousToken :: !Token   -- ^the previous token
     , comment :: [Token]        -- ^the previous comment, if any
+    , inTemplate :: Bool        -- ^whether the parser is expecting template characters
     }
 
 alexInitUserState :: AlexUserState
 alexInitUserState = AlexUserState
     { previousToken = initToken
     , comment = []
+    , inTemplate = False
     }
 
 initToken :: Token
diff --git a/src/Language/JavaScript/Parser/Token.hs b/src/Language/JavaScript/Parser/Token.hs
--- a/src/Language/JavaScript/Parser/Token.hs
+++ b/src/Language/JavaScript/Parser/Token.hs
@@ -59,6 +59,7 @@
     | BreakToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | CaseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | CatchToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | ClassToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ConstToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | LetToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ContinueToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
@@ -68,6 +69,7 @@
     | DoToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ElseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | EnumToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | ExtendsToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | FalseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | FinallyToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ForToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
@@ -80,6 +82,8 @@
     | NullToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | OfToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ReturnToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | StaticToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | SuperToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | SwitchToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ThisToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ThrowToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
@@ -89,6 +93,7 @@
     | VarToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | VoidToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | WhileToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | YieldToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ImportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | WithToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
     | ExportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
@@ -152,6 +157,12 @@
     | LeftParenToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation]  }
     | RightParenToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation]  }
     | CondcommentEndToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation]  }
+
+    -- Template literal lexical components
+    | NoSubstitutionTemplateToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | TemplateHeadToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | TemplateMiddleToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
+    | TemplateTailToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
 
     -- Special cases
     | AsToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation]  }
diff --git a/src/Language/JavaScript/Pretty/Printer.hs b/src/Language/JavaScript/Pretty/Printer.hs
--- a/src/Language/JavaScript/Pretty/Printer.hs
+++ b/src/Language/JavaScript/Pretty/Printer.hs
@@ -77,20 +77,25 @@
     (|>) pacc (JSCallExpression       ex lb xs rb)            = pacc |> ex |> lb |> "(" |> xs |> rb |> ")"
     (|>) pacc (JSCallExpressionDot    ex os xs)               = pacc |> ex |> os |> "." |> xs
     (|>) pacc (JSCallExpressionSquare ex als xs ars)          = pacc |> ex |> als |> "[" |> xs |> ars |> "]"
+    (|>) pacc (JSClassExpression      annot n h lb xs rb)     = pacc |> annot |> "class" |> n |> h |> lb |> "{" |> xs |> rb |> "}"
     (|>) pacc (JSCommaExpression      le c re)                = pacc |> le |> c |> "," |> re
     (|>) pacc (JSExpressionBinary     lhs op rhs)             = pacc |> lhs |> op |> rhs
     (|>) pacc (JSExpressionParen      alp e arp)              = pacc |> alp |> "(" |> e |> arp |> ")"
     (|>) pacc (JSExpressionPostfix    xs op)                  = pacc |> xs |> op
     (|>) pacc (JSExpressionTernary    cond h v1 c v2)         = pacc |> cond |> h |> "?" |> v1 |> c |> ":" |> v2
     (|>) pacc (JSFunctionExpression   annot n lb x2s rb x3)   = pacc |> annot |> "function" |> n |> lb |> "(" |> x2s |> rb |> ")" |> x3
+    (|>) pacc (JSGeneratorExpression  annot s n lb x2s rb x3) = pacc |> annot |> "function" |> s |> "*" |> n |> lb |> "(" |> x2s |> rb |> ")" |> x3
     (|>) pacc (JSMemberDot            xs dot n)               = pacc |> xs |> "." |> dot |> n
     (|>) pacc (JSMemberExpression     e lb a rb)              = pacc |> e |> lb |> "(" |> a |> rb |> ")"
     (|>) pacc (JSMemberNew            a lb n rb s)            = pacc |> a |> "new" |> lb |> "(" |> n |> rb |> ")" |> s
     (|>) pacc (JSMemberSquare         xs als e ars)           = pacc |> xs |> als |> "[" |> e |> ars |> "]"
     (|>) pacc (JSNewExpression        n e)                    = pacc |> n |> "new" |> e
     (|>) pacc (JSObjectLiteral        alb xs arb)             = pacc |> alb |> "{" |> xs |> arb |> "}"
+    (|>) pacc (JSTemplateLiteral      t a h ps)               = pacc |> t |> a |> h |> ps
     (|>) pacc (JSUnaryExpression      op x)                   = pacc |> op |> x
     (|>) pacc (JSVarInitExpression    x1 x2)                  = pacc |> x1 |> x2
+    (|>) pacc (JSYieldExpression      y x)                    = pacc |> y |> "yield" |> x
+    (|>) pacc (JSYieldFromExpression  y s x)                  = pacc |> y |> "yield" |> s |> "*" |> x
     (|>) pacc (JSSpreadExpression     a e)                    = pacc |> a |> "..." |> e
 
 instance RenderJS JSArrowParameterList where
@@ -220,6 +225,7 @@
 instance RenderJS JSStatement where
     (|>) pacc (JSStatementBlock alb blk arb s)             = pacc |> alb |> "{" |> blk |> arb |> "}" |> s
     (|>) pacc (JSBreak annot mi s)                         = pacc |> annot |> "break" |> mi |> s
+    (|>) pacc (JSClass annot n h lb xs rb s)               = pacc |> annot |> "class" |> n |> h |> lb |> "{" |> xs |> rb |> "}" |> s
     (|>) pacc (JSContinue annot mi s)                      = pacc |> annot |> "continue" |> mi |> s
     (|>) pacc (JSConstant annot xs s)                      = pacc |> annot |> "const" |> xs |> s
     (|>) pacc (JSDoWhile ad x1 aw alb x2 arb x3)           = pacc |> ad |> "do" |> x1 |> aw |> "while" |> alb |> "(" |> x2 |> arb |> ")" |> x3
@@ -231,9 +237,13 @@
     (|>) 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 (JSForConst af alb v x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> "const" |> v |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4
+    (|>) pacc (JSForConstIn af alb v x1 i x2 arb x3)         = pacc |> af |> "for" |> alb |> "(" |> "const" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3
+    (|>) pacc (JSForConstOf af alb v x1 i x2 arb x3)         = pacc |> af |> "for" |> alb |> "(" |> "const" |> 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 (JSGenerator af as n alb x2s arb x3 s)       = pacc |> af |> "function" |> as |> "*" |> 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
     (|>) pacc (JSLabelled l c v)                           = pacc |> l |> c |> ":" |> v
@@ -264,13 +274,20 @@
     (|>) pacc (JSBlock alb ss arb) = pacc |> alb |> "{" |> ss |> arb |> "}"
 
 instance RenderJS JSObjectProperty where
-    (|>) pacc (JSPropertyAccessor     s n alp ps arp b)       = pacc |> s |> n |> alp |> "(" |> ps |> arp |> ")" |> b
     (|>) pacc (JSPropertyNameandValue n c vs)                 = pacc |> n |> c |> ":" |> vs
+    (|>) pacc (JSPropertyIdentRef     a s)                    = pacc |> a |> s
+    (|>) pacc (JSObjectMethod         m)                      = pacc |> m
 
+instance RenderJS JSMethodDefinition where
+    (|>) pacc (JSMethodDefinition          n alp ps arp b)   = pacc |> n |> alp |> "(" |> ps |> arp |> ")" |> b
+    (|>) pacc (JSGeneratorMethodDefinition s n alp ps arp b) = pacc |> s |> "*" |> n |> alp |> "(" |> ps |> arp |> ")" |> b
+    (|>) pacc (JSPropertyAccessor          s n alp ps arp b) = pacc |> s |> n |> alp |> "(" |> ps |> arp |> ")" |> b
+
 instance RenderJS JSPropertyName where
     (|>) pacc (JSPropertyIdent a s)  = pacc |> a |> s
     (|>) pacc (JSPropertyString a s) = pacc |> a |> s
     (|>) pacc (JSPropertyNumber a s) = pacc |> a |> s
+    (|>) pacc (JSPropertyComputed lb x rb) = pacc |> lb |> "[" |> x |> rb |> "]"
 
 instance RenderJS JSAccessor where
     (|>) pacc (JSAccessorGet annot) = pacc |> annot |> "get"
@@ -285,6 +302,7 @@
 
 instance RenderJS JSImportDeclaration where
     (|>) pacc (JSImportDeclaration imp from annot) = pacc |> imp |> from |> annot
+    (|>) pacc (JSImportDeclarationBare annot m s) = pacc |> annot |> m |> s
 
 instance RenderJS JSImportClause where
     (|>) pacc (JSImportClauseDefault x) = pacc |> x
@@ -339,5 +357,23 @@
 instance RenderJS JSVarInitializer where
     (|>) pacc (JSVarInit a x) = pacc |> a |> "=" |> x
     (|>) pacc JSVarInitNone   = pacc
+
+instance RenderJS [JSTemplatePart] where
+    (|>) = foldl' (|>)
+
+instance RenderJS JSTemplatePart where
+    (|>) pacc (JSTemplatePart e a s) = pacc |> e |> a |> s
+
+instance RenderJS JSClassHeritage where
+    (|>) pacc (JSExtends a e) = pacc |> a |> "extends" |> e
+    (|>) pacc JSExtendsNone   = pacc
+
+instance RenderJS [JSClassElement] where
+    (|>) = foldl' (|>)
+
+instance RenderJS JSClassElement where
+    (|>) pacc (JSClassInstanceMethod m) = pacc |> m
+    (|>) pacc (JSClassStaticMethod a m) = pacc |> a |> "static" |> m
+    (|>) pacc (JSClassSemi a)           = pacc |> a |> ";"
 
 -- EOF
diff --git a/src/Language/JavaScript/Process/Minify.hs b/src/Language/JavaScript/Process/Minify.hs
--- a/src/Language/JavaScript/Process/Minify.hs
+++ b/src/Language/JavaScript/Process/Minify.hs
@@ -41,6 +41,7 @@
 fixStmt :: JSAnnot -> JSSemi -> JSStatement -> JSStatement
 fixStmt a s (JSStatementBlock _lb ss _rb _) = fixStatementBlock a s ss
 fixStmt a s (JSBreak _ i _) = JSBreak a (fixSpace i) s
+fixStmt a s (JSClass _ n h _ ms _ _) = JSClass a (fixSpace n) (fixSpace h) emptyAnnot (fixEmpty ms) emptyAnnot s
 fixStmt a s (JSConstant _ ss _) = JSConstant a (fixVarList ss) s
 fixStmt a s (JSContinue _ i _) = JSContinue a (fixSpace i) s
 fixStmt a s (JSDoWhile _ st _ _ e _ _) = JSDoWhile a (mkStatementBlock noSemi st) emptyAnnot emptyAnnot (fixEmpty e) emptyAnnot s
@@ -51,9 +52,13 @@
 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 (JSForConst _ _ _ el1 _ el2 _ el3 _ st) = JSForConst a emptyAnnot spaceAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st)
+fixStmt a s (JSForConstIn _ _ _ e1 op e2 _ st) = JSForConstIn a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st)
+fixStmt a s (JSForConstOf _ _ _ e1 op e2 _ st) = JSForConstOf 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 (JSGenerator _ _ n _ ps _ blk _) = JSGenerator a emptyAnnot (fixEmpty 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)
 fixStmt a s (JSIfElse _ _ e _ st _ sf) = JSIfElse a emptyAnnot (fixEmpty e) emptyAnnot (mkStatementBlock noSemi st) emptyAnnot (fixIfElseBlock spaceAnnot s sf)
@@ -153,20 +158,25 @@
     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)
     fix a (JSCallExpressionSquare ex _ xs _)          = JSCallExpressionSquare (fix a ex) emptyAnnot (fixEmpty xs) emptyAnnot
+    fix a (JSClassExpression      _ n h _ ms _)       = JSClassExpression a (fixSpace n) (fixSpace h) emptyAnnot (fixEmpty ms) emptyAnnot
     fix a (JSCommaExpression      le _ re)            = JSCommaExpression (fix a le) emptyAnnot (fixEmpty re)
     fix a (JSExpressionBinary     lhs op rhs)         = fixBinOpExpression a op lhs rhs
     fix _ (JSExpressionParen      _ e _)              = JSExpressionParen emptyAnnot (fixEmpty e) emptyAnnot
     fix a (JSExpressionPostfix    e op)               = JSExpressionPostfix (fix a e) (fixEmpty op)
     fix a (JSExpressionTernary    cond _ v1 _ v2)     = JSExpressionTernary (fix a cond) emptyAnnot (fixEmpty v1) emptyAnnot (fixEmpty v2)
     fix a (JSFunctionExpression   _ n _ x2s _ x3)     = JSFunctionExpression a (fixSpace n) emptyAnnot (fixEmpty x2s) emptyAnnot (fixEmpty x3)
+    fix a (JSGeneratorExpression  _ _ n _ x2s _ x3)   = JSGeneratorExpression a emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty x2s) emptyAnnot (fixEmpty x3)
     fix a (JSMemberDot            xs _ n)             = JSMemberDot (fix a xs) emptyAnnot (fixEmpty n)
     fix a (JSMemberExpression     e _ args _)         = JSMemberExpression (fix a e) emptyAnnot (fixEmpty args) emptyAnnot
     fix a (JSMemberNew            _ n _ s _)          = JSMemberNew a (fix spaceAnnot n) emptyAnnot (fixEmpty s) emptyAnnot
     fix a (JSMemberSquare         xs _ e _)           = JSMemberSquare (fix a xs) emptyAnnot (fixEmpty e) emptyAnnot
     fix a (JSNewExpression        _ e)                = JSNewExpression a (fixSpace e)
     fix _ (JSObjectLiteral        _ xs _)             = JSObjectLiteral emptyAnnot (fixEmpty xs) emptyAnnot
+    fix a (JSTemplateLiteral      t _ s ps)           = JSTemplateLiteral (fmap (fix a) t) emptyAnnot s (map fixEmpty ps)
     fix a (JSUnaryExpression      op x)               = let (ta, fop) = fixUnaryOp a op in JSUnaryExpression fop (fix ta x)
     fix a (JSVarInitExpression    x1 x2)              = JSVarInitExpression (fix a x1) (fixEmpty x2)
+    fix a (JSYieldExpression      _ x)                = JSYieldExpression a (fixSpace x)
+    fix a (JSYieldFromExpression  _ _ x)              = JSYieldFromExpression a emptyAnnot (fixEmpty x)
     fix a (JSSpreadExpression     _ e)                = JSSpreadExpression a (fixEmpty e)
 
 instance MinifyJS JSArrowParameterList where
@@ -289,6 +299,7 @@
                     JSImportClauseNamed {} -> emptyAnnot
                     JSImportClauseDefaultNameSpace {} -> spaceAnnot
                     JSImportClauseDefaultNamed {} -> emptyAnnot
+    fix a (JSImportDeclarationBare _ m _) = JSImportDeclarationBare a m noSemi
 
 instance MinifyJS JSImportClause where
     fix _ (JSImportClauseDefault n) = JSImportClauseDefault (fixSpace n)
@@ -352,13 +363,20 @@
 
 
 instance MinifyJS JSObjectProperty where
-    fix a (JSPropertyAccessor     s n _ ps _ b) = JSPropertyAccessor (fix a s) (fixSpace n) emptyAnnot (map fixEmpty ps) emptyAnnot (fixEmpty b)
     fix a (JSPropertyNameandValue n _ vs)       = JSPropertyNameandValue (fix a n) emptyAnnot (map fixEmpty vs)
+    fix a (JSPropertyIdentRef     _ s)          = JSPropertyIdentRef a s
+    fix a (JSObjectMethod         m)            = JSObjectMethod (fix a m)
 
+instance MinifyJS JSMethodDefinition where
+    fix a (JSMethodDefinition          n _ ps _ b)   = JSMethodDefinition                     (fix a n)    emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b)
+    fix _ (JSGeneratorMethodDefinition _ n _ ps _ b) = JSGeneratorMethodDefinition emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b)
+    fix a (JSPropertyAccessor          s n _ ps _ b) = JSPropertyAccessor          (fix a s)  (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b)
+
 instance MinifyJS JSPropertyName where
     fix a (JSPropertyIdent _ s)  = JSPropertyIdent a s
     fix a (JSPropertyString _ s) = JSPropertyString a s
     fix a (JSPropertyNumber _ s) = JSPropertyNumber a s
+    fix _ (JSPropertyComputed _ x _) = JSPropertyComputed emptyAnnot (fixEmpty x) emptyAnnot
 
 instance MinifyJS JSAccessor where
     fix a (JSAccessorGet _) = JSAccessorGet a
@@ -393,6 +411,22 @@
 instance MinifyJS JSVarInitializer where
     fix a (JSVarInit _ x) = JSVarInit a (fix emptyAnnot x)
     fix _ JSVarInitNone = JSVarInitNone
+
+
+instance MinifyJS JSTemplatePart where
+    fix _ (JSTemplatePart e _ s) = JSTemplatePart (fixEmpty e) emptyAnnot s
+
+
+instance MinifyJS JSClassHeritage where
+    fix _ JSExtendsNone = JSExtendsNone
+    fix a (JSExtends _ e) = JSExtends a (fixSpace e)
+
+
+instance MinifyJS [JSClassElement] where
+    fix _ [] = []
+    fix a (JSClassInstanceMethod m:t) = JSClassInstanceMethod (fix a m) : fixEmpty t
+    fix a (JSClassStaticMethod _ m:t) = JSClassStaticMethod a (fixSpace m) : fixEmpty t
+    fix a (JSClassSemi _:t) = fix a t
 
 
 spaceAnnot :: JSAnnot
diff --git a/test/Test/Language/Javascript/ExpressionParser.hs b/test/Test/Language/Javascript/ExpressionParser.hs
--- a/test/Test/Language/Javascript/ExpressionParser.hs
+++ b/test/Test/Language/Javascript/ExpressionParser.hs
@@ -51,11 +51,20 @@
         testExpr "{x:1}"        `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1']]))"
         testExpr "{x:1,y:2}"    `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1'],JSPropertyNameandValue (JSIdentifier 'y') [JSDecimal '2']]))"
         testExpr "{x:1,}"       `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1'],JSComma]))"
+        testExpr "{yield:1}"    `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'yield') [JSDecimal '1']]))"
+        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 "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 "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']]))"
+        testExpr "{ a(x,y) {}, 'blah blah'() {} }" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSMethodDefinition (JSIdentifier ''blah blah'') () (JSBlock [])]))"
+        testExpr "{[x]() {}}"   `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSMethodDefinition (JSPropertyComputed (JSIdentifier 'x')) () (JSBlock [])]))"
+        testExpr "{*a(x,y) {yield y;}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSGeneratorMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSYieldExpression (JSIdentifier 'y'),JSSemicolon])]))"
+        testExpr "{*[x]({y},...z) {}}"  `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSGeneratorMethodDefinition (JSPropertyComputed (JSIdentifier 'x')) (JSObjectLiteral [JSPropertyIdentRef 'y'],JSSpreadExpression (JSIdentifier 'z')) (JSBlock [])]))"
 
     it "unary expression" $ do
         testExpr "delete y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('delete',JSIdentifier 'y')))"
@@ -120,15 +129,33 @@
         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 "generator expression" $ do
+        testExpr "function*(){}"        `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' () (JSBlock [])))"
+        testExpr "function*(a){}"       `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' (JSIdentifier 'a') (JSBlock [])))"
+        testExpr "function*(a,b){}"     `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))"
+        testExpr "function*(a,...b){}"  `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' (JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b')) (JSBlock [])))"
+        testExpr "function*f(){}"       `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' () (JSBlock [])))"
+        testExpr "function*f(a){}"      `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' (JSIdentifier 'a') (JSBlock [])))"
+        testExpr "function*f(a,b){}"    `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))"
+        testExpr "function*f(a,...b){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' (JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b')) (JSBlock [])))"
+
     it "member expression" $ do
         testExpr "x[y]"         `shouldBe` "Right (JSAstExpression (JSMemberSquare (JSIdentifier 'x',JSIdentifier 'y')))"
         testExpr "x[y][z]"      `shouldBe` "Right (JSAstExpression (JSMemberSquare (JSMemberSquare (JSIdentifier 'x',JSIdentifier 'y'),JSIdentifier 'z')))"
@@ -145,6 +172,28 @@
 
     it "spread expression" $
         testExpr "... x"        `shouldBe` "Right (JSAstExpression (JSSpreadExpression (JSIdentifier 'x')))"
+
+    it "template literal" $ do
+        testExpr "``"            `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'``',[])))"
+        testExpr "`$`"           `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`$`',[])))"
+        testExpr "`$\\n`"        `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`$\\n`',[])))"
+        testExpr "`\\${x}`"      `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`\\${x}`',[])))"
+        testExpr "`$ {x}`"       `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`$ {x}`',[])))"
+        testExpr "`\n\n`"        `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`\n\n`',[])))"
+        testExpr "`${x+y} ${z}`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`${',[(JSExpressionBinary ('+',JSIdentifier 'x',JSIdentifier 'y'),'} ${'),(JSIdentifier 'z','}`')])))"
+        testExpr "`<${x} ${y}>`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`<${',[(JSIdentifier 'x','} ${'),(JSIdentifier 'y','}>`')])))"
+        testExpr "tag `xyz`"     `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((JSIdentifier 'tag'),'`xyz`',[])))"
+        testExpr "tag()`xyz`"    `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((JSMemberExpression (JSIdentifier 'tag',JSArguments ())),'`xyz`',[])))"
+
+    it "yield" $ do
+        testExpr "yield"       `shouldBe` "Right (JSAstExpression (JSYieldExpression ()))"
+        testExpr "yield a + b" `shouldBe` "Right (JSAstExpression (JSYieldExpression (JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b'))))"
+        testExpr "yield* g()"  `shouldBe` "Right (JSAstExpression (JSYieldFromExpression (JSMemberExpression (JSIdentifier 'g',JSArguments ()))))"
+
+    it "class expression" $ do
+        testExpr "class Foo extends Bar { a(x,y) {} *b() {} }" `shouldBe` "Right (JSAstExpression (JSClassExpression 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSGeneratorMethodDefinition (JSIdentifier 'b') () (JSBlock [])]))"
+        testExpr "class { static get [a]() {}; }" `shouldBe` "Right (JSAstExpression (JSClassExpression '' () [JSClassStaticMethod (JSPropertyAccessor JSAccessorGet (JSPropertyComputed (JSIdentifier 'a')) () (JSBlock [])),JSClassSemi]))"
+        testExpr "class Foo extends Bar { a(x,y) { super(x); } }" `shouldBe` "Right (JSAstExpression (JSClassExpression 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSCallExpression (JSLiteral 'super',JSArguments (JSIdentifier 'x')),JSSemicolon])]))"
 
 
 testExpr :: String -> String
diff --git a/test/Test/Language/Javascript/Minify.hs b/test/Test/Language/Javascript/Minify.hs
--- a/test/Test/Language/Javascript/Minify.hs
+++ b/test/Test/Language/Javascript/Minify.hs
@@ -41,6 +41,11 @@
         minifyExpr " { b : 2 , } " `shouldBe` "{b:2}"
         minifyExpr " { c : 3 , d : 4 , } " `shouldBe` "{c:3,d:4}"
         minifyExpr " { 'str' : true , 42 : false , } " `shouldBe` "{'str':true,42:false}"
+        minifyExpr " { x , } " `shouldBe` "{x}"
+        minifyExpr " { [ x + y ] : 1 } " `shouldBe` "{[x+y]:1}"
+        minifyExpr " { a ( x, y ) { } } " `shouldBe` "{a(x,y){}}"
+        minifyExpr " { [ x + y ] ( ) { } } " `shouldBe` "{[x+y](){}}"
+        minifyExpr " { * a ( x, y ) { } } " `shouldBe` "{*a(x,y){}}"
 
     it "parentheses" $ do
         minifyExpr " ( 'hello' ) " `shouldBe` "('hello')"
@@ -105,13 +110,26 @@
         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 "generator" $ do
+        minifyExpr " function * ( ) { } " `shouldBe` "function*(){}"
+        minifyExpr " function * ( a ) { yield * a ; } " `shouldBe` "function*(a){yield*a}"
+        minifyExpr " function * ( a , b ) { yield a + b ; } " `shouldBe` "function*(a,b){yield a+b}"
+
     it "calls" $ do
         minifyExpr " a ( ) " `shouldBe` "a()"
         minifyExpr " b ( ) ( ) " `shouldBe` "b()()"
@@ -121,6 +139,7 @@
     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'"
@@ -136,7 +155,19 @@
     it "spread exporession" $
         minifyExpr " ... x " `shouldBe` "...x"
 
+    it "template literal" $ do
+        minifyExpr " ` a + b + ${ c + d } + ... ` " `shouldBe` "` a + b + ${c+d} + ... `"
+        minifyExpr " tagger () ` a + b ` " `shouldBe` "tagger()` a + b `"
 
+    it "class" $ do
+        minifyExpr " class   Foo   {\n  a() {\n    return 0;\n  };\n  static [ b ] ( x ) {}\n } " `shouldBe` "class Foo{a(){return 0}static[b](x){}}"
+        minifyExpr " class { static get a() { return 0; } static set a(v) {} } " `shouldBe` "class{static get a(){return 0}static set a(v){}}"
+        minifyExpr " class   { ; ; ; } " `shouldBe` "class{}"
+        minifyExpr " class Foo extends Bar {} " `shouldBe` "class Foo extends Bar{}"
+        minifyExpr " class extends (getBase()) {} " `shouldBe` "class extends(getBase()){}"
+        minifyExpr " class extends [ Bar1, Bar2 ][getBaseIndex()] {} " `shouldBe` "class extends[Bar1,Bar2][getBaseIndex()]{}"
+
+
 testMinifyStmt :: Spec
 testMinifyStmt = describe "Minify statements:" $ do
     forM_ [ "break", "continue", "return" ] $ \kw ->
@@ -184,6 +215,9 @@
         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 (const x ; y ; z) { } " `shouldBe` "for(const x;y;z){}"
+        minifyStmt " for ( const x in 5 ) { foo ( x ); y ++ ; } ;" `shouldBe` "for(const x in 5){foo(x);y++}"
+        minifyStmt " for ( const x of 5 ) { foo ( x ); y ++ ; } ;" `shouldBe` "for(const 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
@@ -194,7 +228,16 @@
         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 "generator" $ do
+        minifyStmt " function * f ( ) { } ; " `shouldBe` "function*f(){}"
+        minifyStmt " function * f ( a ) { yield * a ; } ; " `shouldBe` "function*f(a){yield*a}"
+        minifyStmt " function * f ( a , b ) { yield a + b ; } ; " `shouldBe` "function*f(a,b){yield a+b}"
+
     it "with" $ do
         minifyStmt " with ( x ) { } ; " `shouldBe` "with(x){}"
         minifyStmt " with ({ first: 'John' }) { foo ('Hello '+first); }" `shouldBe` "with({first:'John'})foo('Hello '+first)"
@@ -225,10 +268,16 @@
         minifyStmt " var d = 1, x = 2 ; " `shouldBe` "var d=1,x=2"
         minifyStmt " let c = 1 ; " `shouldBe` "let c=1"
         minifyStmt " let d = 1, x = 2 ; " `shouldBe` "let d=1,x=2"
+        minifyStmt " const { a : [ b , c ] } = d; " `shouldBe` "const{a:[b,c]}=d"
 
     it "string concatenation" $
         minifyStmt " f (\"ab\"+\"cd\") " `shouldBe` "f('abcd')"
 
+    it "class" $ do
+        minifyStmt " class   Foo   {\n  a() {\n    return 0;\n  }\n  static b ( x ) {}\n } " `shouldBe` "class Foo{a(){return 0}static b(x){}}"
+        minifyStmt " class Foo extends Bar {} " `shouldBe` "class Foo extends Bar{}"
+        minifyStmt " class Foo extends (getBase()) {} " `shouldBe` "class Foo extends(getBase()){}"
+        minifyStmt " class Foo extends [ Bar1, Bar2 ][getBaseIndex()] {} " `shouldBe` "class Foo extends[Bar1,Bar2][getBaseIndex()]{}"
 
 testMinifyProg :: Spec
 testMinifyProg = describe "Minify programs:" $ do
@@ -267,6 +316,7 @@
         minifyModule "import  def, * as foo  from   \"mod\"  ; " `shouldBe` "import def,* as foo from\"mod\""
         minifyModule "import  { baz,  bar as   foo }  from   \"mod\"  ; " `shouldBe` "import{baz,bar as foo}from\"mod\""
         minifyModule "import  def, { baz,  bar as   foo }  from   \"mod\"  ; " `shouldBe` "import def,{baz,bar as foo}from\"mod\""
+        minifyModule "import     \"mod\"  ; " `shouldBe` "import\"mod\""
 
     it "export" $ do
         minifyModule " export { } ; " `shouldBe` "export{}"
@@ -276,6 +326,7 @@
         minifyModule " export { } from \"mod\" ; " `shouldBe` "export{}from\"mod\""
         minifyModule " export const a = 1 ; " `shouldBe` "export const a=1"
         minifyModule " export function f () {  } ; " `shouldBe` "export function f(){}"
+        minifyModule " export function * f () {  } ; " `shouldBe` "export function*f(){}"
 
 -- -----------------------------------------------------------------------------
 -- Minify test helpers.
diff --git a/test/Test/Language/Javascript/ProgramParser.hs b/test/Test/Language/Javascript/ProgramParser.hs
--- a/test/Test/Language/Javascript/ProgramParser.hs
+++ b/test/Test/Language/Javascript/ProgramParser.hs
@@ -73,15 +73,15 @@
 
     it "programs" $ do
         testProg "newlines=spaces.match(/\\n/g)" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'newlines',JSMemberExpression (JSMemberDot (JSIdentifier 'spaces',JSIdentifier 'match'),JSArguments (JSRegEx '/\\n/g')))])"
-        testProg "Animal=function(){return this.name};" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'Animal',JSFunctionExpression '' () (JSBlock [JSReturn JSMemberDot (JSLiteral 'this',JSIdentifier 'name') ]))),JSSemicolon])"
-        testProg "$(img).click(function(){alert('clicked!')});" `shouldBe` "Right (JSAstProgram [JSCallExpression (JSCallExpressionDot (JSMemberExpression (JSIdentifier '$',JSArguments (JSIdentifier 'img')),JSIdentifier 'click'),JSArguments (JSFunctionExpression '' () (JSBlock [JSMethodCall (JSIdentifier 'alert',JSArguments (JSStringLiteral 'clicked!'))])))),JSSemicolon])"
-        testProg "function() {\nz = function z(o) {\nreturn r;\n};}" `shouldBe` "Right (JSAstProgram [JSFunctionExpression '' () (JSBlock [JSOpAssign ('=',JSIdentifier 'z',JSFunctionExpression 'z' (JSIdentifier 'o') (JSBlock [JSReturn JSIdentifier 'r' JSSemicolon]))),JSSemicolon]))])"
-        testProg "function() {\nz = function /*z*/(o) {\nreturn r;\n};}" `shouldBe` "Right (JSAstProgram [JSFunctionExpression '' () (JSBlock [JSOpAssign ('=',JSIdentifier 'z',JSFunctionExpression '' (JSIdentifier 'o') (JSBlock [JSReturn JSIdentifier 'r' JSSemicolon]))),JSSemicolon]))])"
+        testProg "Animal=function(){return this.name};" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'Animal',JSFunctionExpression '' () (JSBlock [JSReturn JSMemberDot (JSLiteral 'this',JSIdentifier 'name') ])),JSSemicolon])"
+        testProg "$(img).click(function(){alert('clicked!')});" `shouldBe` "Right (JSAstProgram [JSCallExpression (JSCallExpressionDot (JSMemberExpression (JSIdentifier '$',JSArguments (JSIdentifier 'img')),JSIdentifier 'click'),JSArguments (JSFunctionExpression '' () (JSBlock [JSMethodCall (JSIdentifier 'alert',JSArguments (JSStringLiteral 'clicked!'))]))),JSSemicolon])"
+        testProg "function() {\nz = function z(o) {\nreturn r;\n};}" `shouldBe` "Right (JSAstProgram [JSFunctionExpression '' () (JSBlock [JSOpAssign ('=',JSIdentifier 'z',JSFunctionExpression 'z' (JSIdentifier 'o') (JSBlock [JSReturn JSIdentifier 'r' JSSemicolon])),JSSemicolon])])"
+        testProg "function() {\nz = function /*z*/(o) {\nreturn r;\n};}" `shouldBe` "Right (JSAstProgram [JSFunctionExpression '' () (JSBlock [JSOpAssign ('=',JSIdentifier 'z',JSFunctionExpression '' (JSIdentifier 'o') (JSBlock [JSReturn JSIdentifier 'r' JSSemicolon])),JSSemicolon])])"
         testProg "{zero}\nget;two\n{three\nfour;set;\n{\nsix;{seven;}\n}\n}" `shouldBe` "Right (JSAstProgram [JSStatementBlock [JSIdentifier 'zero'],JSIdentifier 'get',JSSemicolon,JSIdentifier 'two',JSStatementBlock [JSIdentifier 'three',JSIdentifier 'four',JSSemicolon,JSIdentifier 'set',JSSemicolon,JSStatementBlock [JSIdentifier 'six',JSSemicolon,JSStatementBlock [JSIdentifier 'seven',JSSemicolon]]]])"
         testProg "{zero}\none1;two\n{three\nfour;five;\n{\nsix;{seven;}\n}\n}" `shouldBe` "Right (JSAstProgram [JSStatementBlock [JSIdentifier 'zero'],JSIdentifier 'one1',JSSemicolon,JSIdentifier 'two',JSStatementBlock [JSIdentifier 'three',JSIdentifier 'four',JSSemicolon,JSIdentifier 'five',JSSemicolon,JSStatementBlock [JSIdentifier 'six',JSSemicolon,JSStatementBlock [JSIdentifier 'seven',JSSemicolon]]]])"
         testProg "v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));"   `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'v',JSExpressionBinary ('in',JSMemberExpression (JSIdentifier 'getValue',JSArguments (JSMemberExpression (JSIdentifier 'execute',JSArguments (JSMemberSquare (JSIdentifier 'n',JSDecimal '0'),JSIdentifier 'x')))),JSMemberExpression (JSIdentifier 'getValue',JSArguments (JSMemberExpression (JSIdentifier 'execute',JSArguments (JSMemberSquare (JSIdentifier 'n',JSDecimal '1'),JSIdentifier 'x')))))),JSSemicolon])"
         testProg "function Animal(name){if(!name)throw new Error('Must specify an animal name');this.name=name};Animal.prototype.toString=function(){return this.name};o=new Animal(\"bob\");o.toString()==\"bob\""
-                                    `shouldBe` "Right (JSAstProgram [JSFunction 'Animal' (JSIdentifier 'name') (JSBlock [JSIf (JSUnaryExpression ('!',JSIdentifier 'name')) (JSThrow (JSMemberNew (JSIdentifier 'Error',JSArguments (JSStringLiteral 'Must specify an animal name')))),JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'name'),JSIdentifier 'name')]),JSOpAssign ('=',JSMemberDot (JSMemberDot (JSIdentifier 'Animal',JSIdentifier 'prototype'),JSIdentifier 'toString'),JSFunctionExpression '' () (JSBlock [JSReturn JSMemberDot (JSLiteral 'this',JSIdentifier 'name') ]))),JSSemicolon,JSOpAssign ('=',JSIdentifier 'o',JSMemberNew (JSIdentifier 'Animal',JSArguments (JSStringLiteral \"bob\"))),JSSemicolon,JSExpressionBinary ('==',JSMemberExpression (JSMemberDot (JSIdentifier 'o',JSIdentifier 'toString'),JSArguments ()),JSStringLiteral \"bob\")])"
+                                    `shouldBe` "Right (JSAstProgram [JSFunction 'Animal' (JSIdentifier 'name') (JSBlock [JSIf (JSUnaryExpression ('!',JSIdentifier 'name')) (JSThrow (JSMemberNew (JSIdentifier 'Error',JSArguments (JSStringLiteral 'Must specify an animal name')))),JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'name'),JSIdentifier 'name')]),JSOpAssign ('=',JSMemberDot (JSMemberDot (JSIdentifier 'Animal',JSIdentifier 'prototype'),JSIdentifier 'toString'),JSFunctionExpression '' () (JSBlock [JSReturn JSMemberDot (JSLiteral 'this',JSIdentifier 'name') ])),JSSemicolon,JSOpAssign ('=',JSIdentifier 'o',JSMemberNew (JSIdentifier 'Animal',JSArguments (JSStringLiteral \"bob\"))),JSSemicolon,JSExpressionBinary ('==',JSMemberExpression (JSMemberDot (JSIdentifier 'o',JSIdentifier 'toString'),JSArguments ()),JSStringLiteral \"bob\")])"
 
 
 testProg :: String -> String
diff --git a/test/Test/Language/Javascript/RoundTrip.hs b/test/Test/Language/Javascript/RoundTrip.hs
--- a/test/Test/Language/Javascript/RoundTrip.hs
+++ b/test/Test/Language/Javascript/RoundTrip.hs
@@ -39,9 +39,15 @@
     it "object literals" $ do
         testRT "/*a*/{/*b*/}"
         testRT "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/}"
+        testRT "/*a*/{/*b*/x/*c*/}"
+        testRT "/*a*/{/*b*/of/*c*/}"
         testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/}"
         testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/,/*j*/z/*k*/:/*l*/3/*m*/}"
         testRT "a=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/}"
+        testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/:/*h*/1/*i*/}"
+        testRT "/*a*/{/*b*/a/*c*/(/*d*/x/*e*/,/*f*/y/*g*/)/*h*/{/*i*/}/*j*/}"
+        testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/(/*h*/)/*i*/{/*j*/}/*k*/}"
+        testRT "/*a*/{/*b*/*/*c*/a/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/}"
 
     it "miscellaneous" $ do
         testRT "/*a*/(/*b*/56/*c*/)"
@@ -61,6 +67,7 @@
         testRT "/*a*/x/*b*/>=/*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 "x = { set foo(/*a*/[/*b*/a/*c*/,/*d*/b/*e*/]/*f*/=/*g*/y/*h*/) {} }"
         testRT "... /*a*/ x"
 
         testRT "a => {}"
@@ -68,8 +75,26 @@
         testRT "(a, b) => {}"
         testRT "(a, b) => a + b"
         testRT "() => { 42 }"
+        testRT "(...a) => a"
+        testRT "(a=1, b=2) => a + b"
+        testRT "([a, b]) => a + b"
+        testRT "({a, b}) => a + b"
 
+        testRT "function (...a) {}"
+        testRT "function (a=1, b=2) {}"
+        testRT "function ([a, ...b]) {}"
+        testRT "function ({a, b: c}) {}"
 
+        testRT "/*a*/function/*b*/*/*c*/f/*d*/(/*e*/)/*f*/{/*g*/yield/*h*/a/*i*/}/*j*/"
+        testRT "function*(a, b) { yield a ; yield b ; }"
+
+        testRT "/*a*/`<${/*b*/x/*c*/}>`/*d*/"
+        testRT "`\\${}`"
+        testRT "`\n\n`"
+        testRT "{}+``"
+        -- ^ https://github.com/erikd/language-javascript/issues/104
+
+
     it "statement" $ do
         testRT "if (1) {}"
         testRT "if (1) {} else {}"
@@ -87,6 +112,9 @@
         testRT "for(let x;y;z){}"
         testRT "for(let x in 5){}"
         testRT "for(let x of 5){}"
+        testRT "for(const x;y;z){}"
+        testRT "for(const x in 5){}"
+        testRT "for(const x of 5){}"
         testRT "for(x of 5){}"
         testRT "for(var x of 5){}"
         testRT "var x=1;"
@@ -105,6 +133,9 @@
         testRT "switch (x) {default:break;}"
         testRT "switch (x) {default:\ncase 1:break;}"
         testRT "var x=1;let y=2;"
+        testRT "var [x, y]=z;"
+        testRT "let {x: [y]}=z;"
+        testRT "let yield=1"
 
     it "module" $ do
         testRTModule "import  def  from 'mod'"
@@ -121,6 +152,8 @@
         testRTModule "export   {}  from \"mod\";"
         testRTModule "export const a = 1 ; "
         testRTModule "export function f () {  } ; "
+        testRTModule "export function * f () {  } ; "
+        testRTModule "export   class Foo\nextends Bar\n{ get a () { return 1 ; }  static b ( x,y ) {} ; }   ; "
 
 
 testRT :: String -> Expectation
diff --git a/test/Test/Language/Javascript/StatementParser.hs b/test/Test/Language/Javascript/StatementParser.hs
--- a/test/Test/Language/Javascript/StatementParser.hs
+++ b/test/Test/Language/Javascript/StatementParser.hs
@@ -54,6 +54,9 @@
         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(const x;y;z){}"   `shouldBe` "Right (JSAstStatement (JSForConst (JSVarInitExpression (JSIdentifier 'x') ) (JSIdentifier 'y') (JSIdentifier 'z') (JSStatementBlock [])))"
+        testStmt "for(const x in 5){}"  `shouldBe` "Right (JSAstStatement (JSForConstIn (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))"
+        testStmt "for(const x of 5){}"  `shouldBe` "Right (JSAstStatement (JSForConstOf (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 [])))"
 
@@ -61,6 +64,8 @@
         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'])))"
         testStmt "let x=1,y=2;"     `shouldBe` "Right (JSAstStatement (JSLet (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1'],JSVarInitExpression (JSIdentifier 'y') [JSDecimal '2'])))"
+        testStmt "var [a,b]=x"      `shouldBe` "Right (JSAstStatement (JSVariable (JSVarInitExpression (JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b']) [JSIdentifier 'x'])))"
+        testStmt "const {a:b}=x"    `shouldBe` "Right (JSAstStatement (JSConstant (JSVarInitExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'a') [JSIdentifier 'b']]) [JSIdentifier 'x'])))"
 
     it "break" $ do
         testStmt "break;"       `shouldBe` "Right (JSAstStatement (JSBreak,JSSemicolon))"
@@ -104,6 +109,26 @@
         testStmt "try{}catch(a){}catch(b){}finally{}"   `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a',JSBlock []),JSCatch (JSIdentifier 'b',JSBlock [])],JSFinally (JSBlock []))))"
         testStmt "try{}catch(a){}catch(b){}"            `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a',JSBlock []),JSCatch (JSIdentifier 'b',JSBlock [])],JSFinally ())))"
         testStmt "try{}catch(a if true){}catch(b){}"    `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a') if JSLiteral 'true' (JSBlock []),JSCatch (JSIdentifier 'b',JSBlock [])],JSFinally ())))"
+
+    it "function" $ do
+        testStmt "function x(){}"     `shouldBe` "Right (JSAstStatement (JSFunction 'x' () (JSBlock [])))"
+        testStmt "function x(a){}"    `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSIdentifier 'a') (JSBlock [])))"
+        testStmt "function x(a,b){}"  `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))"
+        testStmt "function x(...a){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSSpreadExpression (JSIdentifier 'a')) (JSBlock [])))"
+        testStmt "function x(a=1){}"  `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSOpAssign ('=',JSIdentifier 'a',JSDecimal '1')) (JSBlock [])))"
+        testStmt "function x([a]){}"  `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSArrayLiteral [JSIdentifier 'a']) (JSBlock [])))"
+        testStmt "function x({a}){}"  `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSObjectLiteral [JSPropertyIdentRef 'a']) (JSBlock [])))"
+
+    it "generator" $ do
+        testStmt "function* x(){}"       `shouldBe` "Right (JSAstStatement (JSGenerator 'x' () (JSBlock [])))"
+        testStmt "function* x(a){}"      `shouldBe` "Right (JSAstStatement (JSGenerator 'x' (JSIdentifier 'a') (JSBlock [])))"
+        testStmt "function* x(a,b){}"    `shouldBe` "Right (JSAstStatement (JSGenerator 'x' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))"
+        testStmt "function* x(a,...b){}" `shouldBe` "Right (JSAstStatement (JSGenerator 'x' (JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b')) (JSBlock [])))"
+
+    it "class" $ do
+        testStmt "class Foo extends Bar { a(x,y) {} *b() {} }" `shouldBe` "Right (JSAstStatement (JSClass 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSGeneratorMethodDefinition (JSIdentifier 'b') () (JSBlock [])]))"
+        testStmt "class Foo { static get [a]() {}; }" `shouldBe` "Right (JSAstStatement (JSClass 'Foo' () [JSClassStaticMethod (JSPropertyAccessor JSAccessorGet (JSPropertyComputed (JSIdentifier 'a')) () (JSBlock [])),JSClassSemi]))"
+        testStmt "class Foo extends Bar { a(x,y) { super[x](y); } }" `shouldBe` "Right (JSAstStatement (JSClass 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSMethodCall (JSMemberSquare (JSLiteral 'super',JSIdentifier 'x'),JSArguments (JSIdentifier 'y')),JSSemicolon])]))"
 
 
 testStmt :: String -> String
