[Pkg-javascript-commits] [acorn] 06/08: New upstream version 4.0.11

Julien Puydt julien.puydt at laposte.net
Tue Feb 14 06:19:16 UTC 2017


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to branch master
in repository acorn.

commit f2e1f9d722ac0b67980b528fc1faf7d43e38c60f
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Sat Feb 11 10:26:57 2017 +0100

    New upstream version 4.0.11
---
 AUTHORS                  |  2 +
 CHANGELOG.md             | 64 ++++++++++++++++++++++++++++++++
 README.md                |  3 +-
 package.json             |  2 +-
 src/expression.js        | 95 +++++++++++++++++++++++++++++-------------------
 src/index.js             |  4 +-
 src/loose/expression.js  |  2 +-
 src/loose/statement.js   | 22 ++++++-----
 src/parseutil.js         | 43 ++++++++++++++--------
 src/state.js             |  3 +-
 src/statement.js         | 57 ++++++++++++++---------------
 src/tokenize.js          | 17 ++-------
 test/tests-asyncawait.js |  6 ++-
 test/tests-es7.js        | 14 ++++---
 test/tests-harmony.js    | 70 +++++++++++++++++++++++++++++------
 test/tests.js            | 38 +++++++++++++------
 16 files changed, 301 insertions(+), 141 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 3064045..ab64891 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -41,6 +41,7 @@ Max Schaefer
 Max Zerzouri
 Mihai Bazon
 Mike Rennie
+naoh
 Nicholas C. Zakas
 Nick Fitzgerald
 Olivier Thomann
@@ -57,4 +58,5 @@ Sebastian McKenzie
 Simen Bekkhus
 Timothy Gu
 Toru Nagashima
+Wexpo Lyu
 zsjforcn
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 65c50a9..f6d1fa8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,67 @@
+## 4.0.11 (2017-02-07)
+
+### Bug fixes
+
+Allow all forms of member expressions to be parenthesized as lvalue.
+
+## 4.0.10 (2017-02-07)
+
+### Bug fixes
+
+Don't expect semicolons after default-exported functions or classes,
+even when they are expressions.
+
+Check for use of `'use strict'` directives in non-simple parameter
+functions, even when already in strict mode.
+
+## 4.0.9 (2017-02-06)
+
+### Bug fixes
+
+Fix incorrect error raised for parenthesized simple assignment
+targets, so that `(x) = 1` parses again.
+
+## 4.0.8 (2017-02-03)
+
+### Bug fixes
+
+Solve spurious parenthesized pattern errors by temporarily erring on
+the side of accepting programs that our delayed errors don't handle
+correctly yet.
+
+## 4.0.7 (2017-02-02)
+
+### Bug fixes
+
+Accept invalidly rejected code like `(x).y = 2` again.
+
+Don't raise an error when a function _inside_ strict code has a
+non-simple parameter list.
+
+## 4.0.6 (2017-02-02)
+
+### Bug fixes
+
+Fix exponential behavior (manifesting itself as a complete hang for
+even relatively small source files) introduced by the new 'use strict'
+check.
+
+## 4.0.5 (2017-02-02)
+
+### Bug fixes
+
+Disallow parenthesized pattern expressions.
+
+Allow keywords as export names.
+
+Don't allow the `async` keyword to be parenthesized.
+
+Properly raise an error when a keyword contains a character escape.
+
+Allow `"use strict"` to appear after other string literal expressions.
+
+Disallow labeled declarations.
+
 ## 4.0.4 (2016-12-19)
 
 ### Bug fixes
