From ab7d1231ad6bab4e13199038c58e7ea3ae1e9e27 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sun, 25 Mar 2018 22:47:48 +0100 Subject: [PATCH] Fix flow errors with Logical Assignment Operators (#7629) * Fix flow errors with logical assignment * Fix column numbers --- packages/babylon/src/parser/expression.js | 25 +++++++++++++++---- packages/babylon/src/tokenizer/index.js | 21 ++++++---------- .../pipeline-operator/no-plugin/options.json | 2 +- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/packages/babylon/src/parser/expression.js b/packages/babylon/src/parser/expression.js index 75178532ea..1abe3905a3 100644 --- a/packages/babylon/src/parser/expression.js +++ b/packages/babylon/src/parser/expression.js @@ -151,7 +151,16 @@ export default class ExpressionParser extends LValParser { } if (this.state.type.isAssign) { const node = this.startNodeAt(startPos, startLoc); - node.operator = this.state.value; + const operator = this.state.value; + node.operator = operator; + + if (operator === "??=") { + this.expectPlugin("nullishCoalescingOperator"); + this.expectPlugin("logicalAssignment"); + } + if (operator === "||=" || operator === "&&=") { + this.expectPlugin("logicalAssignment"); + } node.left = this.match(tt.eq) ? this.toAssignable(left, undefined, "assignment expression") : left; @@ -271,11 +280,12 @@ export default class ExpressionParser extends LValParser { if (prec != null && (!noIn || !this.match(tt._in))) { if (prec > minPrec) { const node = this.startNodeAt(leftStartPos, leftStartLoc); + const operator = this.state.value; node.left = left; - node.operator = this.state.value; + node.operator = operator; if ( - node.operator === "**" && + operator === "**" && left.type === "UnaryExpression" && left.extra && !left.extra.parenthesizedArgument && @@ -288,13 +298,18 @@ export default class ExpressionParser extends LValParser { } const op = this.state.type; + if (op === tt.nullishCoalescing) { + this.expectPlugin("nullishCoalescingOperator"); + } else if (op === tt.pipeline) { + this.expectPlugin("pipelineOperator"); + } + this.next(); const startPos = this.state.start; const startLoc = this.state.startLoc; - if (node.operator === "|>") { - this.expectPlugin("pipelineOperator"); + if (op === tt.pipeline) { // Support syntax such as 10 |> x => x + 1 this.state.potentialArrowAt = startPos; } diff --git a/packages/babylon/src/tokenizer/index.js b/packages/babylon/src/tokenizer/index.js index 6a7ec8f9f4..3143a0ae43 100644 --- a/packages/babylon/src/tokenizer/index.js +++ b/packages/babylon/src/tokenizer/index.js @@ -464,18 +464,14 @@ export default class Tokenizer extends LocationParser { const next = this.input.charCodeAt(this.state.pos + 1); if (next === code) { - const assign = - this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo; - if (assign) { - // $FlowFixMe - this.expectPlugin("logicalAssignment"); + if (this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo) { + this.finishOp(tt.assign, 3); + } else { + this.finishOp( + code === charCodes.verticalBar ? tt.logicalOR : tt.logicalAND, + 2, + ); } - this.finishOp( - assign - ? tt.assign - : code === charCodes.verticalBar ? tt.logicalOR : tt.logicalAND, - assign ? 3 : 2, - ); return; } @@ -607,11 +603,8 @@ export default class Tokenizer extends LocationParser { const next = this.input.charCodeAt(this.state.pos + 1); const next2 = this.input.charCodeAt(this.state.pos + 2); if (next === charCodes.questionMark) { - this.expectPlugin("nullishCoalescingOperator"); - if (next2 === charCodes.equalsTo) { // '??=' - this.expectPlugin("logicalAssignment"); this.finishOp(tt.assign, 3); } else { // '??' diff --git a/packages/babylon/test/fixtures/experimental/pipeline-operator/no-plugin/options.json b/packages/babylon/test/fixtures/experimental/pipeline-operator/no-plugin/options.json index 0a8f05f84b..5d8a6bb120 100644 --- a/packages/babylon/test/fixtures/experimental/pipeline-operator/no-plugin/options.json +++ b/packages/babylon/test/fixtures/experimental/pipeline-operator/no-plugin/options.json @@ -1,3 +1,3 @@ { - "throws": "This experimental syntax requires enabling the parser plugin: 'pipelineOperator' (1:5)" + "throws": "This experimental syntax requires enabling the parser plugin: 'pipelineOperator' (1:2)" }