Add more supervisory parens, closes #187 (#2423)

master
Lucas Azzola 2017-07-07 23:57:17 +10:00 committed by Christopher Chedeau
parent 8bbbc3a6f3
commit 7e96e01fba
6 changed files with 101 additions and 10 deletions

View File

@ -322,15 +322,15 @@ FastPath.prototype.needsParens = function(options) {
return true;
}
if (no === "**" && po === "**") {
return name === "left";
}
if (pp === np && name === "right") {
assert.strictEqual(parent.right, node);
return true;
}
if (pp === np && !util.shouldFlatten(po, no)) {
return true;
}
// Add parenthesis when working with binary operators
// It's not stricly needed but helps with code understanding
if (["|", "^", "&", ">>", "<<", ">>>"].indexOf(po) !== -1) {

View File

@ -4089,11 +4089,7 @@ function printBinaryishExpressions(
// precedence level and should be treated as a separate group, so
// print them normally. (This doesn't hold for the `**` operator,
// which is unique in that it is right-associative.)
if (
util.getPrecedence(node.left.operator) ===
util.getPrecedence(node.operator) &&
node.operator !== "**"
) {
if (util.shouldFlatten(node.operator, node.left.operator)) {
// Flatten them out by recursively calling this function.
parts = parts.concat(
path.call(

View File

@ -315,6 +315,36 @@ function getPrecedence(op) {
return PRECEDENCE[op];
}
const equalityOperators = { "==": true, "!=": true, "===": true, "!==": true };
const multiplicativeOperators = { "*": true, "/": true, "%": true };
function shouldFlatten(parentOp, nodeOp) {
if (getPrecedence(nodeOp) !== getPrecedence(parentOp)) {
return false;
}
// ** is right-associative
// x ** y ** z --> x ** (y ** z)
if (parentOp === "**") {
return false;
}
// x == y == z --> (x == y) == z
if (equalityOperators[parentOp] && equalityOperators[nodeOp]) {
return false;
}
// x * y % z --> (x * y) % z
if (
(nodeOp === "%" && multiplicativeOperators[parentOp]) ||
(parentOp === "%" && multiplicativeOperators[nodeOp])
) {
return false;
}
return true;
}
// Tests if an expression starts with `{`, or (if forbidFunctionAndClass holds) `function` or `class`.
// Will be overzealous if there's already necessary grouping parentheses.
function startsWithNoLookaheadToken(node, forbidFunctionAndClass) {
@ -405,6 +435,7 @@ function getAlignmentSize(value, tabWidth, startIndex) {
module.exports = {
getPrecedence,
shouldFlatten,
isExportDeclaration,
getParentExportDeclaration,
getPenultimate,

View File

@ -34,6 +34,29 @@ a =
`;
exports[`equality.js 1`] = `
x == y == z;
x != y == z;
x == y != z;
x != y != z;
x === y === z;
x !== y === z;
x === y !== z;
x !== y !== z;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(x == y) == z;
(x != y) == z;
(x == y) != z;
(x != y) != z;
(x === y) === z;
(x !== y) === z;
(x === y) !== z;
(x !== y) !== z;
`;
exports[`exp.js 1`] = `
a ** b ** c;
(a ** b) ** c;
@ -44,7 +67,7 @@ a ** -b;
(a * b) ** c;
a ** (b * c);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a ** b ** c;
a ** (b ** c);
(a ** b) ** c;
a.b ** c;
(-a) ** b;
@ -151,6 +174,29 @@ exports[`jsx_parent.js 1`] = `
`;
exports[`math.js 1`] = `
x + y / z;
x / y + z;
x * y % z;
x / y % z;
x % y * z;
x % y / z;
x % y % z;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
x + y / z;
x / y + z;
(x * y) % z;
(x / y) % z;
(x % y) * z;
(x % y) / z;
(x % y) % z;
`;
exports[`short-right.js 1`] = `
this._cumulativeHeights &&
Math.abs(

View File

@ -0,0 +1,9 @@
x == y == z;
x != y == z;
x == y != z;
x != y != z;
x === y === z;
x !== y === z;
x === y !== z;
x !== y !== z;

View File

@ -0,0 +1,9 @@
x + y / z;
x / y + z;
x * y % z;
x / y % z;
x % y * z;
x % y / z;
x % y % z;