Skip to content
← Back

src/syntax/process/printer/range_locator.ghul

1
namespace Syntax.Process.Printer is
2
use Collections;
3
4
use Trees;
5
use Source;
6
7
// A run of sibling AST nodes selected for range formatting — wrapped in a
8
// fresh list node ready to hand to FORMATTER — plus the source span they
9
// occupy. The line/column bounds let the caller confirm the run sits on
10
// lines of its own before replacing those lines wholesale.
11
class RANGE_TARGET is
12
node: Node;
13
start_line: int;
14
start_column: int;
15
end_line: int;
16
end_column: int;
17
18
init(
19
node: Node,
20
start_line: int,
21
start_column: int,
22
end_line: int,
23
end_column: int
24
) is
25
self.node = node;
26
self.start_line = start_line;
27
self.start_column = start_column;
28
self.end_line = end_line;
29
self.end_column = end_column;
30
si
31
si
32
33
// Finds the smallest run of whole definitions or statements that covers a
34
// requested range. Descends through namespace and class/trait/struct/union
35
// bodies and into a function's statement body; a statement is a leaf — a
36
// block statement is formatted whole rather than split at the range.
37
class RANGE_LOCATOR is
38
_start: int;
39
_end: int;
40
41
init(start_line: int, start_column: int, end_line: int, end_column: int) is
42
_start = LOCATION.pair(start_line, start_column);
43
_end = LOCATION.pair(end_line, end_column);
44
si
45
46
_overlaps(location: LOCATION) -> bool =>
47
location.start <= _end /\ location.end >= _start;
48
49
_contains(location: LOCATION) -> bool =>
50
location.start <= _start /\ location.end >= _end;
51
52
locate(definitions: Definitions.LIST) -> RANGE_TARGET? is
53
let overlapping = LIST[Definitions.Definition]();
54
55
for d in definitions do
56
if _overlaps(d.location) then
57
overlapping.add(d);
58
fi
59
od
60
61
if overlapping.count == 1 /\ _contains(overlapping[0].location) then
62
let descended = _descend(overlapping[0]);
63
if descended? then
64
return descended;
65
fi
66
fi
67
68
if overlapping.count == 0 then
69
return null;
70
fi
71
72
let first = overlapping[0].location;
73
let last = overlapping[overlapping.count - 1].location;
74
75
return RANGE_TARGET(
76
Definitions.LIST(first, overlapping),
77
first.start_line,
78
first.start_column,
79
last.end_line,
80
last.end_column
81
);
82
si
83
84
_descend(definition: Definitions.Definition) -> RANGE_TARGET? is
85
let namespace_definition = cast Definitions.NAMESPACE?(definition);
86
if namespace_definition? then
87
return locate(namespace_definition.body);
88
fi
89
90
let classy = cast Definitions.Classy?(definition);
91
if classy? then
92
return locate(classy.body);
93
fi
94
95
let function_definition = cast Definitions.FUNCTION?(definition);
96
if function_definition? then
97
let block = cast Bodies.BLOCK?(function_definition.body);
98
if block? then
99
return _locate_statements(block.statements);
100
fi
101
fi
102
103
return null;
104
si
105
106
_locate_statements(statements: Statements.LIST) -> RANGE_TARGET? is
107
let overlapping = LIST[Statements.Statement]();
108
109
for s in statements do
110
if _overlaps(s.location) then
111
overlapping.add(s);
112
fi
113
od
114
115
if overlapping.count == 0 then
116
return null;
117
fi
118
119
let first = overlapping[0].location;
120
let last = overlapping[overlapping.count - 1].location;
121
122
return RANGE_TARGET(
123
Statements.LIST(first, overlapping),
124
first.start_line,
125
first.start_column,
126
last.end_line,
127
last.end_column
128
);
129
si
130
si
131
si