diff --git a/README.md b/README.md
index 82dc287..b7efe23 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
 # Acorn
 
 [![Build Status](https://travis-ci.org/ternjs/acorn.svg?branch=master)](https://travis-ci.org/ternjs/acorn)
-[![NPM version](https://img.shields.io/npm/v/acorn.svg)](https://www.npmjs.com/package/acorn)  
+[![NPM version](https://img.shields.io/npm/v/acorn.svg)](https://www.npmjs.com/package/acorn)
+[![CDNJS](https://img.shields.io/cdnjs/v/acorn.svg)](https://cdnjs.com/libraries/acorn)  
 [Author funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png?force)](https://marijnhaverbeke.nl/fund/)
 
 A tiny, fast JavaScript parser, written completely in JavaScript.
diff --git a/package.json b/package.json
index dedbd9e..29a32a7 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "homepage": "https://github.com/ternjs/acorn",
   "main": "dist/acorn.js",
   "jsnext:main": "dist/acorn.es.js",
-  "version": "4.0.4",
+  "version": "4.0.11",
   "engines": {
     "node": ">=0.4.0"
   },
diff --git a/src/expression.js b/src/expression.js
index f8a7e0f..bbcd9da 100644
--- a/src/expression.js
+++ b/src/expression.js
@@ -93,11 +93,15 @@ pp.parseExpression = function(noIn, refDestructuringErrors) {
 pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {
   if (this.inGenerator && this.isContextual("yield")) return this.parseYield()
 
-  let ownDestructuringErrors = false
-  if (!refDestructuringErrors) {
+  let ownDestructuringErrors = false, oldParenAssign = -1
+  if (refDestructuringErrors) {
+    oldParenAssign = refDestructuringErrors.parenthesizedAssign
+    refDestructuringErrors.parenthesizedAssign = -1
+  } else {
     refDestructuringErrors = new DestructuringErrors
     ownDestructuringErrors = true
   }
+
   let startPos = this.start, startLoc = this.startLoc
   if (this.type == tt.parenL || this.type == tt.name)
     this.potentialArrowAt = this.start
@@ -109,7 +113,7 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {
     let node = this.startNodeAt(startPos, startLoc)
     node.operator = this.value
     node.left = this.type === tt.eq ? this.toAssignable(left) : left
-    refDestructuringErrors.shorthandAssign = 0 // reset because shorthand default was used correctly
+    refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly
     this.checkLVal(left)
     this.next()
     node.right = this.parseMaybeAssign(noIn)
@@ -117,6 +121,7 @@ pp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {
   } else {
     if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true)
   }
+  if (oldParenAssign > -1) refDestructuringErrors.parenthesizedAssign = oldParenAssign
   return left
 }
 
@@ -223,24 +228,24 @@ pp.parseExprSubscripts = function(refDestructuringErrors) {
   let expr = this.parseExprAtom(refDestructuringErrors)
   let skipArrowSubscripts = expr.type === "ArrowFunctionExpression" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")"
   if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr
-  return this.parseSubscripts(expr, startPos, startLoc)
+  let result = this.parseSubscripts(expr, startPos, startLoc)
+  if (refDestructuringErrors && result.type === "MemberExpression") {
+    if (refDestructuringErrors.parenthesizedAssign >= result.start) refDestructuringErrors.parenthesizedAssign = -1
+    if (refDestructuringErrors.parenthesizedBind >= result.start) refDestructuringErrors.parenthesizedBind = -1
+  }
+  return result
 }
 
 pp.parseSubscripts = function(base, startPos, startLoc, noCalls) {
-  for (;;) {
-    let maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" && !this.canInsertSemicolon()
-    if (this.eat(tt.dot)) {
+  let maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === "Identifier" && base.name === "async" &&
+      this.lastTokEnd == base.end && !this.canInsertSemicolon()
+  for (let computed;;) {
+    if ((computed = this.eat(tt.bracketL)) || this.eat(tt.dot)) {
       let node = this.startNodeAt(startPos, startLoc)
       node.object = base
-      node.property = this.parseIdent(true)
-      node.computed = false
-      base = this.finishNode(node, "MemberExpression")
-    } else if (this.eat(tt.bracketL)) {
-      let node = this.startNodeAt(startPos, startLoc)
-      node.object = base
-      node.property = this.parseExpression()
-      node.computed = true
-      this.expect(tt.bracketR)
+      node.property = computed ? this.parseExpression() : this.parseIdent(true)
+      node.computed = !!computed
+      if (computed) this.expect(tt.bracketR)
       base = this.finishNode(node, "MemberExpression")
     } else if (!noCalls && this.eat(tt.parenL)) {
       let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
@@ -248,7 +253,7 @@ pp.parseSubscripts = function(base, startPos, startLoc, noCalls) {
       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, true)
+        this.checkPatternErrors(refDestructuringErrors, false)
         this.checkYieldAwaitInDefaultParams()
         this.yieldPos = oldYieldPos
         this.awaitPos = oldAwaitPos
@@ -324,7 +329,14 @@ pp.parseExprAtom = function(refDestructuringErrors) {
     return this.finishNode(node, "Literal")
 
   case tt.parenL:
-    return this.parseParenAndDistinguishExpression(canBeArrow)
+    let start = this.start, expr = this.parseParenAndDistinguishExpression(canBeArrow)
+    if (refDestructuringErrors) {
+      if (refDestructuringErrors.parenthesizedAssign < 0 && !this.isSimpleAssignTarget(expr))
+        refDestructuringErrors.parenthesizedAssign = start
+      if (refDestructuringErrors.parenthesizedBind < 0)
+        refDestructuringErrors.parenthesizedBind = start
+    }
+    return expr
 
   case tt.bracketL:
     node = this.startNode()
@@ -400,7 +412,7 @@ pp.parseParenAndDistinguishExpression = function(canBeArrow) {
     this.expect(tt.parenR)
 
     if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
-      this.checkPatternErrors(refDestructuringErrors, true)
+      this.checkPatternErrors(refDestructuringErrors, false)
       this.checkYieldAwaitInDefaultParams()
       if (innerParenStart) this.unexpected(innerParenStart)
       this.yieldPos = oldYieldPos
@@ -577,7 +589,7 @@ pp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos
     if (isPattern) {
       prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)
     } else if (this.type === tt.eq && refDestructuringErrors) {
-      if (!refDestructuringErrors.shorthandAssign)
+      if (refDestructuringErrors.shorthandAssign < 0)
         refDestructuringErrors.shorthandAssign = this.start
       prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)
     } else {
@@ -616,7 +628,8 @@ pp.initFunction = function(node) {
 // Parse object or class method.
 
 pp.parseMethod = function(isGenerator, isAsync) {
-  let node = this.startNode(), oldInGen = this.inGenerator, oldInAsync = this.inAsync, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
+  let node = this.startNode(), oldInGen = this.inGenerator, oldInAsync = this.inAsync,
+      oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction
 
   this.initFunction(node)
   if (this.options.ecmaVersion >= 6)
@@ -628,6 +641,7 @@ pp.parseMethod = function(isGenerator, isAsync) {
   this.inAsync = node.async
   this.yieldPos = 0
   this.awaitPos = 0
+  this.inFunction = true
 
   this.expect(tt.parenL)
   node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8)
@@ -638,13 +652,15 @@ pp.parseMethod = function(isGenerator, isAsync) {
   this.inAsync = oldInAsync
   this.yieldPos = oldYieldPos
   this.awaitPos = oldAwaitPos
+  this.inFunction = oldInFunc
   return this.finishNode(node, "FunctionExpression")
 }
 
 // Parse arrow function expression with given parameters.
 
 pp.parseArrowExpression = function(node, params, isAsync) {
-  let oldInGen = this.inGenerator, oldInAsync = this.inAsync, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
+  let oldInGen = this.inGenerator, oldInAsync = this.inAsync,
+      oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction
 
   this.initFunction(node)
   if (this.options.ecmaVersion >= 8)
@@ -654,6 +670,7 @@ pp.parseArrowExpression = function(node, params, isAsync) {
   this.inAsync = node.async
   this.yieldPos = 0
   this.awaitPos = 0
+  this.inFunction = true
 
   node.params = this.toAssignableList(params, true)
   this.parseFunctionBody(node, true)
@@ -662,6 +679,7 @@ pp.parseArrowExpression = function(node, params, isAsync) {
   this.inAsync = oldInAsync
   this.yieldPos = oldYieldPos
   this.awaitPos = oldAwaitPos
+  this.inFunction = oldInFunc
   return this.finishNode(node, "ArrowFunctionExpression")
 }
 
@@ -669,29 +687,32 @@ pp.parseArrowExpression = function(node, params, isAsync) {
 
 pp.parseFunctionBody = function(node, isArrowFunction) {
   let isExpression = isArrowFunction && this.type !== tt.braceL
+  let oldStrict = this.strict, useStrict = false
 
   if (isExpression) {
     node.body = this.parseMaybeAssign()
     node.expression = true
   } else {
+    let nonSimple = this.options.ecmaVersion >= 7 && !this.isSimpleParamList(node.params)
+    if (!oldStrict || nonSimple) {
+      useStrict = this.strictDirective(this.end)
+      // If this is a strict mode function, verify that argument names
+      // are not repeated, and it does not try to bind the words `eval`
+      // or `arguments`.
+      if (useStrict && nonSimple)
+        this.raiseRecoverable(node.start, "Illegal 'use strict' directive in function with non-simple parameter list")
+    }
     // Start a new scope with regard to labels and the `inFunction`
     // flag (restore them to their old value afterwards).
-    let oldInFunc = this.inFunction, oldLabels = this.labels
-    this.inFunction = true; this.labels = []
+    let oldLabels = this.labels
+    this.labels = []
+    if (useStrict) this.strict = true
     node.body = this.parseBlock(true)
     node.expression = false
-    this.inFunction = oldInFunc; this.labels = oldLabels
+    this.labels = oldLabels
   }
 
-  // If this is a strict mode function, verify that argument names
-  // are not repeated, and it does not try to bind the words `eval`
-  // or `arguments`.
-  let useStrict = (!isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) ? node.body.body[0] : null
-  if (useStrict && this.options.ecmaVersion >= 7 && !this.isSimpleParamList(node.params))
-    this.raiseRecoverable(useStrict.start, "Illegal 'use strict' directive in function with non-simple parameter list")
-
-  if (this.strict || useStrict) {
-    let oldStrict = this.strict
+  if (oldStrict || useStrict) {
     this.strict = true
     if (node.id)
       this.checkLVal(node.id, true)
@@ -735,11 +756,11 @@ pp.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructur
       elt = null
     else if (this.type === tt.ellipsis) {
       elt = this.parseSpread(refDestructuringErrors)
-      if (this.type === tt.comma && refDestructuringErrors && !refDestructuringErrors.trailingComma) {
+      if (refDestructuringErrors && this.type === tt.comma && refDestructuringErrors.trailingComma < 0)
         refDestructuringErrors.trailingComma = this.start
-      }
-    } else
+    } else {
       elt = this.parseMaybeAssign(false, refDestructuringErrors)
+    }
     elts.push(elt)
   }
   return elts
diff --git a/src/index.js b/src/index.js
index 9debb0a..3f93d1e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -30,13 +30,13 @@ export {Parser, plugins} from "./state"
 export {defaultOptions} from "./options"
 export {Position, SourceLocation, getLineInfo} from "./locutil"
 export {Node} from "./node"
-export {TokenType, types as tokTypes} from "./tokentype"
+export {TokenType, types as tokTypes, keywords as keywordTypes} from "./tokentype"
 export {TokContext, types as tokContexts} from "./tokencontext"
 export {isIdentifierChar, isIdentifierStart} from "./identifier"
 export {Token} from "./tokenize"
 export {isNewLine, lineBreak, lineBreakG} from "./whitespace"
 
-export const version = "4.0.4"
+export const version = "4.0.11"
 
 // The main exported interface (under `self.acorn` when in the
 // browser) is a `parse` function that takes a code string and
diff --git a/src/loose/expression.js b/src/loose/expression.js
index 1ef11b8..321ca66 100644
--- a/src/loose/expression.js
+++ b/src/loose/expression.js
@@ -280,7 +280,7 @@ lp.parseExprAtom = function() {
     return this.parseObj()
 
   case tt._class:
-    return this.parseClass()
+    return this.parseClass(false)
 
   case tt._function:
     node = this.startNode()
diff --git a/src/loose/statement.js b/src/loose/statement.js
index 42eda05..f4a3b1f 100644
--- a/src/loose/statement.js
+++ b/src/loose/statement.js
@@ -251,6 +251,7 @@ lp.parseVar = function(noIn, kind) {
 lp.parseClass = function(isStatement) {
   let node = this.startNode()
   this.next()
+  if (isStatement == null) isStatement = this.tok.type === tt.name
   if (this.tok.type === tt.name) node.id = this.parseIdent()
   else if (isStatement) node.id = this.dummyIdent()
   else node.id = null
@@ -325,6 +326,7 @@ lp.parseFunction = function(node, isStatement, isAsync) {
   if (this.options.ecmaVersion >= 8) {
     node.async = !!isAsync
   }
+  if (isStatement == null) isStatement = this.tok.type === tt.name
   if (this.tok.type === tt.name) node.id = this.parseIdent()
   else if (isStatement) node.id = this.dummyIdent()
   this.inAsync = node.async
@@ -343,16 +345,18 @@ lp.parseExport = function() {
   }
   if (this.eat(tt._default)) {
     // export default (function foo() {}) // This is FunctionExpression.
-    let isParenL = this.tok.type === tt.parenL
-    let expr = this.parseMaybeAssign()
-    if (!isParenL && expr.id) {
-      switch (expr.type) {
-      case "FunctionExpression": expr.type = "FunctionDeclaration"; break
-      case "ClassExpression": expr.type = "ClassDeclaration"; break
-      }
+    let isAsync
+    if (this.tok.type === tt._function || (isAsync = this.toks.isAsyncFunction())) {
+      let fNode = this.startNode()
+      this.next()
+      if (isAsync) this.next()
+      node.declaration = this.parseFunction(fNode, null, isAsync)
+    } else if (this.tok.type === tt._class) {
+      node.declaration = this.parseClass(null)
+    } else {
+      node.declaration = this.parseMaybeAssign()
+      this.semicolon()
     }
-    node.declaration = expr
-    this.semicolon()
     return this.finishNode(node, "ExportDefaultDeclaration")
   }
   if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) {
diff --git a/src/parseutil.js b/src/parseutil.js
index 55d1034..46e4521 100644
--- a/src/parseutil.js
+++ b/src/parseutil.js
@@ -1,17 +1,21 @@
 import {types as tt} from "./tokentype"
 import {Parser} from "./state"
-import {lineBreak} from "./whitespace"
+import {lineBreak, skipWhiteSpace} from "./whitespace"
 
 const pp = Parser.prototype
 
 // ## Parser utilities
 
-// Test whether a statement node is the string literal `"use strict"`.
-
-pp.isUseStrict = function(stmt) {
-  return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" &&
-    stmt.expression.type === "Literal" &&
-    stmt.expression.raw.slice(1, -1) === "use strict"
+const literal = /^(?:'((?:[^\']|\.)*)'|"((?:[^\"]|\.)*)"|;)/
+pp.strictDirective = function(start) {
+  for (;;) {
+    skipWhiteSpace.lastIndex = start
+    start += skipWhiteSpace.exec(this.input)[0].length
+    let match = literal.exec(this.input.slice(start))
+    if (!match) return false
+    if ((match[1] || match[2]) == "use strict") return true
+    start += match[0].length
+  }
 }
 
 // Predicate that tests whether the next token is of the given
@@ -92,21 +96,22 @@ pp.unexpected = function(pos) {
 
 export class DestructuringErrors {
   constructor() {
-    this.shorthandAssign = 0
-    this.trailingComma = 0
+    this.shorthandAssign = this.trailingComma = this.parenthesizedAssign = this.parenthesizedBind = -1
   }
 }
 
-pp.checkPatternErrors = function(refDestructuringErrors, andThrow) {
-  let trailing = refDestructuringErrors && refDestructuringErrors.trailingComma
-  if (!andThrow) return !!trailing
-  if (trailing) this.raise(trailing, "Comma is not permitted after the rest element")
+pp.checkPatternErrors = function(refDestructuringErrors, isAssign) {
+  if (!refDestructuringErrors) return
+  if (refDestructuringErrors.trailingComma > -1)
+    this.raiseRecoverable(refDestructuringErrors.trailingComma, "Comma is not permitted after the rest element")
+  let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind
+  if (parens > -1) this.raiseRecoverable(parens, "Parenthesized pattern")
 }
 
 pp.checkExpressionErrors = function(refDestructuringErrors, andThrow) {
-  let pos = refDestructuringErrors && refDestructuringErrors.shorthandAssign
-  if (!andThrow) return !!pos
-  if (pos) this.raise(pos, "Shorthand property assignments are valid only in destructuring patterns")
+  let pos = refDestructuringErrors ? refDestructuringErrors.shorthandAssign : -1
+  if (!andThrow) return pos >= 0
+  if (pos > -1) this.raise(pos, "Shorthand property assignments are valid only in destructuring patterns")
 }
 
 pp.checkYieldAwaitInDefaultParams = function() {
@@ -115,3 +120,9 @@ pp.checkYieldAwaitInDefaultParams = function() {
   if (this.awaitPos)
     this.raise(this.awaitPos, "Await expression cannot be a default value")
 }
+
+pp.isSimpleAssignTarget = function(expr) {
+  if (expr.type === "ParenthesizedExpression")
+    return this.isSimpleAssignTarget(expr.expression)
+  return expr.type === "Identifier" || expr.type === "MemberExpression"
+}
diff --git a/src/state.js b/src/state.js
index 1a8e293..4c244e4 100644
--- a/src/state.js
+++ b/src/state.js
@@ -69,7 +69,8 @@ export class Parser {
     this.exprAllowed = true
 
     // Figure out if it's a module code.
-    this.strict = this.inModule = options.sourceType === "module"
+    this.inModule = options.sourceType === "module"
+    this.strict = this.inModule || this.strictDirective(this.pos)
 
     // Used to signify the start of a potential arrow function
     this.potentialArrowAt = -1
diff --git a/src/statement.js b/src/statement.js
index 3cd2916..ee09613 100644
--- a/src/statement.js
+++ b/src/statement.js
@@ -14,15 +14,11 @@ const pp = Parser.prototype
 // to its body instead of creating a new node.
 
 pp.parseTopLevel = function(node) {
-  let first = true, exports = {}
+  let exports = {}
   if (!node.body) node.body = []
   while (this.type !== tt.eof) {
     let stmt = this.parseStatement(true, true, exports)
     node.body.push(stmt)
-    if (first) {
-      if (this.isUseStrict(stmt)) this.setStrict(true)
-      first = false
-    }
   }
   this.next()
   if (this.options.ecmaVersion >= 6) {
@@ -203,9 +199,9 @@ pp.parseForStatement = function(node) {
   let refDestructuringErrors = new DestructuringErrors
   let init = this.parseExpression(true, refDestructuringErrors)
   if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) {
-    this.checkPatternErrors(refDestructuringErrors, true)
     this.toAssignable(init)
     this.checkLVal(init)
+    this.checkPatternErrors(refDestructuringErrors, true)
     return this.parseForIn(node, init)
   } else {
     this.checkExpressionErrors(refDestructuringErrors, true)
@@ -357,6 +353,10 @@ pp.parseLabeledStatement = function(node, maybeName, expr) {
   }
   this.labels.push({name: maybeName, kind: kind, statementStart: this.start})
   node.body = this.parseStatement(true)
+  if (node.body.type == "ClassDeclaration" ||
+      node.body.type == "VariableDeclaration" && (this.strict || node.body.kind != "var") ||
+      node.body.type == "FunctionDeclaration" && (this.strict || node.body.generator))
+    this.raiseRecoverable(node.body.start, "Invalid labeled declaration")
   this.labels.pop()
   node.label = expr
   return this.finishNode(node, "LabeledStatement")
@@ -372,20 +372,14 @@ pp.parseExpressionStatement = function(node, expr) {
 // strict"` declarations when `allowStrict` is true (used for
 // function bodies).
 
-pp.parseBlock = function(allowStrict) {
-  let node = this.startNode(), first = true, oldStrict
+pp.parseBlock = function() {
+  let node = this.startNode()
   node.body = []
   this.expect(tt.braceL)
   while (!this.eat(tt.braceR)) {
     let stmt = this.parseStatement(true)
     node.body.push(stmt)
-    if (first && allowStrict && this.isUseStrict(stmt)) {
-      oldStrict = this.strict
-      this.setStrict(this.strict = true)
-    }
-    first = false
   }
-  if (oldStrict === false) this.setStrict(false)
   return this.finishNode(node, "BlockStatement")
 }
 
@@ -457,14 +451,18 @@ pp.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) {
   if (this.options.ecmaVersion >= 8)
     node.async = !!isAsync
 
+  if (isStatement == null)
+    isStatement = this.type == tt.name
   if (isStatement)
     node.id = this.parseIdent()
 
-  let oldInGen = this.inGenerator, oldInAsync = this.inAsync, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos
+  let oldInGen = this.inGenerator, oldInAsync = this.inAsync,
+      oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction
   this.inGenerator = node.generator
   this.inAsync = node.async
   this.yieldPos = 0
   this.awaitPos = 0
+  this.inFunction = true
 
   if (!isStatement && this.type === tt.name)
     node.id = this.parseIdent()
@@ -475,6 +473,7 @@ pp.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) {
   this.inAsync = oldInAsync
   this.yieldPos = oldYieldPos
   this.awaitPos = oldAwaitPos
+  this.inFunction = oldInFunc
   return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression")
 }
 
@@ -489,6 +488,7 @@ pp.parseFunctionParams = function(node) {
 
 pp.parseClass = function(node, isStatement) {
   this.next()
+  if (isStatement == null) isStatement = this.type === tt.name
   this.parseClassId(node, isStatement)
   this.parseClassSuper(node)
   let classBody = this.startNode()
@@ -578,20 +578,19 @@ pp.parseExport = function(node, exports) {
   }
   if (this.eat(tt._default)) { // export default ...
     this.checkExport(exports, "default", this.lastTokStart)
-    let parens = this.type == tt.parenL
-    let expr = this.parseMaybeAssign()
-    let needsSemi = true
-    if (!parens && (expr.type == "FunctionExpression" ||
-                    expr.type == "ClassExpression")) {
-      needsSemi = false
-      if (expr.id) {
-        expr.type = expr.type == "FunctionExpression"
-          ? "FunctionDeclaration"
-          : "ClassDeclaration"
-      }
+    let isAsync
+    if (this.type === tt._function || (isAsync = this.isAsyncFunction())) {
+      let fNode = this.startNode()
+      this.next()
+      if (isAsync) this.next()
+      node.declaration = this.parseFunction(fNode, null, false, isAsync)
+    } else if (this.type === tt._class) {
+      let cNode = this.startNode()
+      node.declaration = this.parseClass(cNode, null)
+    } else {
+      node.declaration = this.parseMaybeAssign()
+      this.semicolon()
     }
-    node.declaration = expr
-    if (needsSemi) this.semicolon()
     return this.finishNode(node, "ExportDefaultDeclaration")
   }
   // export var|const|let|function|class ...
@@ -676,7 +675,7 @@ pp.parseExportSpecifiers = function(exports) {
     } else first = false
 
     let node = this.startNode()
-    node.local = this.parseIdent(this.type === tt._default)
+    node.local = this.parseIdent(true)
     node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local
     this.checkExport(exports, node.exported.name, node.exported.start)
     nodes.push(this.finishNode(node, "ExportSpecifier"))
diff --git a/src/tokenize.js b/src/tokenize.js
index 08ea7bf..9a34ba7 100644
--- a/src/tokenize.js
+++ b/src/tokenize.js
@@ -62,19 +62,6 @@ if (typeof Symbol !== "undefined")
 // Toggle strict mode. Re-reads the next number or string to please
 // pedantic tests (`"use strict"; 010;` should fail).
 
-pp.setStrict = function(strict) {
-  this.strict = strict
-  if (this.type !== tt.num && this.type !== tt.string) return
-  this.pos = this.start
-  if (this.options.locations) {
-    while (this.pos < this.lineStart) {
-      this.lineStart = this.input.lastIndexOf("\n", this.lineStart - 2) + 1
-      --this.curLine
-    }
-  }
-  this.nextToken()
-}
-
 pp.curContext = function() {
   return this.context[this.context.length - 1]
 }
@@ -691,7 +678,9 @@ pp.readWord1 = function() {
 pp.readWord = function() {
   let word = this.readWord1()
   let type = tt.name
-  if ((this.options.ecmaVersion >= 6 || !this.containsEsc) && this.keywords.test(word))
+  if (this.keywords.test(word)) {
+    if (this.containsEsc) this.raiseRecoverable(this.start, "Escape sequence in keyword " + word)
     type = keywordTypes[word]
+  }
   return this.finishToken(type, word)
 }
diff --git a/test/tests-asyncawait.js b/test/tests-asyncawait.js
index 8b699c9..53c72a1 100644
--- a/test/tests-asyncawait.js
+++ b/test/tests-asyncawait.js
@@ -3105,4 +3105,8 @@ test(
     }]
   },
   {ecmaVersion: 8}
-)
\ No newline at end of file
+)
+
+testFail("(async)(a) => 12", "Unexpected token (1:11)", {ecmaVersion: 8})
+
+testFail("f = async ((x)) => x", "Parenthesized pattern (1:11)", {ecmaVersion: 8})
diff --git a/test/tests-es7.js b/test/tests-es7.js
index 11637b3..8c77eab 100644
--- a/test/tests-es7.js
+++ b/test/tests-es7.js
@@ -344,10 +344,10 @@ test("a-- ** 2", {
   "sourceType": "script"
 }, {ecmaVersion: 7})
 
-testFail("function foo(a=2) { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:20)", { ecmaVersion: 7 })
-testFail("(a=2) => { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:11)", { ecmaVersion: 7 })
-testFail("function foo({a}) { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:20)", { ecmaVersion: 7 })
-testFail("({a}) => { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:11)", { ecmaVersion: 7 })
+testFail("function foo(a=2) { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 })
+testFail("(a=2) => { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 })
+testFail("function foo({a}) { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 })
+testFail("({a}) => { 'use strict'; }", "Illegal 'use strict' directive in function with non-simple parameter list (1:0)", { ecmaVersion: 7 })
 test("function foo(a) { 'use strict'; }", {}, { ecmaVersion: 7 });
 
 // Tests for B.3.4 FunctionDeclarations in IfStatement Statement Clauses
@@ -387,4 +387,8 @@ testFail(
   "'use strict'; if(x) function f() {}",
   "Unexpected token (1:20)",
   { ecmaVersion: 7 }
-)
\ No newline at end of file
+)
+
+testFail("'use strict'; function y(x = 1) { 'use strict' }",
+         "Illegal 'use strict' directive in function with non-simple parameter list (1:14)",
+         {ecmaVersion: 7})
diff --git a/test/tests-harmony.js b/test/tests-harmony.js
index ddd27d5..e11a910 100644
--- a/test/tests-harmony.js
+++ b/test/tests-harmony.js
@@ -3132,7 +3132,7 @@ test("[a, b] = [b, a]", {
   locations: true
 });
 
-test("({ responseText: text }) = res", {
+test("({ responseText: text } = res)", {
   type: "Program",
   body: [{
     type: "ExpressionStatement",
@@ -3177,13 +3177,13 @@ test("({ responseText: text }) = res", {
         type: "Identifier",
         name: "res",
         loc: {
-          start: {line: 1, column: 27},
-          end: {line: 1, column: 30}
+          start: {line: 1, column: 26},
+          end: {line: 1, column: 29}
         }
       },
       loc: {
-        start: {line: 1, column: 0},
-        end: {line: 1, column: 30}
+        start: {line: 1, column: 1},
+        end: {line: 1, column: 29}
       }
     },
     loc: {
@@ -4582,7 +4582,6 @@ test("export { default } from \"other\"", {
 
 testFail("export { default }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" });
 testFail("export { if }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" });
-testFail("export { if } from 'foo'", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" });
 testFail("export { default as foo }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" });
 testFail("export { if as foo }", "Unexpected token (1:9)", {ecmaVersion: 6, sourceType: "module" });
 
@@ -12679,9 +12678,9 @@ testFail("[v] += ary", "Assigning to rvalue (1:0)", {ecmaVersion: 6});
 
 testFail("[2] = 42", "Assigning to rvalue (1:1)", {ecmaVersion: 6});
 
-testFail("({ obj:20 }) = 42", "Assigning to rvalue (1:7)", {ecmaVersion: 6});
+testFail("({ obj:20 }) = 42", "Parenthesized pattern (1:0)", {ecmaVersion: 6});
 
-testFail("( { get x() {} } ) = 0", "Object pattern can't contain getter or setter (1:8)", {ecmaVersion: 6});
+testFail("( { get x() {} } = 0)", "Object pattern can't contain getter or setter (1:8)", {ecmaVersion: 6});
 
 testFail("x \n is y", "Unexpected token (2:4)", {ecmaVersion: 6});
 
@@ -12701,9 +12700,9 @@ testFail("let default", "Unexpected token (1:4)", {ecmaVersion: 6});
 
 testFail("const default", "Unexpected token (1:6)", {ecmaVersion: 6});
 
-testFail("\"use strict\"; ({ v: eval }) = obj", "Assigning to eval in strict mode (1:20)", {ecmaVersion: 6});
+testFail("\"use strict\"; ({ v: eval } = obj)", "Assigning to eval in strict mode (1:20)", {ecmaVersion: 6});
 
-testFail("\"use strict\"; ({ v: arguments }) = obj", "Assigning to arguments in strict mode (1:20)", {ecmaVersion: 6});
+testFail("\"use strict\"; ({ v: arguments } = obj)", "Assigning to arguments in strict mode (1:20)", {ecmaVersion: 6});
 
 testFail("for (let x = 42 in list) process(x);", "Unexpected token (1:16)", {ecmaVersion: 6});
 
@@ -12715,9 +12714,9 @@ testFail("import { foo, bar }", "Unexpected token (1:19)", {ecmaVersion: 6, sour
 
 testFail("import foo from bar", "Unexpected token (1:16)", {ecmaVersion: 6, sourceType: "module"});
 
-testFail("((a)) => 42", "Unexpected token (1:1)", {ecmaVersion: 6});
+testFail("((a)) => 42", "Parenthesized pattern (1:1)", {ecmaVersion: 6});
 
-testFail("(a, (b)) => 42", "Unexpected token (1:4)", {ecmaVersion: 6});
+testFail("(a, (b)) => 42", "Parenthesized pattern (1:4)", {ecmaVersion: 6});
 
 testFail("\"use strict\"; (eval = 10) => 42", "Assigning to eval in strict mode (1:15)", {ecmaVersion: 6});
 
@@ -15497,6 +15496,43 @@ test("function* wrap() {\n({a = yield b} = obj)\n}", {
   ],
   "sourceType": "script"
 }, {ecmaVersion: 6})
+
+test("export default class Foo {}++x", {
+  "type": "Program",
+  "body": [
+    {
+      "type": "ExportDefaultDeclaration",
+      "declaration": {
+        "type": "ClassDeclaration",
+        "id": {
+          "type": "Identifier",
+          "name": "Foo"
+        },
+        "superClass": null,
+        "body": {
+          "type": "ClassBody",
+          "body": []
+        }
+      }
+    },
+    {
+      "type": "ExpressionStatement",
+      "expression": {
+        "type": "UpdateExpression",
+        "operator": "++",
+        "prefix": true,
+        "argument": {
+          "type": "Identifier",
+          "name": "x"
+        }
+      }
+    }
+  ],
+  "sourceType": "module"
+}, {ecmaVersion: 6, sourceType: "module"})
+
+test("class B extends A { foo(a = super.foo()) { return a }}", {}, {ecmaVersion: 6})
+
 testFail("function* wrap() {\n({a = yield b} = obj) => a\n}", "Yield expression cannot be a default value (2:6)", {ecmaVersion: 6})
 
 // invalid syntax '*foo: 1'
@@ -15511,3 +15547,13 @@ test("export { default as y } from './y.js';\nexport default 42;",
 testFail("export { default} from './y.js';\nexport default 42;",
          "Duplicate export 'default' (2:7)",
          {sourceType: "module", ecmaVersion: 6})
+
+testFail("foo: class X {}", "Invalid labeled declaration (1:5)", {ecmaVersion: 6})
+
+testFail("'use strict'; bar: function x() {}", "Invalid labeled declaration (1:19)", {ecmaVersion: 6})
+
+testFail("({x, y}) = {}", "Parenthesized pattern (1:0)", {ecmaVersion: 6})
+
+test("[x, (y), {z, u: (v)}] = foo", {}, {ecmaVersion: 6})
+
+test("export default function(x) {};", {body: [{}, {}]}, {ecmaVersion: 6, sourceType: "module"})
diff --git a/test/tests.js b/test/tests.js
index 7519951..a10aeaa 100644
--- a/test/tests.js
+++ b/test/tests.js
@@ -403,24 +403,24 @@ test("(1 + 2 ) * 3", {
   preserveParens: true
 });
 
-test("(x) = 23", {
+test("(x = 23)", {
   body: [
     {
       expression: {
-        operator: "=",
-        left: {
-          expression: {
+        type: "ParenthesizedExpression",
+        expression: {
+          type: "AssignmentExpression",
+          operator: "=",
+          left: {
             name: "x",
             type: "Identifier",
           },
-          type: "ParenthesizedExpression",
-        },
-        right: {
-          value: 23,
-          raw: "23",
-          type: "Literal",
+          right: {
+            value: 23,
+            raw: "23",
+            type: "Literal",
+          },
         },
-        type: "AssignmentExpression",
       },
       type: "ExpressionStatement",
     }
@@ -26988,7 +26988,7 @@ testFail("func() = 4",
          "Assigning to rvalue (1:0)");
 
 testFail("(1 + 1) = 10",
-         "Assigning to rvalue (1:1)");
+         "Parenthesized pattern (1:0)");
 
 testFail("1++",
          "Assigning to rvalue (1:0)");
@@ -27310,6 +27310,8 @@ testFail("x: while (true) { x: while (true) { } }",
 testFail("(function () { 'use strict'; delete i; }())",
          "Deleting local variable in strict mode (1:29)");
 
+testFail("function x() { '\\12'; 'use strict'; }", "Octal literal in strict mode (1:16)")
+
 testFail("(function () { 'use strict'; with (i); }())",
          "'with' in strict mode (1:29)");
 
@@ -29169,3 +29171,15 @@ test("0123. in/foo/i", {
 })
 
 test("undefined", {}, { ecmaVersion: 8 })
+
+testFail("\\u{74}rue", "Escape sequence in keyword true (1:0)", {ecmaVersion: 6})
+
+testFail("(x=1)=2", "Parenthesized pattern (1:0)")
+
+test("(foo = [])[0] = 4;", {})
+
+test("for ((foo = []).bar in {}) {}", {})
+
+test("((b), a=1)", {})
+
+test("(x) = 1", {})

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/acorn.git



More information about the Pkg-javascript-commits mailing list