Upgrade to https://github.com/acornjs/acorn.git commit 84eda6bf
[jst.git] / src / expression.js
index e40808f..78bc2df 100644 (file)
 //
 // [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
 
-import {types as tt} from "./tokentype"
-import {Parser} from "./state"
-import {DestructuringErrors} from "./parseutil"
-import {lineBreak} from "./whitespace"
-import {functionFlags, SCOPE_ARROW, SCOPE_SUPER, SCOPE_DIRECT_SUPER, BIND_OUTSIDE, BIND_VAR} from "./scopeflags"
+import {types as tt} from "./tokentype.js"
+import {types as tokenCtxTypes} from "./tokencontext.js"
+import {Parser} from "./state.js"
+import {DestructuringErrors} from "./parseutil.js"
+import {lineBreak} from "./whitespace.js"
+import {functionFlags, SCOPE_ARROW, SCOPE_SUPER, SCOPE_DIRECT_SUPER, BIND_OUTSIDE, BIND_VAR} from "./scopeflags.js"
 
 // Nick
 import CleanCSS from "@ndcode/clean-css"
@@ -48,9 +49,13 @@ pp.checkPropClash = function(prop, propHash, refDestructuringErrors) {
   if (this.options.ecmaVersion >= 6) {
     if (name === "__proto__" && kind === "init") {
       if (propHash.proto) {
-        if (refDestructuringErrors && refDestructuringErrors.doubleProto < 0) refDestructuringErrors.doubleProto = key.start
-        // Backwards-compat kludge. Can be removed in version 6.0
-        else this.raiseRecoverable(key.start, "Redefinition of __proto__ property")
+        if (refDestructuringErrors) {
+          if (refDestructuringErrors.doubleProto < 0) {
+            refDestructuringErrors.doubleProto = key.start
+          }
+        } else {
+          this.raiseRecoverable(key.start, "Redefinition of __proto__ property")
+        }
       }
       propHash.proto = true
     }
@@ -92,13 +97,13 @@ pp.checkPropClash = function(prop, propHash, refDestructuringErrors) {
 // and object pattern might appear (so it's possible to raise
 // delayed syntax error at correct position).
 
-pp.parseExpression = function(noIn, refDestructuringErrors) {
+pp.parseExpression = function(forInit, refDestructuringErrors) {
   let startPos = this.start, startLoc = this.startLoc
-  let expr = this.parseMaybeAssign(noIn, refDestructuringErrors)
+  let expr = this.parseMaybeAssign(forInit, refDestructuringErrors)
   if (this.type === tt.comma) {
     let node = this.startNodeAt(startPos, startLoc)
     node.expressions = [expr]
-    while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refDestructuringErrors))
+    while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(forInit, refDestructuringErrors))
     return this.finishNode(node, "SequenceExpression")
   }
   return expr
@@ -107,61 +112,71 @@ pp.parseExpression = function(noIn, refDestructuringErrors) {
 // Parse an assignment expression. This includes applications of
 // operators like `+=`.
 
-pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {
+pp.parseMaybeAssign = function(forInit, refDestructuringErrors, afterLeftParse) {
   if (this.isContextual("yield")) {
-    if (this.inGenerator) return this.parseYield()
+    if (this.inGenerator) return this.parseYield(forInit)
     // The tokenizer will assume an expression is allowed after
     // `yield`, but this isn't that kind of yield
     else this.exprAllowed = false
   }
 
-  let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldShorthandAssign = -1
+  let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldDoubleProto = -1
   if (refDestructuringErrors) {
     oldParenAssign = refDestructuringErrors.parenthesizedAssign
     oldTrailingComma = refDestructuringErrors.trailingComma
-    oldShorthandAssign = refDestructuringErrors.shorthandAssign
-    refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.shorthandAssign = -1
+    oldDoubleProto = refDestructuringErrors.doubleProto
+    refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = -1
   } else {
     refDestructuringErrors = new DestructuringErrors
     ownDestructuringErrors = true
   }
 
   let startPos = this.start, startLoc = this.startLoc
-  if (this.type === tt.parenL || this.type === tt.name)
+  if (this.type === tt.parenL || this.type === tt.name) {
     this.potentialArrowAt = this.start
-  let left = this.parseMaybeConditional(noIn, refDestructuringErrors)
+    this.potentialArrowInForAwait = forInit === "await"
+  }
+  let left = this.parseMaybeConditional(forInit, refDestructuringErrors)
   if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc)
   if (this.type.isAssign) {
     let node = this.startNodeAt(startPos, startLoc)
     node.operator = this.value
-    node.left = this.type === tt.eq ? this.toAssignable(left, false, refDestructuringErrors) : left
-    if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors)
-    refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly
-    this.checkLVal(left)
+    if (this.type === tt.eq)
+      left = this.toAssignable(left, false, refDestructuringErrors)
+    if (!ownDestructuringErrors) {
+      refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.doubleProto = -1
+    }
+    if (refDestructuringErrors.shorthandAssign >= left.start)
+      refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly
+    if (this.type === tt.eq)
+      this.checkLValPattern(left)
+    else
+      this.checkLValSimple(left)
+    node.left = left
     this.next()
-    node.right = this.parseMaybeAssign(noIn)
+    node.right = this.parseMaybeAssign(forInit)
+    if (oldDoubleProto > -1) refDestructuringErrors.doubleProto = oldDoubleProto
     return this.finishNode(node, "AssignmentExpression")
   } else {
     if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true)
   }
   if (oldParenAssign > -1) refDestructuringErrors.parenthesizedAssign = oldParenAssign
   if (oldTrailingComma > -1) refDestructuringErrors.trailingComma = oldTrailingComma
-  if (oldShorthandAssign > -1) refDestructuringErrors.shorthandAssign = oldShorthandAssign
   return left
 }
 
 // Parse a ternary conditional (`?:`) operator.
 
-pp.parseMaybeConditional = function(noIn, refDestructuringErrors) {
+pp.parseMaybeConditional = function(forInit, refDestructuringErrors) {
   let startPos = this.start, startLoc = this.startLoc
-  let expr = this.parseExprOps(noIn, refDestructuringErrors)
+  let expr = this.parseExprOps(forInit, refDestructuringErrors)
   if (this.checkExpressionErrors(refDestructuringErrors)) return expr
   if (this.eat(tt.question)) {
     let node = this.startNodeAt(startPos, startLoc)
     node.test = expr
     node.consequent = this.parseMaybeAssign()
     this.expect(tt.colon)
-    node.alternate = this.parseMaybeAssign(noIn)
+    node.alternate = this.parseMaybeAssign(forInit)
     return this.finishNode(node, "ConditionalExpression")
   }
   return expr
@@ -169,11 +184,11 @@ pp.parseMaybeConditional = function(noIn, refDestructuringErrors) {
 
 // Start the precedence parser.
 
-pp.parseExprOps = function(noIn, refDestructuringErrors) {
+pp.parseExprOps = function(forInit, refDestructuringErrors) {
   let startPos = this.start, startLoc = this.startLoc
-  let expr = this.parseMaybeUnary(refDestructuringErrors, false)
+  let expr = this.parseMaybeUnary(refDestructuringErrors, false, false, forInit)
   if (this.checkExpressionErrors(refDestructuringErrors)) return expr
-  return expr.start === startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn)
+  return expr.start === startPos && expr.type === "ArrowFunctionExpression" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, forInit)
 }
 
 // Parse binary operators with the operator precedence parsing
@@ -182,23 +197,33 @@ pp.parseExprOps = function(noIn, refDestructuringErrors) {
 // defer further parser to one of its callers when it encounters an
 // operator that has a lower precedence than the set it is parsing.
 
-pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {
+pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, forInit) {
   let prec = this.type.binop
-  if (prec != null && (!noIn || this.type !== tt._in)) {
+  if (prec != null && (!forInit || this.type !== tt._in)) {
     if (prec > minPrec) {
       let logical = this.type === tt.logicalOR || this.type === tt.logicalAND
+      let coalesce = this.type === tt.coalesce
+      if (coalesce) {
+        // Handle the precedence of `tt.coalesce` as equal to the range of logical expressions.
+        // In other words, `node.right` shouldn't contain logical expressions in order to check the mixed error.
+        prec = tt.logicalAND.binop
+      }
       let op = this.value
       this.next()
       let startPos = this.start, startLoc = this.startLoc
-      let right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn)
-      let node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical)
-      return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn)
+      let right = this.parseExprOp(this.parseMaybeUnary(null, false, false, forInit), startPos, startLoc, prec, forInit)
+      let node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical || coalesce)
+      if ((logical && this.type === tt.coalesce) || (coalesce && (this.type === tt.logicalOR || this.type === tt.logicalAND))) {
+        this.raiseRecoverable(this.start, "Logical expressions and coalesce expressions cannot be mixed. Wrap either by parentheses")
+      }
+      return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, forInit)
     }
   }
   return left
 }
 
 pp.buildBinary = function(startPos, startLoc, left, right, op, logical) {
+  if (right.type === "PrivateIdentifier") this.raise(right.start, "Private identifier can only be left side of binary expression")
   let node = this.startNodeAt(startPos, startLoc)
   node.left = left
   node.operator = op
@@ -208,143 +233,206 @@ pp.buildBinary = function(startPos, startLoc, left, right, op, logical) {
 
 // Parse unary operators, both prefix and postfix.
 
-pp.parseMaybeUnary = function(refDestructuringErrors, sawUnary) {
+pp.parseMaybeUnary = function(refDestructuringErrors, sawUnary, incDec, forInit) {
   let startPos = this.start, startLoc = this.startLoc, expr
-  if (this.isContextual("await") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) {
-    expr = this.parseAwait()
+  if (this.isContextual("await") && this.canAwait) {
+    expr = this.parseAwait(forInit)
     sawUnary = true
   } else if (this.type.prefix) {
     let node = this.startNode(), update = this.type === tt.incDec
     node.operator = this.value
     node.prefix = true
     this.next()
-    node.argument = this.parseMaybeUnary(null, true)
+    node.argument = this.parseMaybeUnary(null, true, update, forInit)
     this.checkExpressionErrors(refDestructuringErrors, true)
-    if (update) this.checkLVal(node.argument)
+    if (update) this.checkLValSimple(node.argument)
     else if (this.strict && node.operator === "delete" &&
              node.argument.type === "Identifier")
       this.raiseRecoverable(node.start, "Deleting local variable in strict mode")
+    else if (node.operator === "delete" && isPrivateFieldAccess(node.argument))
+      this.raiseRecoverable(node.start, "Private fields can not be deleted")
     else sawUnary = true
     expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression")
+  } else if (!sawUnary && this.type === tt.privateId) {
+    if (forInit || this.privateNameStack.length === 0) this.unexpected()
+    expr = this.parsePrivateIdent()
+    // only could be private fields in 'in', such as #x in obj
+    if (this.type !== tt._in) this.unexpected()
   } else {
-    expr = this.parseExprSubscripts(refDestructuringErrors)
+    expr = this.parseExprSubscripts(refDestructuringErrors, forInit)
     if (this.checkExpressionErrors(refDestructuringErrors)) return expr
     while (this.type.postfix && !this.canInsertSemicolon()) {
       let node = this.startNodeAt(startPos, startLoc)
       node.operator = this.value
       node.prefix = false
       node.argument = expr
-      this.checkLVal(expr)
+      this.checkLValSimple(expr)
       this.next()
       expr = this.finishNode(node, "UpdateExpression")
     }
   }
 
-  if (!sawUnary && this.eat(tt.starstar))
-    return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), "**", false)
-  else
+  if (!incDec && this.eat(tt.starstar)) {
+    if (sawUnary)
+      this.unexpected(this.lastTokStart)
+    else
+      return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false, false, forInit), "**", false)
+  } else {
     return expr
+  }
+}
+
+function isPrivateFieldAccess(node) {
+  return (
+    node.type === "MemberExpression" && node.property.type === "PrivateIdentifier" ||
+    node.type === "ChainExpression" && isPrivateFieldAccess(node.expression)
+  )
 }
 
 // Parse call, dot, and `[]`-subscript expressions.
 
