Skip to content
← Back

src/semantic/symbol_definition_locations.ghul

1
namespace Semantic is
2
use IO.Std
3
4
use Source
5
6
trait SymbolDefinitionListener is
7
add_symbol_definition(location: LOCATION, symbol: Symbols.Symbol)
8
si
9
10
class SYMBOL_DEFINITION_LOCATIONS(_symbol_use_listener: SymbolUseListener): SymbolDefinitionListener is
11
12
_symbol_definition_map: Collections.MAP[string,Collections.LIST[Symbols.Symbol]]
13
14
// The location each definition above was recorded at, in step
15
// with it: what the replay checks a re-declaration against.
16
_definition_locations: Collections.MAP[string,Collections.LIST[LOCATION]]
17
_workspace_definition_map: Collections.MAP[string,Collections.LIST[Symbols.Symbol]]
18
19
init(..) is
20
clear()
21
si
22
23
dump_counts() is
24
Std.error.write_line("symbol definition map: {_symbol_definition_map.count}")
25
Std.error.write_line("workspace definition map: {_workspace_definition_map.count}")
26
si
27
28
clear() is
29
_symbol_definition_map = Collections.MAP[string,Collections.LIST[Symbols.Symbol]]()
30
_definition_locations = Collections.MAP[string,Collections.LIST[LOCATION]]()
31
_workspace_definition_map = Collections.MAP[string,Collections.LIST[Symbols.Symbol]]()
32
si
33
34
35
// One declaration of the previous generation, in the order it was
36
// recorded, for the replay below.
37
_replay: Collections.MAP[string, Collections.LIST[(location: LOCATION, name: string, id: int)]]?
38
_replay_cursor: Collections.MAP[string, int]?
39
40
// Forget the recorded definitions ahead of a rebuild, keeping
41
// each unedited file's sequence of (location, name, id) so its
42
// re-declaration can adopt the ids. A file re-declared from
43
// its retained tree records the same declarations in the same
44
// order; the location and name of each are checked as they
45
// arrive, and a file whose sequence diverges gets fresh ids from
46
// that point - the behaviour without any replay.
47
clear_and_replay_ids(edited_files: Collections.Iterable[string]) is
48
let edited = Collections.SET[string]()
49
50
for file_name in edited_files do
51
edited.add(file_name)
52
od
53
54
let replay = Collections.MAP[string, Collections.LIST[(location: LOCATION, name: string, id: int)]]()
55
56
for entry in _symbol_definition_map do
57
if edited.contains(entry.key) then
58
continue
59
fi
60
61
let sequence = Collections.LIST[(location: LOCATION, name: string, id: int)]()
62
let locations = _definition_locations[entry.key]
63
64
for i in 0..entry.value.count do
65
let symbol = entry.value[i]
66
67
sequence.add((location = locations[i], name = symbol.name, id = symbol.id))
68
od
69
70
replay[entry.key] = sequence
71
od
72
73
clear()
74
75
_replay = replay
76
_replay_cursor = Collections.MAP[string, int]()
77
si
78
79
_adopt_replayed_id(location: LOCATION, symbol: Symbols.Symbol) is
80
if let replay = _replay, cursor = _replay_cursor then
81
let file_name = location.file_name
82
83
let sequence: Collections.LIST[(location: LOCATION, name: string, id: int)] mut
84
85
if !replay.try_get_value(file_name, sequence ref) then
86
return
87
fi
88
89
let index = if cursor.contains_key(file_name) then cursor[file_name] else 0 fi
90
91
if index < sequence.count then
92
let expected = sequence[index]
93
94
if expected.location =~ location /\ expected.name =~ symbol.name then
95
symbol.adopt_id(expected.id)
96
cursor[file_name] = index + 1
97
98
return
99
fi
100
fi
101
102
replay.remove(file_name)
103
fi
104
si
105
add_symbol_definition(location: LOCATION, symbol: Symbols.Symbol) is
106
_adopt_replayed_id(location, symbol)
107
108
get_symbol_list_for_file_name(location.file_name).add(symbol)
109
_definition_locations[location.file_name].add(location)
110
111
if !symbol.is_internal then
112
_symbol_use_listener.add_symbol_use(location, symbol)
113
fi
114
si
115
116
// Reconcile one file's recorded definitions after an
117
// interface-preserving incremental EDIT, before the body re-walk
118
// re-declares its bodies. The body-local definitions are dropped —
119
// the re-walk re-records them — and the interface definitions are
120
// kept (the re-walk does not re-declare the interface; the
121
// interface symbols' own locations are refreshed by
122
// SYMBOL_USE_LOCATIONS.refresh_edited_file). The derived workspace
123
// list is discarded so it rebuilds on next query.
124
refresh_edited_file(file_name: string, body_spans: Source.BODY_SPANS) is
125
if _symbol_definition_map.contains_key(file_name) then
126
let kept = Collections.LIST[Symbols.Symbol]()
127
let kept_locations = Collections.LIST[LOCATION]()
128
let symbols = _symbol_definition_map[file_name]
129
let locations = _definition_locations[file_name]
130
131
for i in 0..symbols.count do
132
let symbol = symbols[i]
133
134
if !body_spans.contains(symbol.location.start) then
135
kept.add(symbol)
136
kept_locations.add(locations[i])
137
fi
138
od
139
140
_symbol_definition_map[file_name] = kept
141
_definition_locations[file_name] = kept_locations
142
fi
143
144
_workspace_definition_map.remove(file_name)
145
si
146
147
find_definitions_from_file(file_name: string, workspace_search: bool) -> Collections.Iterable[Symbols.Symbol] =>
148
if workspace_search then
149
get_workspace_list_for_file_name(file_name)
150
else
151
get_symbol_list_for_file_name(file_name)
152
fi
153
154
// True iff at least one definition is recorded for the file —
155
// distinguishes "this file was already compiled and genuinely
156
// has no visible definitions" from "no compile has run yet".
157
// `get_symbol_list_for_file_name` lazily creates an empty list,
158
// so `contains_key` after-the-fact isn't a safe test; check
159
// count instead.
160
// Every recorded definition, over every file.
161
all_definitions() -> Ghul.Pipes.Pipe[Symbols.Symbol] is
162
for symbols in _symbol_definition_map.values do
163
for symbol in symbols do
164
yield symbol
165
od
166
od
167
si
168
169
has_definitions_for(file_name: string) -> bool =>
170
_symbol_definition_map.contains_key(file_name) /\ _symbol_definition_map[file_name].count > 0
171
172
get_symbol_list_for_file_name(file_name: string) -> Collections.LIST[Symbols.Symbol] is
173
if _symbol_definition_map.contains_key(file_name) then
174
return _symbol_definition_map[file_name]
175
fi
176
177
let result = Collections.LIST[Symbols.Symbol]()
178
179
_symbol_definition_map[file_name] = result
180
_definition_locations[file_name] = Collections.LIST[LOCATION]()
181
182
return result
183
si
184
185
get_workspace_list_for_file_name(file_name: string) -> Collections.LIST[Symbols.Symbol] is
186
if _workspace_definition_map.contains_key(file_name) then
187
return _workspace_definition_map[file_name]
188
fi
189
190
let result = Collections.LIST[Symbols.Symbol]()
191
192
_workspace_definition_map[file_name] = result
193
194
for symbol in get_symbol_list_for_file_name(file_name) do
195
if symbol.is_workspace_visible then
196
result.add(symbol)
197
fi
198
od
199
200
return result
201
si
202
si
203
si