diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index d88bf86266d0..86c4f0808d78 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -41,6 +41,7 @@ import { SCOPE_PROGRAM, SCOPE_ASYNC, } from "../util/scopeflags"; +import { ExpressionErrors } from "./util"; export default class ExpressionParser extends LValParser { // Forward-declaration: defined in statement.js @@ -69,7 +70,8 @@ export default class ExpressionParser extends LValParser { checkDuplicatedProto( prop: N.ObjectMember | N.SpreadElement, - protoRef: { used: boolean, start?: number }, + protoRef: { used: boolean }, + refExpressionErrors: ?ExpressionErrors, ): void { if ( prop.type === "SpreadElement" || @@ -87,8 +89,12 @@ export default class ExpressionParser extends LValParser { if (name === "__proto__") { // Store the first redefinition's position - if (protoRef.used && !protoRef.start) { - protoRef.start = key.start; + if (protoRef.used) { + if (refExpressionErrors && refExpressionErrors.doubleProto === -1) { + refExpressionErrors.doubleProto = key.start; + } else { + this.raise(key.start, "Redefinition of __proto__ property"); + } } protoRef.used = true; @@ -127,17 +133,18 @@ export default class ExpressionParser extends LValParser { // and object pattern might appear (so it's possible to raise // delayed syntax error at correct position). - parseExpression(noIn?: boolean, refShorthandDefaultPos?: Pos): N.Expression { + parseExpression( + noIn?: boolean, + refExpressionErrors?: ExpressionErrors, + ): N.Expression { const startPos = this.state.start; const startLoc = this.state.startLoc; - const expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos); + const expr = this.parseMaybeAssign(noIn, refExpressionErrors); if (this.match(tt.comma)) { const node = this.startNodeAt(startPos, startLoc); node.expressions = [expr]; while (this.eat(tt.comma)) { - node.expressions.push( - this.parseMaybeAssign(noIn, refShorthandDefaultPos), - ); + node.expressions.push(this.parseMaybeAssign(noIn, refExpressionErrors)); } this.toReferencedList(node.expressions); return this.finishNode(node, "SequenceExpression"); @@ -150,7 +157,7 @@ export default class ExpressionParser extends LValParser { parseMaybeAssign( noIn?: ?boolean, - refShorthandDefaultPos?: ?Pos, + refExpressionErrors?: ?ExpressionErrors, afterLeftParse?: Function, refNeedsArrowPos?: ?Pos, ): N.Expression { @@ -170,12 +177,12 @@ export default class ExpressionParser extends LValParser { } } - let failOnShorthandAssign; - if (refShorthandDefaultPos) { - failOnShorthandAssign = false; + let ownExpressionErrors; + if (refExpressionErrors) { + ownExpressionErrors = false; } else { - refShorthandDefaultPos = { start: 0 }; - failOnShorthandAssign = true; + refExpressionErrors = new ExpressionErrors(); + ownExpressionErrors = true; } if (this.match(tt.parenL) || this.match(tt.name)) { @@ -184,7 +191,7 @@ export default class ExpressionParser extends LValParser { let left = this.parseMaybeConditional( noIn, - refShorthandDefaultPos, + refExpressionErrors, refNeedsArrowPos, ); if (afterLeftParse) { @@ -201,12 +208,15 @@ export default class ExpressionParser extends LValParser { if (operator === "||=" || operator === "&&=") { this.expectPlugin("logicalAssignment"); } - node.left = this.match(tt.eq) - ? this.toAssignable(left, undefined, "assignment expression") - : left; + if (this.match(tt.eq)) { + node.left = this.toAssignable(left, undefined, "assignment expression"); + refExpressionErrors.doubleProto = -1; // reset because double __proto__ is valid in assignment expression + } else { + node.left = left; + } - if (refShorthandDefaultPos.start >= node.left.start) { - refShorthandDefaultPos.start = 0; // reset because shorthand default was used correctly + if (refExpressionErrors.shorthandAssign >= node.left.start) { + refExpressionErrors.shorthandAssign = -1; // reset because shorthand default was used correctly } this.checkLVal(left, undefined, undefined, "assignment expression"); @@ -214,8 +224,8 @@ export default class ExpressionParser extends LValParser { this.next(); node.right = this.parseMaybeAssign(noIn); return this.finishNode(node, "AssignmentExpression"); - } else if (failOnShorthandAssign && refShorthandDefaultPos.start) { - this.unexpected(refShorthandDefaultPos.start); + } else if (ownExpressionErrors) { + this.checkExpressionErrors(refExpressionErrors, true); } return left; @@ -225,13 +235,13 @@ export default class ExpressionParser extends LValParser { parseMaybeConditional( noIn: ?boolean, - refShorthandDefaultPos: Pos, + refExpressionErrors: ExpressionErrors, refNeedsArrowPos?: ?Pos, ): N.Expression { const startPos = this.state.start; const startLoc = this.state.startLoc; const potentialArrowAt = this.state.potentialArrowAt; - const expr = this.parseExprOps(noIn, refShorthandDefaultPos); + const expr = this.parseExprOps(noIn, refExpressionErrors); if ( expr.type === "ArrowFunctionExpression" && @@ -239,7 +249,7 @@ export default class ExpressionParser extends LValParser { ) { return expr; } - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + if (this.checkExpressionErrors(refExpressionErrors, false)) return expr; return this.parseConditional( expr, @@ -272,11 +282,14 @@ export default class ExpressionParser extends LValParser { // Start the precedence parser. - parseExprOps(noIn: ?boolean, refShorthandDefaultPos: Pos): N.Expression { + parseExprOps( + noIn: ?boolean, + refExpressionErrors: ExpressionErrors, + ): N.Expression { const startPos = this.state.start; const startLoc = this.state.startLoc; const potentialArrowAt = this.state.potentialArrowAt; - const expr = this.parseMaybeUnary(refShorthandDefaultPos); + const expr = this.parseMaybeUnary(refExpressionErrors); if ( expr.type === "ArrowFunctionExpression" && @@ -284,7 +297,7 @@ export default class ExpressionParser extends LValParser { ) { return expr; } - if (refShorthandDefaultPos && refShorthandDefaultPos.start) { + if (this.checkExpressionErrors(refExpressionErrors, false)) { return expr; } @@ -463,7 +476,7 @@ export default class ExpressionParser extends LValParser { // Parse unary operators, both prefix and postfix. - parseMaybeUnary(refShorthandDefaultPos: ?Pos): N.Expression { + parseMaybeUnary(refExpressionErrors: ?ExpressionErrors): N.Expression { if (this.isContextual("await") && this.isAwaitAllowed()) { return this.parseAwait(); } else if (this.state.type.prefix) { @@ -479,9 +492,7 @@ export default class ExpressionParser extends LValParser { node.argument = this.parseMaybeUnary(); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) { - this.unexpected(refShorthandDefaultPos.start); - } + this.checkExpressionErrors(refExpressionErrors, true); if (update) { this.checkLVal(node.argument, undefined, undefined, "prefix operation"); @@ -506,8 +517,8 @@ export default class ExpressionParser extends LValParser { const startPos = this.state.start; const startLoc = this.state.startLoc; - let expr = this.parseExprSubscripts(refShorthandDefaultPos); - if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; + let expr = this.parseExprSubscripts(refExpressionErrors); + if (this.checkExpressionErrors(refExpressionErrors, false)) return expr; while (this.state.type.postfix && !this.canInsertSemicolon()) { const node = this.startNodeAt(startPos, startLoc); node.operator = this.state.value; @@ -522,11 +533,11 @@ export default class ExpressionParser extends LValParser { // Parse call, dot, and `[]`-subscript expressions. - parseExprSubscripts(refShorthandDefaultPos: ?Pos): N.Expression { + parseExprSubscripts(refExpressionErrors: ?ExpressionErrors): N.Expression { const startPos = this.state.start; const startLoc = this.state.startLoc; const potentialArrowAt = this.state.potentialArrowAt; - const expr = this.parseExprAtom(refShorthandDefaultPos); + const expr = this.parseExprAtom(refExpressionErrors); if ( expr.type === "ArrowFunctionExpression" && @@ -535,7 +546,7 @@ export default class ExpressionParser extends LValParser { return expr; } - if (refShorthandDefaultPos && refShorthandDefaultPos.start) { + if (this.checkExpressionErrors(refExpressionErrors, false)) { return expr; } @@ -816,7 +827,7 @@ export default class ExpressionParser extends LValParser { elts.push( this.parseExprListItem( false, - possibleAsyncArrow ? { start: 0 } : undefined, + possibleAsyncArrow ? new ExpressionErrors() : undefined, possibleAsyncArrow ? { start: 0 } : undefined, allowPlaceholder, ), @@ -864,7 +875,7 @@ export default class ExpressionParser extends LValParser { // `new`, or an expression wrapped in punctuation like `()`, `[]`, // or `{}`. - parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression { + parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression { // If a division operator appears in an expression position, the // tokenizer got confused, and we force it to read a regexp instead. if (this.state.type === tt.slash) this.readRegexp(); @@ -1038,7 +1049,7 @@ export default class ExpressionParser extends LValParser { node.elements = this.parseExprList( tt.bracketR, true, - refShorthandDefaultPos, + refExpressionErrors, node, ); if (!this.state.maybeInArrowParameters) { @@ -1056,7 +1067,7 @@ export default class ExpressionParser extends LValParser { const oldInFSharpPipelineDirectBody = this.state .inFSharpPipelineDirectBody; this.state.inFSharpPipelineDirectBody = false; - const ret = this.parseObj(false, refShorthandDefaultPos); + const ret = this.parseObj(false, refExpressionErrors); this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody; return ret; } @@ -1263,7 +1274,7 @@ export default class ExpressionParser extends LValParser { const innerStartPos = this.state.start; const innerStartLoc = this.state.startLoc; const exprList = []; - const refShorthandDefaultPos = { start: 0 }; + const refExpressionErrors = new ExpressionErrors(); const refNeedsArrowPos = { start: 0 }; let first = true; let spreadStart; @@ -1299,7 +1310,7 @@ export default class ExpressionParser extends LValParser { exprList.push( this.parseMaybeAssign( false, - refShorthandDefaultPos, + refExpressionErrors, this.parseParenItem, refNeedsArrowPos, ), @@ -1343,9 +1354,7 @@ export default class ExpressionParser extends LValParser { } if (optionalCommaStart) this.unexpected(optionalCommaStart); if (spreadStart) this.unexpected(spreadStart); - if (refShorthandDefaultPos.start) { - this.unexpected(refShorthandDefaultPos.start); - } + this.checkExpressionErrors(refExpressionErrors, true); if (refNeedsArrowPos.start) this.unexpected(refNeedsArrowPos.start); this.toReferencedListDeep(exprList, /* isParenthesizedExpr */ true); @@ -1490,7 +1499,7 @@ export default class ExpressionParser extends LValParser { parseObj( isPattern: boolean, - refShorthandDefaultPos?: ?Pos, + refExpressionErrors?: ?ExpressionErrors, ): T { const propHash: any = Object.create(null); let first = true; @@ -1511,9 +1520,11 @@ export default class ExpressionParser extends LValParser { } } - const prop = this.parseObjectMember(isPattern, refShorthandDefaultPos); - // $FlowIgnore RestElement will never be returned if !isPattern - if (!isPattern) this.checkDuplicatedProto(prop, propHash); + const prop = this.parseObjectMember(isPattern, refExpressionErrors); + if (!isPattern) { + // $FlowIgnore RestElement will never be returned if !isPattern + this.checkDuplicatedProto(prop, propHash, refExpressionErrors); + } // $FlowIgnore if (prop.shorthand) { @@ -1523,10 +1534,6 @@ export default class ExpressionParser extends LValParser { node.properties.push(prop); } - if (!this.match(tt.eq) && propHash.start !== undefined) { - this.raise(propHash.start, "Redefinition of __proto__ property"); - } - return this.finishNode( node, isPattern ? "ObjectPattern" : "ObjectExpression", @@ -1550,7 +1557,7 @@ export default class ExpressionParser extends LValParser { parseObjectMember( isPattern: boolean, - refShorthandDefaultPos: ?Pos, + refExpressionErrors?: ?ExpressionErrors, ): N.ObjectMember | N.SpreadElement | N.RestElement { let decorators = []; if (this.match(tt.at)) { @@ -1594,7 +1601,7 @@ export default class ExpressionParser extends LValParser { prop.method = false; - if (isPattern || refShorthandDefaultPos) { + if (isPattern || refExpressionErrors) { startPos = this.state.start; startLoc = this.state.startLoc; } @@ -1621,7 +1628,7 @@ export default class ExpressionParser extends LValParser { isGenerator, isAsync, isPattern, - refShorthandDefaultPos, + refExpressionErrors, containsEsc, ); @@ -1715,14 +1722,14 @@ export default class ExpressionParser extends LValParser { startPos: ?number, startLoc: ?Position, isPattern: boolean, - refShorthandDefaultPos: ?Pos, + refExpressionErrors: ?ExpressionErrors, ): ?N.ObjectProperty { prop.shorthand = false; if (this.eat(tt.colon)) { prop.value = isPattern ? this.parseMaybeDefault(this.state.start, this.state.startLoc) - : this.parseMaybeAssign(false, refShorthandDefaultPos); + : this.parseMaybeAssign(false, refExpressionErrors); return this.finishNode(prop, "ObjectProperty"); } @@ -1736,9 +1743,9 @@ export default class ExpressionParser extends LValParser { startLoc, prop.key.__clone(), ); - } else if (this.match(tt.eq) && refShorthandDefaultPos) { - if (!refShorthandDefaultPos.start) { - refShorthandDefaultPos.start = this.state.start; + } else if (this.match(tt.eq) && refExpressionErrors) { + if (refExpressionErrors.shorthandAssign === -1) { + refExpressionErrors.shorthandAssign = this.state.start; } prop.value = this.parseMaybeDefault( startPos, @@ -1761,7 +1768,7 @@ export default class ExpressionParser extends LValParser { isGenerator: boolean, isAsync: boolean, isPattern: boolean, - refShorthandDefaultPos: ?Pos, + refExpressionErrors?: ?ExpressionErrors, containsEsc: boolean, ): void { const node = @@ -1777,7 +1784,7 @@ export default class ExpressionParser extends LValParser { startPos, startLoc, isPattern, - refShorthandDefaultPos, + refExpressionErrors, ); if (!node) this.unexpected(); @@ -2019,7 +2026,7 @@ export default class ExpressionParser extends LValParser { parseExprList( close: TokenType, allowEmpty?: boolean, - refShorthandDefaultPos?: ?Pos, + refExpressionErrors?: ?ExpressionErrors, nodeForExtra?: ?N.Node, ): $ReadOnlyArray { const elts = []; @@ -2043,14 +2050,14 @@ export default class ExpressionParser extends LValParser { } } - elts.push(this.parseExprListItem(allowEmpty, refShorthandDefaultPos)); + elts.push(this.parseExprListItem(allowEmpty, refExpressionErrors)); } return elts; } parseExprListItem( allowEmpty: ?boolean, - refShorthandDefaultPos: ?Pos, + refExpressionErrors?: ?ExpressionErrors, refNeedsArrowPos: ?Pos, allowPlaceholder: ?boolean, ): ?N.Expression { @@ -2061,7 +2068,7 @@ export default class ExpressionParser extends LValParser { const spreadNodeStartPos = this.state.start; const spreadNodeStartLoc = this.state.startLoc; elt = this.parseParenItem( - this.parseSpread(refShorthandDefaultPos, refNeedsArrowPos), + this.parseSpread(refExpressionErrors, refNeedsArrowPos), spreadNodeStartPos, spreadNodeStartLoc, ); @@ -2076,7 +2083,7 @@ export default class ExpressionParser extends LValParser { } else { elt = this.parseMaybeAssign( false, - refShorthandDefaultPos, + refExpressionErrors, this.parseParenItem, refNeedsArrowPos, ); diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index 383b5f3edc1a..0bb6347ceaab 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -21,6 +21,7 @@ import { } from "../util/identifier"; import { NodeUtils } from "./node"; import { type BindingTypes, BIND_NONE } from "../util/scopeflags"; +import { ExpressionErrors } from "./util"; const unwrapParenthesizedExpression = (node: Node) => { return node.type === "ParenthesizedExpression" @@ -33,13 +34,13 @@ export default class LValParser extends NodeUtils { +parseIdentifier: (liberal?: boolean) => Identifier; +parseMaybeAssign: ( noIn?: ?boolean, - refShorthandDefaultPos?: ?Pos, + refExpressionErrors?: ?ExpressionErrors, afterLeftParse?: Function, refNeedsArrowPos?: ?Pos, ) => Expression; +parseObj: ( isPattern: boolean, - refShorthandDefaultPos?: ?Pos, + refExpressionErrors?: ?ExpressionErrors, ) => T; // Forward-declaration: defined in statement.js +parseDecorator: () => Decorator; @@ -241,14 +242,14 @@ export default class LValParser extends NodeUtils { // Parses spread element. parseSpread( - refShorthandDefaultPos: ?Pos, + refExpressionErrors: ?ExpressionErrors, refNeedsArrowPos?: ?Pos, ): SpreadElement { const node = this.startNode(); this.next(); node.argument = this.parseMaybeAssign( false, - refShorthandDefaultPos, + refExpressionErrors, undefined, refNeedsArrowPos, ); diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 85e177564676..a57a618c9748 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -27,6 +27,7 @@ import { CLASS_ELEMENT_STATIC_SETTER, type BindingTypes, } from "../util/scopeflags"; +import { ExpressionErrors } from "./util"; const loopLabel = { kind: "loop" }, switchLabel = { kind: "switch" }; @@ -533,8 +534,8 @@ export default class StatementParser extends ExpressionParser { return this.parseFor(node, init); } - const refShorthandDefaultPos = { start: 0 }; - const init = this.parseExpression(true, refShorthandDefaultPos); + const refExpressionErrors = new ExpressionErrors(); + const init = this.parseExpression(true, refExpressionErrors); if (this.match(tt._in) || this.isContextual("of")) { const description = this.isContextual("of") ? "for-of statement" @@ -542,8 +543,8 @@ export default class StatementParser extends ExpressionParser { this.toAssignable(init, undefined, description); this.checkLVal(init, undefined, undefined, description); return this.parseForIn(node, init, awaitAt); - } else if (refShorthandDefaultPos.start) { - this.unexpected(refShorthandDefaultPos.start); + } else { + this.checkExpressionErrors(refExpressionErrors, true); } if (awaitAt > -1) { this.unexpected(awaitAt); diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index e37becfa1a73..ceb42ef5a410 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -268,4 +268,35 @@ export default class UtilParser extends Tokenizer { throw error; } } + + checkExpressionErrors( + refExpressionErrors: ?ExpressionErrors, + andThrow: boolean, + ) { + if (!refExpressionErrors) return false; + const { shorthandAssign, doubleProto } = refExpressionErrors; + if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0; + if (shorthandAssign >= 0) { + this.unexpected(shorthandAssign); + } + if (doubleProto >= 0) { + this.raise(doubleProto, "Redefinition of __proto__ property"); + } + } +} + +/** + * The ExpressionErrors is a context struct used to track + * - **shorthandAssign**: track initializer `=` position when parsing ambiguous + * patterns. When we are sure the parsed pattern is a RHS, which means it is + * not a pattern, we will throw on this position on invalid assign syntax, + * otherwise it will be reset to -1 + * - **doubleProto**: track the duplicate `__proto__` key position when parsing + * ambiguous object patterns. When we are sure the parsed pattern is a RHS, + * which means it is an object literal, we will throw on this position for + * __proto__ redefinition, otherwise it will be reset to -1 + */ +export class ExpressionErrors { + shorthandAssign = -1; + doubleProto = -1; } diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index 5fd0ab11350c..9cd825945015 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -4,8 +4,9 @@ import { types as tt, TokenType } from "../tokenizer/types"; import type Parser from "../parser"; +import type { ExpressionErrors } from "../parser/util"; import * as N from "../types"; -import type { Pos, Position } from "../util/location"; +import type { Position } from "../util/location"; import { type BindingTypes, BIND_NONE } from "../util/scopeflags"; function isSimpleProperty(node: N.Node): boolean { @@ -148,7 +149,8 @@ export default (superClass: Class): Class => checkDuplicatedProto( prop: N.ObjectMember | N.SpreadElement, - protoRef: { used: boolean, start?: number }, + protoRef: { used: boolean }, + refExpressionErrors: ?ExpressionErrors, ): void { if ( prop.type === "SpreadElement" || @@ -166,8 +168,12 @@ export default (superClass: Class): Class => if (name === "__proto__" && prop.kind === "init") { // Store the first redefinition's position - if (protoRef.used && !protoRef.start) { - protoRef.start = key.start; + if (protoRef.used) { + if (refExpressionErrors && refExpressionErrors.doubleProto === -1) { + refExpressionErrors.doubleProto = key.start; + } else { + this.raise(key.start, "Redefinition of __proto__ property"); + } } protoRef.used = true; @@ -234,7 +240,7 @@ export default (superClass: Class): Class => classBody.body.push(method); } - parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression { + parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression { switch (this.state.type) { case tt.num: case tt.string: @@ -256,7 +262,7 @@ export default (superClass: Class): Class => return this.estreeParseLiteral(false); default: - return super.parseExprAtom(refShorthandDefaultPos); + return super.parseExprAtom(refExpressionErrors); } } @@ -340,14 +346,14 @@ export default (superClass: Class): Class => startPos: ?number, startLoc: ?Position, isPattern: boolean, - refShorthandDefaultPos: ?Pos, + refExpressionErrors: ?ExpressionErrors, ): ?N.ObjectProperty { const node: N.EstreeProperty = (super.parseObjectProperty( prop, startPos, startLoc, isPattern, - refShorthandDefaultPos, + refExpressionErrors, ): any); if (node) { diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index 42f864a2069d..2ab7604514d1 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -21,6 +21,7 @@ import { SCOPE_ARROW, SCOPE_OTHER, } from "../util/scopeflags"; +import type { ExpressionErrors } from "../parser/util"; const reservedTypes = new Set([ "_", @@ -2283,7 +2284,7 @@ export default (superClass: Class): Class => isGenerator: boolean, isAsync: boolean, isPattern: boolean, - refShorthandDefaultPos: ?Pos, + refExpressionErrors: ?ExpressionErrors, containsEsc: boolean, ): void { if ((prop: $FlowFixMe).variance) { @@ -2306,7 +2307,7 @@ export default (superClass: Class): Class => isGenerator, isAsync, isPattern, - refShorthandDefaultPos, + refExpressionErrors, containsEsc, ); @@ -2559,7 +2560,7 @@ export default (superClass: Class): Class => // 3. This is neither. Just call the super method parseMaybeAssign( noIn?: ?boolean, - refShorthandDefaultPos?: ?Pos, + refExpressionErrors?: ?ExpressionErrors, afterLeftParse?: Function, refNeedsArrowPos?: ?Pos, ): N.Expression { @@ -2577,7 +2578,7 @@ export default (superClass: Class): Class => () => super.parseMaybeAssign( noIn, - refShorthandDefaultPos, + refExpressionErrors, afterLeftParse, refNeedsArrowPos, ), @@ -2611,7 +2612,7 @@ export default (superClass: Class): Class => () => super.parseMaybeAssign( noIn, - refShorthandDefaultPos, + refExpressionErrors, afterLeftParse, refNeedsArrowPos, ), @@ -2659,7 +2660,7 @@ export default (superClass: Class): Class => return super.parseMaybeAssign( noIn, - refShorthandDefaultPos, + refExpressionErrors, afterLeftParse, refNeedsArrowPos, ); diff --git a/packages/babel-parser/src/plugins/jsx/index.js b/packages/babel-parser/src/plugins/jsx/index.js index 2aba709267f2..fce057e48b74 100644 --- a/packages/babel-parser/src/plugins/jsx/index.js +++ b/packages/babel-parser/src/plugins/jsx/index.js @@ -4,11 +4,12 @@ import * as charCodes from "charcodes"; import XHTMLEntities from "./xhtml"; import type Parser from "../../parser"; +import type { ExpressionErrors } from "../../parser/util"; import { TokenType, types as tt } from "../../tokenizer/types"; import { TokContext, types as tc } from "../../tokenizer/context"; import * as N from "../../types"; import { isIdentifierChar, isIdentifierStart } from "../../util/identifier"; -import type { Pos, Position } from "../../util/location"; +import type { Position } from "../../util/location"; import { isNewLine } from "../../util/whitespace"; const HEX_NUMBER = /^[\da-fA-F]+$/; @@ -510,7 +511,7 @@ export default (superClass: Class): Class => // Overrides // ================================== - parseExprAtom(refShortHandDefaultPos: ?Pos): N.Expression { + parseExprAtom(refExpressionErrors: ?ExpressionErrors): N.Expression { if (this.match(tt.jsxText)) { return this.parseLiteral(this.state.value, "JSXText"); } else if (this.match(tt.jsxTagStart)) { @@ -524,7 +525,7 @@ export default (superClass: Class): Class => this.finishToken(tt.jsxTagStart); return this.jsxParseElement(); } else { - return super.parseExprAtom(refShortHandDefaultPos); + return super.parseExprAtom(refExpressionErrors); } } diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index b53dca72d61c..08691c5b90ba 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -25,6 +25,7 @@ import { } from "../../util/scopeflags"; import TypeScriptScopeHandler from "./scope"; import * as charCodes from "charcodes"; +import type { ExpressionErrors } from "../../parser/util"; type TsModifier = | "readonly" @@ -2340,11 +2341,11 @@ export default (superClass: Class): Class => } // Handle type assertions - parseMaybeUnary(refShorthandDefaultPos?: ?Pos): N.Expression { + parseMaybeUnary(refExpressionErrors?: ?ExpressionErrors): N.Expression { if (!this.hasPlugin("jsx") && this.isRelational("<")) { return this.tsParseTypeAssertion(); } else { - return super.parseMaybeUnary(refShorthandDefaultPos); + return super.parseMaybeUnary(refExpressionErrors); } } diff --git a/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto/input.js b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-1/input.js similarity index 100% rename from packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto/input.js rename to packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-1/input.js diff --git a/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto/output.json b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-1/output.json similarity index 100% rename from packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto/output.json rename to packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-1/output.json diff --git a/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-2/input.js b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-2/input.js new file mode 100644 index 000000000000..73d46e315061 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-2/input.js @@ -0,0 +1 @@ +([{ __proto__: x, __proto__: y }] = [{}]); diff --git a/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-2/output.json b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-2/output.json new file mode 100644 index 000000000000..3646ce22df38 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-2/output.json @@ -0,0 +1,241 @@ +{ + "type": "File", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "expression": { + "type": "AssignmentExpression", + "start": 1, + "end": 40, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 40 + } + }, + "operator": "=", + "left": { + "type": "ArrayPattern", + "start": 1, + "end": 33, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 33 + } + }, + "elements": [ + { + "type": "ObjectPattern", + "start": 2, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "properties": [ + { + "type": "ObjectProperty", + "start": 4, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 16 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 4, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "Identifier", + "start": 15, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 16 + }, + "identifierName": "x" + }, + "name": "x" + } + }, + { + "type": "ObjectProperty", + "start": 18, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 18, + "end": 27, + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 27 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "Identifier", + "start": 29, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 30 + }, + "identifierName": "y" + }, + "name": "y" + } + } + ] + } + ] + }, + "right": { + "type": "ArrayExpression", + "start": 36, + "end": 40, + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 40 + } + }, + "elements": [ + { + "type": "ObjectExpression", + "start": 37, + "end": 39, + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 39 + } + }, + "properties": [] + } + ] + }, + "extra": { + "parenthesized": true, + "parenStart": 0 + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-3/input.js b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-3/input.js new file mode 100644 index 000000000000..478c33774b46 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-3/input.js @@ -0,0 +1 @@ +({ __proto__: x, __proto__: y }) => {}; diff --git a/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-3/output.json b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-3/output.json new file mode 100644 index 000000000000..27df8bb4401e --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/destructuring/duplicate-proto-3/output.json @@ -0,0 +1,208 @@ +{ + "type": "File", + "start": 0, + "end": 39, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 39 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 39, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 39 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 39, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 39 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 38, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 38 + } + }, + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "ObjectPattern", + "start": 1, + "end": 31, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 31 + } + }, + "properties": [ + { + "type": "ObjectProperty", + "start": 3, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 15 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 3, + "end": 12, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 12 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "Identifier", + "start": 14, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + }, + "identifierName": "x" + }, + "name": "x" + } + }, + { + "type": "ObjectProperty", + "start": 17, + "end": 29, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 29 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 17, + "end": 26, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 26 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "Identifier", + "start": 28, + "end": 29, + "loc": { + "start": { + "line": 1, + "column": 28 + }, + "end": { + "line": 1, + "column": 29 + }, + "identifierName": "y" + }, + "name": "y" + } + } + ] + } + ], + "body": { + "type": "BlockStatement", + "start": 36, + "end": 38, + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 38 + } + }, + "body": [], + "directives": [] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/duplicate-proto/in-new-expression/input.js b/packages/babel-parser/test/fixtures/es2015/duplicate-proto/in-new-expression/input.js new file mode 100644 index 000000000000..900d3841bc6c --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/duplicate-proto/in-new-expression/input.js @@ -0,0 +1 @@ +new {__proto__: Number, __proto__: Number}.__proto__; diff --git a/packages/babel-parser/test/fixtures/es2015/duplicate-proto/in-new-expression/output.json b/packages/babel-parser/test/fixtures/es2015/duplicate-proto/in-new-expression/output.json new file mode 100644 index 000000000000..8b1e9a9a780d --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/duplicate-proto/in-new-expression/output.json @@ -0,0 +1,223 @@ +{ + "type": "File", + "start": 0, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 53 + } + }, + "errors": [ + "SyntaxError: Redefinition of __proto__ property (1:24)" + ], + "program": { + "type": "Program", + "start": 0, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 53 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 53 + } + }, + "expression": { + "type": "NewExpression", + "start": 0, + "end": 52, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 52 + } + }, + "callee": { + "type": "MemberExpression", + "start": 4, + "end": 52, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 52 + } + }, + "object": { + "type": "ObjectExpression", + "start": 4, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 42 + } + }, + "properties": [ + { + "type": "ObjectProperty", + "start": 5, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 22 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 5, + "end": 14, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 14 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "Identifier", + "start": 16, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 22 + }, + "identifierName": "Number" + }, + "name": "Number" + } + }, + { + "type": "ObjectProperty", + "start": 24, + "end": 41, + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 41 + } + }, + "method": false, + "key": { + "type": "Identifier", + "start": 24, + "end": 33, + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 33 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "Identifier", + "start": 35, + "end": 41, + "loc": { + "start": { + "line": 1, + "column": 35 + }, + "end": { + "line": 1, + "column": 41 + }, + "identifierName": "Number" + }, + "name": "Number" + } + } + ] + }, + "property": { + "type": "Identifier", + "start": 43, + "end": 52, + "loc": { + "start": { + "line": 1, + "column": 43 + }, + "end": { + "line": 1, + "column": 52 + }, + "identifierName": "__proto__" + }, + "name": "__proto__" + }, + "computed": false + }, + "arguments": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file