diff --git a/src/parser/expression.js b/src/parser/expression.js index 1dddc2bf7b..ee50937efa 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -379,6 +379,12 @@ pp.parseExprSubscripts = function (refShorthandDefaultPos) { }; pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { + + // pipeCall plugin hack: pass noPipes via state to avoid changing args + // to core parser function. + const noPipes = this.state.noPipeSubscripts; + this.state.noPipeSubscripts = false; + for (;;) { if (this.hasPlugin("bangCall") && this.shouldUnwindBangSubscript()) { return base; @@ -470,6 +476,7 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { if (next) base = next; else return node; } else if ( !noCalls && + !noPipes && this.hasPlugin("pipeCall") && this.match(tt.pipeCall) ) { diff --git a/src/plugins/pipeCall.js b/src/plugins/pipeCall.js index 8da584dcb8..79fc132b7b 100644 --- a/src/plugins/pipeCall.js +++ b/src/plugins/pipeCall.js @@ -13,13 +13,13 @@ export default function(parser) { node.left = left; - // Left-associative parsing of pipeCalls + // To get left-associative parsing for pipe calls, we can't let the RHS + // of a pipe call subscript into another pipe call. + // Thus we use a state flag to prevent deep parsing of pipe calls + // Hackish but avoids changing the core args of parseSubscripts const right = this.parseExprAtom(); - if (this.match(tt.pipeCall)) { - node.right = right; - } else { - node.right = this.parseSubscripts(right, this.state.start, this.state.startLoc, true); - } + this.state.noPipeSubscripts = true; + node.right = this.parseSubscripts(right, this.state.start, this.state.startLoc); return this.finishNode(node, "PipeCallExpression"); }; diff --git a/test/fixtures/pipe-call/basic/rhs-expr/expected.json b/test/fixtures/pipe-call/basic/rhs-expr/expected.json index 0d5ac5bd4d..856c241654 100644 --- a/test/fixtures/pipe-call/basic/rhs-expr/expected.json +++ b/test/fixtures/pipe-call/basic/rhs-expr/expected.json @@ -43,7 +43,7 @@ } }, "expression": { - "type": "CallExpression", + "type": "PipeCallExpression", "start": 0, "end": 9, "loc": { @@ -56,10 +56,10 @@ "column": 9 } }, - "callee": { - "type": "PipeCallExpression", + "left": { + "type": "Identifier", "start": 0, - "end": 6, + "end": 1, "loc": { "start": { "line": 1, @@ -67,27 +67,27 @@ }, "end": { "line": 1, - "column": 6 - } + "column": 1 + }, + "identifierName": "a" }, - "left": { - "type": "Identifier", - "start": 0, - "end": 1, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 1 - }, - "identifierName": "a" + "name": "a" + }, + "right": { + "type": "CallExpression", + "start": 6, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 6 }, - "name": "a" + "end": { + "line": 1, + "column": 9 + } }, - "right": { + "callee": { "type": "Identifier", "start": 5, "end": 6, @@ -103,27 +103,27 @@ "identifierName": "b" }, "name": "b" - } - }, - "arguments": [ - { - "type": "Identifier", - "start": 7, - "end": 8, - "loc": { - "start": { - "line": 1, - "column": 7 - }, - "end": { - "line": 1, - "column": 8 + }, + "arguments": [ + { + "type": "Identifier", + "start": 7, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + }, + "identifierName": "c" }, - "identifierName": "c" - }, - "name": "c" - } - ] + "name": "c" + } + ] + } } } ],