Skip to content

Commit 5120041

Browse files
committed
Antlr4 - Hierarchical indentation and grouping of binary expressions.
1 parent 47f4721 commit 5120041

16 files changed

+169
-130
lines changed
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { binaryOperationPrinter } from './printers/binary-operation-printer.js';
2+
import { bit } from './bit.js';
3+
import { shift } from './shift.js';
4+
import { inequality } from './inequality.js';
5+
import { equality } from './equality.js';
6+
import { logical } from './logical.js';
7+
8+
export const addition = {
9+
match: (op) => ['+', '-'].includes(op),
10+
print: binaryOperationPrinter([shift, bit, inequality, equality, logical])
11+
};

src/binary-operator-printers/arithmetic.js

-51
This file was deleted.

src/binary-operator-printers/bit.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { arithmetic } from './arithmetic.js';
1+
import { binaryOperationPrinter } from './printers/binary-operation-printer.js';
2+
import { inequality } from './inequality.js';
3+
import { equality } from './equality.js';
4+
import { logical } from './logical.js';
25

36
export const bit = {
47
match: (op) => ['&', '|', '^'].includes(op),
5-
print: arithmetic.print
8+
print: binaryOperationPrinter([inequality, equality, logical])
69
};

src/binary-operator-printers/comparison.js

-36
This file was deleted.
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { binaryOperationPrinter } from './printers/binary-operation-printer.js';
2+
import { logical } from './logical.js';
3+
4+
export const equality = {
5+
match: (op) => ['==', '!='].includes(op),
6+
print: binaryOperationPrinter([logical])
7+
};
+22-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
import { doc } from 'prettier';
2+
import { createBinaryOperationPrinter } from './printers/create-binary-operation-printer.js';
3+
import { createIndentIfNecessaryBuilder } from './printers/create-indent-if-necessary-builder.js';
4+
import { multiplication } from './multiplication.js';
5+
import { addition } from './addition.js';
6+
import { shift } from './shift.js';
7+
import { bit } from './bit.js';
8+
import { inequality } from './inequality.js';
9+
import { equality } from './equality.js';
10+
import { logical } from './logical.js';
211

3-
const { group, indent, line } = doc.builders;
12+
const { group } = doc.builders;
413

514
export const exponentiation = {
615
match: (op) => op === '**',
7-
print: (node, path, print) => {
8-
const right = [' ', node.operator, line, path.call(print, 'right')];
9-
// If it's a single binary operation, avoid having a small right
10-
// operand like - 1 on its own line
11-
const shouldGroup =
12-
node.left.type !== 'BinaryOperation' &&
13-
path.getParentNode().type !== 'BinaryOperation';
14-
return group([
15-
path.call(print, 'left'),
16-
indent(shouldGroup ? group(right) : right)
17-
]);
18-
}
16+
print: createBinaryOperationPrinter(
17+
() => (document) => group(document), // always group
18+
createIndentIfNecessaryBuilder([
19+
multiplication,
20+
addition,
21+
shift,
22+
bit,
23+
inequality,
24+
equality,
25+
logical
26+
])
27+
)
1928
};

src/binary-operator-printers/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
export * from './arithmetic.js';
1+
export * from './addition.js';
22
export * from './assignment.js';
33
export * from './bit.js';
4-
export * from './comparison.js';
4+
export * from './equality.js';
55
export * from './exponentiation.js';
6+
export * from './inequality.js';
67
export * from './logical.js';
8+
export * from './multiplication.js';
79
export * from './shift.js';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { binaryOperationPrinter } from './printers/binary-operation-printer.js';
2+
import { logical } from './logical.js';
3+
import { equality } from './equality.js';
4+
5+
export const inequality = {
6+
match: (op) => ['<', '>', '<=', '>='].includes(op),
7+
print: binaryOperationPrinter([logical, equality])
8+
};
+11-24
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,32 @@
11
import { doc } from 'prettier';
2+
import { createBinaryOperationPrinter } from './printers/create-binary-operation-printer.js';
3+
import { createGroupIfNecessaryBuilder } from './printers/create-group-if-necessary-builder.js';
4+
import { notIndentParentTypes } from './printers/create-indent-if-necessary-builder.js';
5+
import { shouldGroupOrIndent } from './utils/should-group-or-indent.js';
26

3-
const { group, line, indent } = doc.builders;
4-
5-
const groupIfNecessaryBuilder = (path) => (document) =>
6-
path.getParentNode().type === 'BinaryOperation' ? document : group(document);
7+
const { indent } = doc.builders;
78

89
const indentIfNecessaryBuilder = (path, options) => (document) => {
910
let node = path.getNode();
1011
for (let i = 0; ; i += 1) {
1112
const parentNode = path.getParentNode(i);
12-
if (parentNode.type === 'ReturnStatement') return document;
13-
if (parentNode.type === 'IfStatement') return document;
14-
if (parentNode.type === 'WhileStatement') return document;
13+
if (notIndentParentTypes.includes(parentNode.type)) return document;
1514
if (
1615
options.experimentalTernaries &&
1716
parentNode.type === 'Conditional' &&
1817
parentNode.condition === node
1918
)
2019
return document;
21-
if (parentNode.type !== 'BinaryOperation') return indent(document);
20+
if (shouldGroupOrIndent(parentNode, [])) return indent(document);
2221
if (node === parentNode.right) return document;
2322
node = parentNode;
2423
}
2524
};
2625

