[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