-pp.parseExprSubscripts = function(refDestructuringErrors) {
+pp.parseExprSubscripts = function(refDestructuringErrors, forInit) {
   let startPos = this.start, startLoc = this.startLoc
-  let expr = this.parseExprAtom(refDestructuringErrors)
-  let skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")"
-  if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr
-  let result = this.parseSubscripts(expr, startPos, startLoc)
+  let expr = this.parseExprAtom(refDestructuringErrors, forInit)
+  if (expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")")
+    return expr
+  let result = this.parseSubscripts(expr, startPos, startLoc, false, forInit)
   if (refDestructuringErrors && result.type === "MemberExpression") {
     if (refDestructuringErrors.parenthesizedAssign >= result.start) refDestructuringErrors.parenthesizedAssign = -1
     if (refDestructuringErrors.parenthesizedBind >= result.start) refDestructuringErrors.parenthesizedBind = -1
+    if (refDestructuringErrors.trailingComma >= result.start) refDestructuringErrors.trailingComma = -1
   }
   return result
 }
 
-pp.parseSubscripts = function(base, startPos, startLoc, noCalls) {
+pp.parseSubscripts = function(base, startPos, startLoc, noCalls, forInit) {
   let maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" &&
-      this.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === "async"
-  for (let computed;;) {
-    if ((computed = this.eat(tt.bracketL)) || this.eat(tt.dot)) {
-      let node = this.startNodeAt(startPos, startLoc)
-      node.object = base
-      //node.property = computed ? this.parseExpression() : this.parseIdent(true)
-      node.property = computed ? this.parseExpression() : this.type === tt.string ? this.parseLiteral(this.value) : this.parseIdent(true) // Nick
-      node.computed = !!computed
-      if (computed) this.expect(tt.bracketR)
-      base = this.finishNode(node, "MemberExpression")
+      this.lastTokEnd === base.end && !this.canInsertSemicolon() && base.end - base.start === 5 &&
+      this.potentialArrowAt === base.start
+  let optionalChained = false
+
+  while (true) {
+    let element = this.parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit)
+
+    if (element.optional) optionalChained = true
+    if (element === base || element.type === "ArrowFunctionExpression") {
+      if (optionalChained) {
+        const chainNode = this.startNodeAt(startPos, startLoc)
+        chainNode.expression = element
+        element = this.finishNode(chainNode, "ChainExpression")
+      }
+      return element
+    }
+
+    base = element
+  }
+}
+
+pp.parseSubscript = function(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit) {
+  let optionalSupported = this.options.ecmaVersion >= 11
+  let optional = optionalSupported && this.eat(tt.questionDot)
+  if (noCalls && optional) this.raise(this.lastTokStart, "Optional chaining cannot appear in the callee of new expressions")
+
+  let computed = this.eat(tt.bracketL)
+  if (computed || (optional && this.type !== tt.parenL && this.type !== tt.backQuote) || this.eat(tt.dot)) {
+    let node = this.startNodeAt(startPos, startLoc)
+    node.object = base
+    if (computed) {
+      node.property = this.parseExpression()
+      this.expect(tt.bracketR)
+    } else if (this.type === tt.privateId && base.type !== "Super") {
+      node.property = this.parsePrivateIdent()
+    } else if (this.type === tt.string) { // Nick
+      node.property = this.parseLiteral(this.value)
+    } else {
+      node.property = this.parseIdent(this.options.allowReserved !== "never")
+    }
+    node.computed = !!computed
+    if (optionalSupported) {
+      node.optional = optional
+    }
+    base = this.finishNode(node, "MemberExpression")
     } else if (this.eat(tt.hash)) { // Nick
       let node = this.startNodeAt(startPos, startLoc)
       node.object = base
       //node.property = this.parseIdent(true)
       node.property = this.type === tt.string ? this.parseLiteral(this.value) : this.parseIdent(true) // Nick
       base = this.finishNode(node, "MemberExpressionHash")
-    } else if (!noCalls && this.eat(tt.parenL)) {
-      let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
-      this.yieldPos = 0
-      this.awaitPos = 0
-      let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors)
-      if (maybeAsyncArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
-        this.checkPatternErrors(refDestructuringErrors, false)
-        this.checkYieldAwaitInDefaultParams()
-        this.yieldPos = oldYieldPos
-        this.awaitPos = oldAwaitPos
-        return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true)
-      }
-      this.checkExpressionErrors(refDestructuringErrors, true)
-      this.yieldPos = oldYieldPos || this.yieldPos
-      this.awaitPos = oldAwaitPos || this.awaitPos
-      let node = this.startNodeAt(startPos, startLoc)
-      node.callee = base
-      node.arguments = exprList
-      base = this.finishNode(node, "CallExpression")
-    } else if (this.type === tt.backQuote) {
-      let node = this.startNodeAt(startPos, startLoc)
-      node.tag = base
-      node.quasi = this.parseTemplate({isTagged: true})
-      base = this.finishNode(node, "TaggedTemplateExpression")
-    } else if (this.type === tt.braceL) { // Nick
-      let node = this.startNodeAt(startPos, startLoc)
-      node.tag = base
-      if (
-        (
-          base.type === 'Identifier' &&
-          base.name === 'style'
-        ) ||
-        (
-          base.type === 'CallExpression' &&
-          base.callee.type === 'Identifier' &&
-          base.callee.name === 'style'
-        )
-      ) {
-        let render = clean_css.minifyEmbedded(this.input, this.pos)
-        if (render.errors.length)
-          throw render.errors
-        for (let i = 0; i < render.warnings.length; ++i)
-          console.log(`clean-css warning: ${render.warnings[i]}`)
-        node.body = {
-          type: 'BlockStatement',
-          body: [
-            {
-              type: 'ExpressionStatement',
-              expression: {
-                type: 'Literal',
-                value: render.styles // we simply assume it does not contain </style> tags, should HTML escape it??
-              }
+  } else if (!noCalls && this.eat(tt.parenL)) {
+    let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos
+    this.yieldPos = 0
+    this.awaitPos = 0
+    this.awaitIdentPos = 0
+    let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors)
+    if (maybeAsyncArrow && !optional && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
+      this.checkPatternErrors(refDestructuringErrors, false)
+      this.checkYieldAwaitInDefaultParams()
+      if (this.awaitIdentPos > 0)
+        this.raise(this.awaitIdentPos, "Cannot use 'await' as identifier inside an async function")
+      this.yieldPos = oldYieldPos
+      this.awaitPos = oldAwaitPos
+      this.awaitIdentPos = oldAwaitIdentPos
+      return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true, forInit)
+    }
+    this.checkExpressionErrors(refDestructuringErrors, true)
+    this.yieldPos = oldYieldPos || this.yieldPos
+    this.awaitPos = oldAwaitPos || this.awaitPos
+    this.awaitIdentPos = oldAwaitIdentPos || this.awaitIdentPos
+    let node = this.startNodeAt(startPos, startLoc)
+    node.callee = base
+    node.arguments = exprList
+    if (optionalSupported) {
+      node.optional = optional
+    }
+    base = this.finishNode(node, "CallExpression")
+  } else if (this.type === tt.backQuote) {
+    if (optional || optionalChained) {
+      this.raise(this.start, "Optional chaining cannot appear in the tag of tagged template expressions")
+    }
+    let node = this.startNodeAt(startPos, startLoc)
+    node.tag = base
+    node.quasi = this.parseTemplate({isTagged: true})
+    base = this.finishNode(node, "TaggedTemplateExpression")
+  } else if (this.type === tt.braceL) { // Nick
+    let node = this.startNodeAt(startPos, startLoc)
+    node.tag = base
+    if (
+      (
+        base.type === 'Identifier' &&
+        base.name === 'style'
+      ) ||
+      (
+        base.type === 'CallExpression' &&
+        base.callee.type === 'Identifier' &&
+        base.callee.name === 'style'
+      )
+    ) {
+      let render = clean_css.minifyEmbedded(this.input, this.pos)
+      if (render.errors.length)
+        throw render.errors
+      for (let i = 0; i < render.warnings.length; ++i)
+        console.log(`clean-css warning: ${render.warnings[i]}`)
+      node.body = {
+        type: 'BlockStatement',
+        body: [
+          {
+            type: 'ExpressionStatement',
+            expression: {
+              type: 'Literal',
+              value: render.styles // we simply assume it does not contain </style> tags, should HTML escape it??
             }
-          ]
-        }
-        this.pos = render.embeddedEnd
-        this.next()
-        this.expect(tt.braceR)
+          }
+        ]
       }
-      else
-        node.body = this.parseBlock(false)
-      base = this.finishNode(node, "HTMLExpression")
-    } else {
-      return base
+      this.pos = render.embeddedEnd
+      this.next()
+      this.expect(tt.braceR)
     }
+    else
+      node.body = this.parseBlock(false)
+    base = this.finishNode(node, "HTMLExpression")
   }
+  return base
 }
 
 // Parse an atomic expression — either a single token that is an
@@ -352,7 +440,11 @@ pp.parseSubscripts = function(base, startPos, startLoc, noCalls) {
 // `new`, or an expression wrapped in punctuation like `()`, `[]`,
 // or `{}`.
 
-pp.parseExprAtom = function(refDestructuringErrors) {
+pp.parseExprAtom = function(refDestructuringErrors, forInit) {
+  // If a division operator appears in an expression position, the
+  // tokenizer got confused, and we force it to read a regexp instead.
+  if (this.type === tt.slash) this.readRegexp()
+
   let node, canBeArrow = this.potentialArrowAt === this.start
   switch (this.type) {
   case tt._super:
@@ -367,7 +459,7 @@ pp.parseExprAtom = function(refDestructuringErrors) {
     //     super [ Expression ]
     //     super . IdentifierName
     // SuperCall:
-    //     super Arguments
+    //     super ( Arguments )
     if (this.type !== tt.dot && this.type !== tt.bracketL && this.type !== tt.parenL)
       this.unexpected()
     return this.finishNode(node, "Super")
@@ -379,17 +471,20 @@ pp.parseExprAtom = function(refDestructuringErrors) {
 
   case tt.name:
     let startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc
-    let id = this.parseIdent(this.type !== tt.name)
-    if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === "async" && !this.canInsertSemicolon() && this.eat(tt._function))
-      return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true)
+    let id = this.parseIdent(false)
+    if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === "async" && !this.canInsertSemicolon() && this.eat(tt._function)) {
+      this.overrideContext(tokenCtxTypes.f_expr)
+      return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true, forInit)
+    }
     if (canBeArrow && !this.canInsertSemicolon()) {
       if (this.eat(tt.arrow))
-        return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false)
-      if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc) {
-        id = this.parseIdent()
+        return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false, forInit)
+      if (this.options.ecmaVersion >= 8 && id.name === "async" && this.type === tt.name && !containsEsc &&
+          (!this.potentialArrowInForAwait || this.value !== "of" || this.containsEsc)) {
+        id = this.parseIdent(false)
         if (this.canInsertSemicolon() || !this.eat(tt.arrow))
           this.unexpected()
-        return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true)
+        return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true, forInit)
       }
     }
     return id
