diff --git a/escodegen.js b/escodegen.js index 847fc370..96a5b694 100644 --- a/escodegen.js +++ b/escodegen.js @@ -85,6 +85,7 @@ Assignment: 1, Conditional: 2, ArrowFunction: 2, + NullishCoalescing: 3, LogicalOR: 3, LogicalAND: 4, BitwiseOR: 5, @@ -108,6 +109,7 @@ }; BinaryPrecedence = { + '??': Precedence.NullishCoalescing, '||': Precedence.LogicalOR, '&&': Precedence.LogicalAND, '|': Precedence.BitwiseOR, @@ -1836,8 +1838,34 @@ BinaryExpression: function (expr, precedence, flags) { var result, leftPrecedence, rightPrecedence, currentPrecedence, fragment, leftSource; currentPrecedence = BinaryPrecedence[expr.operator]; - leftPrecedence = expr.operator === '**' ? Precedence.Postfix : currentPrecedence; - rightPrecedence = expr.operator === '**' ? currentPrecedence : currentPrecedence + 1; + + leftPrecedence = currentPrecedence; + rightPrecedence = currentPrecedence + 1; + + switch (expr.operator) { + case '**': + leftPrecedence = Precedence.Postfix; + rightPrecedence = currentPrecedence; + break; + + case '??': + if (expr.left.type === Syntax.LogicalExpression && (expr.left.operator === '||' || expr.left.operator === '&&')) { + leftPrecedence = BinaryPrecedence[expr.left.operator] + 1; + } + + if (expr.right.type === Syntax.LogicalExpression && expr.right.operator === '&&') { + rightPrecedence = BinaryPrecedence[expr.right.operator] + 1; + } + + break; + + case '||': + if (expr.left.type === Syntax.LogicalExpression && expr.left.operator === '??') { + leftPrecedence = BinaryPrecedence[expr.left.operator] + 1; + } + + break; + } if (currentPrecedence < precedence) { flags |= F_ALLOW_IN; diff --git a/test/compare-acorn-es2020/nullish-coalescing.expected.js b/test/compare-acorn-es2020/nullish-coalescing.expected.js new file mode 100644 index 00000000..5bb15e1f --- /dev/null +++ b/test/compare-acorn-es2020/nullish-coalescing.expected.js @@ -0,0 +1,15 @@ +a ?? b; +a ?? b ?? c; +a | b ?? c | d; +a ?? b ? c : d; +a ? b ?? c : d; +a ? b : c ?? d; +a => b ?? c; +(a || b) ?? c; +a || (b ?? c); +(a && b) ?? c; +a && (b ?? c); +(a ?? b) || c; +a ?? (b || c); +(a ?? b) && c; +a ?? (b && c); \ No newline at end of file diff --git a/test/compare-acorn-es2020/nullish-coalescing.expected.min.js b/test/compare-acorn-es2020/nullish-coalescing.expected.min.js new file mode 100644 index 00000000..dfefb728 --- /dev/null +++ b/test/compare-acorn-es2020/nullish-coalescing.expected.min.js @@ -0,0 +1 @@ +a??b;a??b??c;a|b??c|d;a??b?c:d;a?b??c:d;a?b:c??d;a=>b??c;(a||b)??c;a||(b??c);(a&&b)??c;a&&(b??c);(a??b)||c;a??(b||c);(a??b)&&c;a??(b&&c) diff --git a/test/compare-acorn-es2020/nullish-coalescing.js b/test/compare-acorn-es2020/nullish-coalescing.js new file mode 100644 index 00000000..d49d4189 --- /dev/null +++ b/test/compare-acorn-es2020/nullish-coalescing.js @@ -0,0 +1,15 @@ +a ?? b; +a ?? b ?? c; +a | b ?? c | d; +a ?? b ? c : d; +a ? b ?? c : d; +a ? b : c ?? d; +a => b ?? c; +(a || b) ?? c; +a || (b ?? c); +(a && b) ?? c; +a && (b ?? c); +(a ?? b) || c; +a ?? (b || c); +(a ?? b) && c; +a ?? (b && c);