diff --git a/README.md b/README.md index bf53c31b87..269c0bf5da 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,11 @@ object referring to that same position. - **directSourceFile**: Like `sourceFile`, but a `sourceFile` property will be added directly to the nodes, rather than the `loc` object. +- **preserveParens**: If this option is `true`, parenthesized expressions + are represented by (non-standard) `ParenthesizedExpression` nodes + that have a single `expression` property containing the expression + inside parentheses. + [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 **parseExpressionAt**`(input, offset, options)` will parse a single diff --git a/acorn.js b/acorn.js index 2da669c499..2d740e8c50 100644 --- a/acorn.js +++ b/acorn.js @@ -112,7 +112,10 @@ sourceFile: null, // This value, if given, is stored in every node, whether // `locations` is on or off. - directSourceFile: null + directSourceFile: null, + // When enabled, parenthesized expressions are represented by + // (non-standard) ParenthesizedExpression nodes + preserveParens: false }; // This function tries to parse a single expression at a given @@ -1459,6 +1462,10 @@ case "SpreadElement": break; + case "ParenthesizedExpression": + checkLVal(expr.expression); + break; + default: raise(expr.start, "Assigning to rvalue"); } @@ -2041,6 +2048,12 @@ if (exprList[i].type === "SpreadElement") unexpected(); } } + + if (options.preserveParens) { + var par = startNodeAt(start); + par.expression = val; + val = finishNode(par, "ParenthesizedExpression"); + } } } return val; diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 01010e95ca..1a883ee051 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -15391,3 +15391,25 @@ test('function normal(x, y = 10) {}', { }, {ecmaVersion: 6}); test("'use strict'; function f([x,,z]) {}", {}, {ecmaVersion: 6}); + +// test preserveParens option with arrow functions +test("() => 42", { + type: "Program", + body: [{ + type: "ExpressionStatement", + expression: { + type: "ArrowFunctionExpression" + } + }] +}, {ecmaVersion: 6, preserveParens: true}); + +// test preserveParens with generators +test("(for (x of array) for (y of array2) if (x === test) x)", { + type: "Program", + body: [{ + type: "ExpressionStatement", + expression: { + type: "ComprehensionExpression" + } + }] +}, {ecmaVersion: 6, preserveParens: true}); diff --git a/test/tests.js b/test/tests.js index 5a86572a93..4fedc72ca1 100644 --- a/test/tests.js +++ b/test/tests.js @@ -234,6 +234,123 @@ test("(1 + 2 ) * 3", { } }); +test("(1 + 2 ) * 3", { + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "BinaryExpression", + left: { + type: "ParenthesizedExpression", + expression: { + type: "BinaryExpression", + left: { + type: "Literal", + value: 1, + loc: { + start: { + line: 1, + column: 1 + }, + end: { + line: 1, + column: 2 + } + } + }, + operator: "+", + right: { + type: "Literal", + value: 2, + loc: { + start: { + line: 1, + column: 5 + }, + end: { + line: 1, + column: 6 + } + } + }, + loc: { + start: { + line: 1, + column: 1 + }, + end: { + line: 1, + column: 6 + } + } + }, + loc: { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 8 + } + } + }, + operator: "*", + right: { + type: "Literal", + value: 3, + loc: { + start: { + line: 1, + column: 11 + }, + end: { + line: 1, + column: 12 + } + } + }, + loc: { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 12 + } + } + }, + loc: { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 12 + } + } + } + ], + loc: { + start: { + line: 1, + column: 0 + }, + end: { + line: 1, + column: 12 + } + } +}, { + locations: true, + preserveParens: true +}); + +test("(x) = 23", {}, { preserveParens: true }); + test("x = []", { type: "Program", body: [