2726
export const logical = {
2827
match: (op) => ['&&', '||'].includes(op),
29-
print: (node, path, print, options) => {
30-
const groupIfNecessary = groupIfNecessaryBuilder(path);
31-
const indentIfNecessary = indentIfNecessaryBuilder(path, options);
32-
33-
const right = [node.operator, line, path.call(print, 'right')];
34-
// If it's a single binary operation, avoid having a small right
35-
// operand like - 1 on its own line
36-
const shouldGroup =
37-
node.left.type !== 'BinaryOperation' &&
38-
path.getParentNode().type !== 'BinaryOperation';
39-
return groupIfNecessary([
40-
path.call(print, 'left'),
41-
' ',
42-
indentIfNecessary(shouldGroup ? group(right) : right)
43-
]);
44-
}
28+
print: createBinaryOperationPrinter(
29+
createGroupIfNecessaryBuilder([]),
30+
indentIfNecessaryBuilder
31+
)
4532
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { binaryOperationPrinter } from './printers/binary-operation-printer.js';
2+
import { addition } from './addition.js';
3+
import { bit } from './bit.js';
4+
import { equality } from './equality.js';
5+
import { inequality } from './inequality.js';
6+
import { shift } from './shift.js';
7+
import { logical } from './logical.js';
8+
9+
export const multiplication = {
10+
match: (op) => ['*', '/', '%'].includes(op),
11+
print: binaryOperationPrinter([
12+
addition,
13+
shift,
14+
bit,
15+
inequality,
16+
equality,
17+
logical
18+
])
19+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { createBinaryOperationPrinter } from './create-binary-operation-printer.js';
2+
import { createGroupIfNecessaryBuilder } from './create-group-if-necessary-builder.js';
3+
import { createIndentIfNecessaryBuilder } from './create-indent-if-necessary-builder.js';
4+
5+
export const binaryOperationPrinter = (shouldGroupAndIndentMatchers) =>
6+
createBinaryOperationPrinter(
7+
createGroupIfNecessaryBuilder(shouldGroupAndIndentMatchers),
8+
createIndentIfNecessaryBuilder(shouldGroupAndIndentMatchers)
9+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { doc } from 'prettier';
2+
import { assignment } from '../assignment.js';
3+
4+
const { group, line } = doc.builders;
5+
6+
const rightOperandPrinter = (node, path, print) => {
7+
const right = [' ', node.operator, line, path.call(print, 'right')];
8+
9+
// If it's a single binary operation, avoid having a small right
10+
// operand like - 1 on its own line
11+
const parent = path.getParentNode();
12+
return node.left.type !== 'BinaryOperation' &&
13+
parent.type !== 'BinaryOperation'
14+
? group(right)
15+
: right;
16+
};
17+
18+
export const createBinaryOperationPrinter =
19+
(groupIfNecessaryBuilder, indentIfNecessaryBuilder) =>
20+
(node, path, print, options) => {
21+
const groupIfNecessary = groupIfNecessaryBuilder(path);
22+
const indentIfNecessary = indentIfNecessaryBuilder(path, options);
23+
24+
return groupIfNecessary([
25+
path.call(print, 'left'),
26+
indentIfNecessary(rightOperandPrinter(node, path, print))
27+
]);
28+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { doc } from 'prettier';
2+
import { shouldGroupOrIndent } from '../utils/should-group-or-indent.js';
3+
4+
const { group } = doc.builders;
5+
6+
export const createGroupIfNecessaryBuilder =
7+
(shouldIndentMatchers) => (path) => (document) => {
8+
const parentNode = path.getParentNode();
9+
if (shouldGroupOrIndent(parentNode, shouldIndentMatchers))
10+
return group(document);
11+
return document;
12+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { doc } from 'prettier';
2+
import { shouldGroupOrIndent } from '../utils/should-group-or-indent.js';
3+
4+
const { indent } = doc.builders;
5+
6+
export const notIndentParentTypes = [
7+
'ReturnStatement',
8+
'IfStatement',
9+
'ForStatement',
10+
'WhileStatement'
11+
];
12+
13+
export const createIndentIfNecessaryBuilder =
14+
(shouldIndentMatchers) => (path) => (document) => {
15+
let node = path.getNode();
16+
for (let i = 0; ; i += 1) {
17+
const parentNode = path.getParentNode(i);
18+
if (notIndentParentTypes.includes(parentNode.type)) return document;
19+
if (shouldGroupOrIndent(parentNode, shouldIndentMatchers))
20+
return indent(document);
21+
if (node === parentNode.right) return document;
22+
node = parentNode;
23+
}
24+
};

src/binary-operator-printers/shift.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
import { arithmetic } from './arithmetic.js';
1+
import { binaryOperationPrinter } from './printers/binary-operation-printer.js';
2+
import { bit } from './bit.js';
3+
import { inequality } from './inequality.js';
4+
import { equality } from './equality.js';
5+
import { logical } from './logical.js';
26

37
export const shift = {
48
match: (op) => ['<<', '>>'].includes(op),
5-
print: arithmetic.print
9+
print: binaryOperationPrinter([bit, inequality, equality, logical])
610
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const shouldGroupOrIndent = ({ type, operator }, matchers) =>
2+
type !== 'BinaryOperation' ||
3+
matchers.some((matcher) => matcher.match(operator));

0 commit comments

Comments
 (0)