diff --git a/src/parser.ts b/src/parser.ts index 61159528b..f47d224e2 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1475,8 +1475,16 @@ export class Parser { parseExponentiationExpression(): Node.Expression { const startToken = this.lookahead; + // -1 ** 2 is not accepted, but (-1) ** 2 + // However, the AST for both cases is identical + // We distinguish the two cases by explicitly checking for a parenthesis. + + const isLeftParenthesized = this.match('('); let expr = this.inheritCoverGrammar(this.parseUnaryExpression); - if (expr.type !== Syntax.UnaryExpression && this.match('**')) { + + const exponentAllowed = expr.type !== Syntax.UnaryExpression || isLeftParenthesized; + + if (exponentAllowed && this.match('**')) { this.nextToken(); this.context.isAssignmentTarget = false; this.context.isBindingElement = false; diff --git a/test/fixtures/ES2016/exponent/exp_paren.js b/test/fixtures/ES2016/exponent/exp_paren.js new file mode 100644 index 000000000..8433b1636 --- /dev/null +++ b/test/fixtures/ES2016/exponent/exp_paren.js @@ -0,0 +1 @@ +(-2) ** 1; \ No newline at end of file diff --git a/test/fixtures/ES2016/exponent/exp_paren.tree.json b/test/fixtures/ES2016/exponent/exp_paren.tree.json new file mode 100644 index 000000000..ffe46da05 --- /dev/null +++ b/test/fixtures/ES2016/exponent/exp_paren.tree.json @@ -0,0 +1,240 @@ +{ + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "BinaryExpression", + "operator": "**", + "left": { + "type": "UnaryExpression", + "operator": "-", + "argument": { + "type": "Literal", + "value": 2, + "raw": "2", + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "prefix": true, + "range": [ + 1, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "right": { + "type": "Literal", + "value": 1, + "raw": "1", + "range": [ + 8, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + "range": [ + 0, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + } + } + ], + "sourceType": "script", + "range": [ + 0, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "(", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Punctuator", + "value": "-", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Numeric", + "value": "2", + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 3, + 4 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 4 + } + } + }, + { + "type": "Punctuator", + "value": "**", + "range": [ + 5, + 7 + ], + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 7 + } + } + }, + { + "type": "Numeric", + "value": "1", + "range": [ + 8, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + { + "type": "Punctuator", + "value": ";", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + } + } + ] +} \ No newline at end of file