@@ -411,7 +506,7 @@ pp.parseExprAtom = function(refDestructuringErrors) {
     return this.finishNode(node, "Literal")
 
   case tt.parenL:
-    let start = this.start, expr = this.parseParenAndDistinguishExpression(canBeArrow)
+    let start = this.start, expr = this.parseParenAndDistinguishExpression(canBeArrow, forInit)
     if (refDestructuringErrors) {
       if (refDestructuringErrors.parenthesizedAssign < 0 && !this.isSimpleAssignTarget(expr))
         refDestructuringErrors.parenthesizedAssign = start
@@ -427,6 +522,7 @@ pp.parseExprAtom = function(refDestructuringErrors) {
     return this.finishNode(node, "ArrayExpression")
 
   case tt.braceL:
+    this.overrideContext(tokenCtxTypes.b_expr)
     return this.parseObj(false, refDestructuringErrors)
 
   case tt._function:
@@ -443,15 +539,77 @@ pp.parseExprAtom = function(refDestructuringErrors) {
   case tt.backQuote:
     return this.parseTemplate()
 
+  case tt._import:
+    if (this.options.ecmaVersion >= 11) {
+      return this.parseExprImport()
+    } else {
+      return this.unexpected()
+    }
+
   default:
     return this.parseIdent(true) // Nick this.unexpected()
   }
 }
 
+pp.parseExprImport = function() {
+  const node = this.startNode()
+
+  // Consume `import` as an identifier for `import.meta`.
+  // Because `this.parseIdent(true)` doesn't check escape sequences, it needs the check of `this.containsEsc`.
+  if (this.containsEsc) this.raiseRecoverable(this.start, "Escape sequence in keyword import")
+  const meta = this.parseIdent(true)
+
+  switch (this.type) {
+  case tt.parenL:
+    return this.parseDynamicImport(node)
+  case tt.dot:
+    node.meta = meta
+    return this.parseImportMeta(node)
+  default:
+    this.unexpected()
+  }
+}
+
+pp.parseDynamicImport = function(node) {
+  this.next() // skip `(`
+
+  // Parse node.source.
+  node.source = this.parseMaybeAssign()
+
+  // Verify ending.
+  if (!this.eat(tt.parenR)) {
+    const errorPos = this.start
+    if (this.eat(tt.comma) && this.eat(tt.parenR)) {
+      this.raiseRecoverable(errorPos, "Trailing comma is not allowed in import()")
+    } else {
+      this.unexpected(errorPos)
+    }
+  }
+
+  return this.finishNode(node, "ImportExpression")
+}
+
+pp.parseImportMeta = function(node) {
+  this.next() // skip `.`
+
+  const containsEsc = this.containsEsc
+  node.property = this.parseIdent(true)
+
+  if (node.property.name !== "meta")
+    this.raiseRecoverable(node.property.start, "The only valid meta property for import is 'import.meta'")
+  if (containsEsc)
+    this.raiseRecoverable(node.start, "'import.meta' must not contain escaped characters")
+  if (this.options.sourceType !== "module" && !this.options.allowImportExportEverywhere)
+    this.raiseRecoverable(node.start, "Cannot use 'import.meta' outside a module")
+
+  return this.finishNode(node, "MetaProperty")
+}
+
 pp.parseLiteral = function(value) {
   let node = this.startNode()
   node.value = value
   node.raw = this.input.slice(this.start, this.end)
+  if (node.raw.charCodeAt(node.raw.length - 1) === 110) node.bigint = node.raw.slice(0, -1).replace(/_/g, "")
   this.next()
   return this.finishNode(node, "Literal")
 }
@@ -463,7 +621,7 @@ pp.parseParenExpression = function() {
   return val
 }
 
-pp.parseParenAndDistinguishExpression = function(canBeArrow) {
+pp.parseParenAndDistinguishExpression = function(canBeArrow, forInit) {
   let startPos = this.start, startLoc = this.startLoc, val, allowTrailingComma = this.options.ecmaVersion >= 8
   if (this.options.ecmaVersion >= 6) {
     this.next()
@@ -473,6 +631,7 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow) {
     let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, spreadStart
     this.yieldPos = 0
     this.awaitPos = 0
+    // Do not save awaitIdentPos to allow checking awaits nested in parameters
     while (this.type !== tt.parenR) {
       first ? first = false : this.expect(tt.comma)
       if (allowTrailingComma && this.afterTrailingComma(tt.parenR, true)) {
@@ -487,7 +646,7 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow) {
         exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem))
       }
     }
-    let innerEndPos = this.start, innerEndLoc = this.startLoc
+    let innerEndPos = this.lastTokEnd, innerEndLoc = this.lastTokEndLoc
     this.expect(tt.parenR)
 
     if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
@@ -495,7 +654,7 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow) {
       this.checkYieldAwaitInDefaultParams()
       this.yieldPos = oldYieldPos
       this.awaitPos = oldAwaitPos
-      return this.parseParenArrowList(startPos, startLoc, exprList)
+      return this.parseParenArrowList(startPos, startLoc, exprList, forInit)
     }
 
     if (!exprList.length || lastIsComma) this.unexpected(this.lastTokStart)
@@ -528,8 +687,8 @@ pp.parseParenItem = function(item) {
   return item
 }
 
-pp.parseParenArrowList = function(startPos, startLoc, exprList) {
-  return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList)
+pp.parseParenArrowList = function(startPos, startLoc, exprList, forInit) {
+  return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, false, forInit)
 }
 
 // New's precedence is slightly tricky. It must allow its argument to
@@ -541,20 +700,26 @@ pp.parseParenArrowList = function(startPos, startLoc, exprList) {
 const empty = []
 
 pp.parseNew = function() {
+  if (this.containsEsc) this.raiseRecoverable(this.start, "Escape sequence in keyword new")
   let node = this.startNode()
   let meta = this.parseIdent(true)
   if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {
     node.meta = meta
     let containsEsc = this.containsEsc
     node.property = this.parseIdent(true)
-    if (node.property.name !== "target" || containsEsc)
-      this.raiseRecoverable(node.property.start, "The only valid meta property for new is new.target")
-    if (!this.inNonArrowFunction())
-      this.raiseRecoverable(node.start, "new.target can only be used in functions")
+    if (node.property.name !== "target")
+      this.raiseRecoverable(node.property.start, "The only valid meta property for new is 'new.target'")
+    if (containsEsc)
+      this.raiseRecoverable(node.start, "'new.target' must not contain escaped characters")
+    if (!this.allowNewDotTarget)
+      this.raiseRecoverable(node.start, "'new.target' can only be used in functions and class static block")
     return this.finishNode(node, "MetaProperty")
   }
-  let startPos = this.start, startLoc = this.startLoc
-  node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true)
+  let startPos = this.start, startLoc = this.startLoc, isImport = this.type === tt._import
+  node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true, false)
+  if (isImport && node.callee.type === "ImportExpression") {
+    this.raise(startPos, "Cannot use new with import()")
+  }
   if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false)
   else node.arguments = empty
   return this.finishNode(node, "NewExpression")
