From 7353a3884634d244d0e9dd5f143754b90c539afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Sat, 5 Aug 2017 00:27:11 +0200 Subject: [PATCH] Arrow fns can't be used as the left side of a binary or ternary expression (#559) * Arrow fns can't be used as the left side of a binary or ternary expression Fixes #536 * Add test for logical expression with arrow function * Fix eslint --- src/parser/expression.js | 20 +- .../in-logic-expression/actual.js | 2 + .../in-logic-expression/expected.json | 227 ++++++++++++++++++ .../arrow-functions/no-binary-left/actual.js | 1 + .../no-binary-left/options.json | 3 + .../arrow-functions/no-ternary-test/actual.js | 1 + .../no-ternary-test/options.json | 3 + 7 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/es2015/arrow-functions/in-logic-expression/actual.js create mode 100644 test/fixtures/es2015/arrow-functions/in-logic-expression/expected.json create mode 100644 test/fixtures/es2015/arrow-functions/no-binary-left/actual.js create mode 100644 test/fixtures/es2015/arrow-functions/no-binary-left/options.json create mode 100644 test/fixtures/es2015/arrow-functions/no-ternary-test/actual.js create mode 100644 test/fixtures/es2015/arrow-functions/no-ternary-test/options.json diff --git a/src/parser/expression.js b/src/parser/expression.js index c651edaf20..9b971a7097 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -191,7 +191,15 @@ export default class ExpressionParser extends LValParser { ): N.Expression { const startPos = this.state.start; const startLoc = this.state.startLoc; + const potentialArrowAt = this.state.potentialArrowAt; const expr = this.parseExprOps(noIn, refShorthandDefaultPos); + + if ( + expr.type === "ArrowFunctionExpression" && + expr.start === potentialArrowAt + ) { + return expr; + } if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr; return this.parseConditional( @@ -228,12 +236,20 @@ export default class ExpressionParser extends LValParser { parseExprOps(noIn: ?boolean, refShorthandDefaultPos: Pos): N.Expression { const startPos = this.state.start; const startLoc = this.state.startLoc; + const potentialArrowAt = this.state.potentialArrowAt; const expr = this.parseMaybeUnary(refShorthandDefaultPos); + + if ( + expr.type === "ArrowFunctionExpression" && + expr.start === potentialArrowAt + ) { + return expr; + } if (refShorthandDefaultPos && refShorthandDefaultPos.start) { return expr; - } else { - return this.parseExprOp(expr, startPos, startLoc, -1, noIn); } + + return this.parseExprOp(expr, startPos, startLoc, -1, noIn); } // Parse binary operators with the operator precedence parsing diff --git a/test/fixtures/es2015/arrow-functions/in-logic-expression/actual.js b/test/fixtures/es2015/arrow-functions/in-logic-expression/actual.js new file mode 100644 index 0000000000..6589fe8ea7 --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/in-logic-expression/actual.js @@ -0,0 +1,2 @@ +(() => {}) || true; +(() => {}) ? a : b; \ No newline at end of file diff --git a/test/fixtures/es2015/arrow-functions/in-logic-expression/expected.json b/test/fixtures/es2015/arrow-functions/in-logic-expression/expected.json new file mode 100644 index 0000000000..abc58a8846 --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/in-logic-expression/expected.json @@ -0,0 +1,227 @@ +{ + "type": "File", + "start": 0, + "end": 39, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 39, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 19, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 19 + } + }, + "expression": { + "type": "LogicalExpression", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "left": { + "type": "ArrowFunctionExpression", + "start": 1, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 7, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "body": [], + "directives": [] + }, + "extra": { + "parenthesized": true, + "parenStart": 0 + } + }, + "operator": "||", + "right": { + "type": "BooleanLiteral", + "start": 14, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "value": true + } + } + }, + { + "type": "ExpressionStatement", + "start": 20, + "end": 39, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 19 + } + }, + "expression": { + "type": "ConditionalExpression", + "start": 20, + "end": 38, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "test": { + "type": "ArrowFunctionExpression", + "start": 21, + "end": 29, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 9 + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 27, + "end": 29, + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 9 + } + }, + "body": [], + "directives": [] + }, + "extra": { + "parenthesized": true, + "parenStart": 20 + } + }, + "consequent": { + "type": "Identifier", + "start": 33, + "end": 34, + "loc": { + "start": { + "line": 2, + "column": 13 + }, + "end": { + "line": 2, + "column": 14 + }, + "identifierName": "a" + }, + "name": "a" + }, + "alternate": { + "type": "Identifier", + "start": 37, + "end": 38, + "loc": { + "start": { + "line": 2, + "column": 17 + }, + "end": { + "line": 2, + "column": 18 + }, + "identifierName": "b" + }, + "name": "b" + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/es2015/arrow-functions/no-binary-left/actual.js b/test/fixtures/es2015/arrow-functions/no-binary-left/actual.js new file mode 100644 index 0000000000..e00f488826 --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/no-binary-left/actual.js @@ -0,0 +1 @@ +() => {} || true \ No newline at end of file diff --git a/test/fixtures/es2015/arrow-functions/no-binary-left/options.json b/test/fixtures/es2015/arrow-functions/no-binary-left/options.json new file mode 100644 index 0000000000..a904da48cb --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/no-binary-left/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected ; (1:9)" +} \ No newline at end of file diff --git a/test/fixtures/es2015/arrow-functions/no-ternary-test/actual.js b/test/fixtures/es2015/arrow-functions/no-ternary-test/actual.js new file mode 100644 index 0000000000..9c5cfc9b44 --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/no-ternary-test/actual.js @@ -0,0 +1 @@ +() => {} ? 1 : 2; \ No newline at end of file diff --git a/test/fixtures/es2015/arrow-functions/no-ternary-test/options.json b/test/fixtures/es2015/arrow-functions/no-ternary-test/options.json new file mode 100644 index 0000000000..a904da48cb --- /dev/null +++ b/test/fixtures/es2015/arrow-functions/no-ternary-test/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token, expected ; (1:9)" +} \ No newline at end of file