@@ -615,7 +780,7 @@ pp.parseObj = function(isPattern, refDestructuringErrors) {
   while (!this.eat(tt.braceR)) {
     if (!first) {
       this.expect(tt.comma)
-      if (this.afterTrailingComma(tt.braceR)) break
+      if (this.options.ecmaVersion >= 5 && this.afterTrailingComma(tt.braceR)) break
     } else first = false
 
     const prop = this.parseProperty(isPattern, refDestructuringErrors)
@@ -691,7 +856,7 @@ pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos
   } else if (!isPattern && !containsEsc &&
              this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" &&
              (prop.key.name === "get" || prop.key.name === "set") &&
-             (this.type !== tt.comma && this.type !== tt.braceR)) {
+             (this.type !== tt.comma && this.type !== tt.braceR && this.type !== tt.eq)) {
     if (isGenerator || isAsync) this.unexpected()
     prop.kind = prop.key.name
     this.parsePropertyName(prop)
@@ -708,16 +873,19 @@ pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos
         this.raiseRecoverable(prop.value.params[0].start, "Setter cannot use rest params")
     }
   } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
+    if (isGenerator || isAsync) this.unexpected()
     this.checkUnreserved(prop.key)
+    if (prop.key.name === "await" && !this.awaitIdentPos)
+      this.awaitIdentPos = startPos
     prop.kind = "init"
     if (isPattern) {
-      prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)
+      prop.value = this.parseMaybeDefault(startPos, startLoc, this.copyNode(prop.key))
     } else if (this.type === tt.eq && refDestructuringErrors) {
       if (refDestructuringErrors.shorthandAssign < 0)
         refDestructuringErrors.shorthandAssign = this.start
-      prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)
+      prop.value = this.parseMaybeDefault(startPos, startLoc, this.copyNode(prop.key))
     } else {
-      prop.value = prop.key
+      prop.value = this.copyNode(prop.key)
     }
     prop.shorthand = true
   } else this.unexpected()
@@ -734,7 +902,7 @@ pp.parsePropertyName = function(prop) {
       prop.computed = false
     }
   }
-  return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true)
+  return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(this.options.allowReserved !== "never")
 }
 
 // Initialize empty function node.
@@ -748,7 +916,7 @@ pp.initFunction = function(node) {
 // Parse object or class method.
 
 pp.parseMethod = function(isGenerator, isAsync, allowDirectSuper) {
-  let node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
+  let node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos
 
   this.initFunction(node)
   if (this.options.ecmaVersion >= 6)
@@ -758,22 +926,24 @@ pp.parseMethod = function(isGenerator, isAsync, allowDirectSuper) {
 
   this.yieldPos = 0
   this.awaitPos = 0
+  this.awaitIdentPos = 0
   this.enterScope(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0))
 
   this.expect(tt.parenL)
   node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8)
   this.checkYieldAwaitInDefaultParams()
-  this.parseFunctionBody(node, false)
+  this.parseFunctionBody(node, false, true, false)
 
   this.yieldPos = oldYieldPos
   this.awaitPos = oldAwaitPos
+  this.awaitIdentPos = oldAwaitIdentPos
   return this.finishNode(node, "FunctionExpression")
 }
 
 // Parse arrow function expression with given parameters.
 
-pp.parseArrowExpression = function(node, params, isAsync) {
-  let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
+pp.parseArrowExpression = function(node, params, isAsync, forInit) {
+  let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldAwaitIdentPos = this.awaitIdentPos
 
   this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW)
   this.initFunction(node)
@@ -781,23 +951,25 @@ pp.parseArrowExpression = function(node, params, isAsync) {
 
   this.yieldPos = 0
   this.awaitPos = 0
+  this.awaitIdentPos = 0
 
   node.params = this.toAssignableList(params, true)
-  this.parseFunctionBody(node, true)
+  this.parseFunctionBody(node, true, false, forInit)
 
   this.yieldPos = oldYieldPos
   this.awaitPos = oldAwaitPos
+  this.awaitIdentPos = oldAwaitIdentPos
   return this.finishNode(node, "ArrowFunctionExpression")
 }
 
 // Parse function body and check parameters.
 
-pp.parseFunctionBody = function(node, isArrowFunction) {
+pp.parseFunctionBody = function(node, isArrowFunction, isMethod, forInit) {
   let isExpression = isArrowFunction && this.type !== tt.braceL
   let oldStrict = this.strict, useStrict = false
 
   if (isExpression) {
-    node.body = this.parseMaybeAssign()
+    node.body = this.parseMaybeAssign(forInit)
     node.expression = true
     this.checkParams(node, false)
   } else {
@@ -818,17 +990,15 @@ pp.parseFunctionBody = function(node, isArrowFunction) {
 
     // Add the params to varDeclaredNames to ensure that an error is thrown
     // if a let/const declaration in the function clashes with one of the params.
-    this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && this.isSimpleParamList(node.params))
-    node.body = this.parseBlock(false)
+    this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && !isMethod && this.isSimpleParamList(node.params))
+    // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'
+    if (this.strict && node.id) this.checkLValSimple(node.id, BIND_OUTSIDE)
+    node.body = this.parseBlock(false, undefined, useStrict && !oldStrict)
     node.expression = false
     this.adaptDirectivePrologue(node.body.body)
     this.labels = oldLabels
   }
   this.exitScope()
-
-  // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'
-  if (this.strict && node.id) this.checkLVal(node.id, BIND_OUTSIDE)
-  this.strict = oldStrict
 }
 
 pp.isSimpleParamList = function(params) {
@@ -841,9 +1011,9 @@ pp.isSimpleParamList = function(params) {
 // or "arguments" and duplicate parameters.
 
 pp.checkParams = function(node, allowDuplicates) {
-  let nameHash = {}
+  let nameHash = Object.create(null)
   for (let param of node.params)
-    this.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash)
+    this.checkLValInnerPattern(param, BIND_VAR, allowDuplicates ? null : nameHash)
 }
 
 // Parses a comma-separated list of expressions, and returns them as
@@ -877,9 +1047,13 @@ pp.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructur
 
 pp.checkUnreserved = function({start, end, name}) {
   if (this.inGenerator && name === "yield")
-    this.raiseRecoverable(start, "Can not use 'yield' as identifier inside a generator")
+    this.raiseRecoverable(start, "Cannot use 'yield' as identifier inside a generator")
   if (this.inAsync && name === "await")
-    this.raiseRecoverable(start, "Can not use 'await' as identifier inside an async function")
+    this.raiseRecoverable(start, "Cannot use 'await' as identifier inside an async function")
+  if (this.currentThisScope().inClassFieldInit && name === "arguments")
+    this.raiseRecoverable(start, "Cannot use 'arguments' in class field initializer")
+  if (this.inClassStaticBlock && (name === "arguments" || name === "await"))
+    this.raise(start, `Cannot use ${name} in class static initialization block`)
   if (this.keywords.test(name))
     this.raise(start, `Unexpected keyword '${name}'`)
   if (this.options.ecmaVersion < 6 &&
@@ -887,7 +1061,7 @@ pp.checkUnreserved = function({start, end, name}) {
   const re = this.strict ? this.reservedWordsStrict : this.reservedWords
   if (re.test(name)) {
     if (!this.inAsync && name === "await")
-      this.raiseRecoverable(start, "Can not use keyword 'await' outside an async function")
+      this.raiseRecoverable(start, "Cannot use keyword 'await' outside an async function")
     this.raiseRecoverable(start, `The keyword '${name}' is reserved`)
   }
 }
@@ -898,7 +1072,6 @@ pp.checkUnreserved = function({start, end, name}) {
 
 pp.parseIdent = function(liberal, isBinding) {
   let node = this.startNode()
-  if (liberal && this.options.allowReserved === "never") liberal = false
   if (this.type === tt.name) {
     node.name = this.value
   } else if (this.type.keyword) {
@@ -915,15 +1088,39 @@ pp.parseIdent = function(liberal, isBinding) {
   } else {
     this.unexpected()
   }
-  this.next()
+  this.next(!!liberal)
   this.finishNode(node, "Identifier")
-  if (!liberal) this.checkUnreserved(node)
+  if (!liberal) {
+    this.checkUnreserved(node)
+    if (node.name === "await" && !this.awaitIdentPos)
+      this.awaitIdentPos = node.start
+  }
+  return node
+}
+
+pp.parsePrivateIdent = function() {
+  const node = this.startNode()
+  if (this.type === tt.privateId) {
+    node.name = this.value
+  } else {
+    this.unexpected()
+  }
+  this.next()
+  this.finishNode(node, "PrivateIdentifier")
+
+  // For validating existence
+  if (this.privateNameStack.length === 0) {
+    this.raise(node.start, `Private field '#${node.name}' must be declared in an enclosing class`)
+  } else {
+    this.privateNameStack[this.privateNameStack.length - 1].used.push(node)
+  }
+
   return node
 }
 
 // Parses yield expression inside generator.
 
-pp.parseYield = function() {
+pp.parseYield = function(forInit) {
   if (!this.yieldPos) this.yieldPos = this.start
 
   let node = this.startNode()
@@ -933,16 +1130,16 @@ pp.parseYield = function() {
     node.argument = null
   } else {
     node.delegate = this.eat(tt.star)
-    node.argument = this.parseMaybeAssign()
+    node.argument = this.parseMaybeAssign(forInit)
   }
   return this.finishNode(node, "YieldExpression")
 }
 
-pp.parseAwait = function() {
+pp.parseAwait = function(forInit) {
   if (!this.awaitPos) this.awaitPos = this.start
 
   let node = this.startNode()
   this.next()
-  node.argument = this.parseMaybeUnary(null, true)
+  node.argument = this.parseMaybeUnary(null, true, false, forInit)
   return this.finishNode(node, "AwaitExpression")
 }