Skip to content
← Back

src/semantic/namespaces.ghul

1
namespace Semantic is
2
use IO.Std;
3
4
use Logging;
5
use Source;
6
7
use Syntax.Trees;
8
9
// This class manages entering and leaving namespace scopes: it merges all lexical
10
// namespace blocks that reference the same namespace into a single aggregated
11
// namespace symbol, so that symbols defined within any lexical namespace are visible
12
// across all references to that namespace
13
14
class NAMESPACES(_logger: Logger, _symbol_table: SYMBOL_TABLE): Collections.Iterable[Symbols.NAMESPACE] is
15
_namespaces: Collections.MAP[string,Symbols.NAMESPACE];
16
_prefixes: Collections.STACK[string];
17
_current_prefix: string => _prefixes.peek();
18
19
iterator: Collections.Iterator[Symbols.NAMESPACE] => _namespaces.values.iterator;
20
21
get_qualified_name(name: string) -> string =>
22
"{_current_prefix}.{name}";
23
24
init(..) is
25
clear();
26
si
27
28
dump_counts() is
29
Std.error.write_line("namespaces: {_namespaces.count}");
30
Std.error.write_line("prefixes: {_prefixes.count}");
31
si
32
33
clear() is
34
_namespaces = Collections.MAP[string,Symbols.NAMESPACE](65521);
35
_prefixes = Collections.STACK[string]();
36
37
_prefixes.push("");
38
si
39
40
mark_namespace_stack() -> int => _prefixes.count;
41
42
release_namepace_stack(mark: int) is
43
assert mark <= _prefixes.count;
44
45
while _prefixes.count > mark do
46
_prefixes.pop();
47
od
48
si
49
50
find_root_matches(results: Collections.MutableMap[string,Symbols.Symbol]) is
51
for ns in _namespaces do
52
let parts = ns.key.split(['.']);
53
54
if parts.count == 2 then
55
let name = parts[1];
56
57
if name.length > 0 /\ !results.contains_key(name) then
58
results.add(name, ns.value);
59
fi
60
fi
61
od
62
si
63
64
find_namespace_matches(namespace_name: string, results: Collections.MutableMap[string,Symbols.Symbol]) is
65
let prefix = ".{namespace_name}.";
66
67
for ns in _namespaces do
68
if ns.key.starts_with(prefix) then
69
let suffix = ns.key.substring(prefix.length);
70
71
if !suffix.contains('.') /\ !results.contains_key(suffix) then
72
results.add(suffix, ns.value);
73
fi
74
fi
75
od
76
si
77
78
declare_and_enter_namespace(
79
location: LOCATION,
80
name: string,
81
symbol_definition_listener: Semantic.SymbolDefinitionListener,
82
is_compiler_generated: bool
83
) -> Symbols.NAMESPACE
84
is
85
let qualified_name = get_qualified_name(name);
86
let ns = find_or_add_namespace(name, qualified_name, is_compiler_generated);
87
let existing = _symbol_table.current_scope.find_direct(name);
88
89
if existing == null then
90
91
_symbol_table.current_namespace_context.declare_namespace(location, name, ns, symbol_definition_listener);
92
elif existing != ns then
93
_logger.error(location, "redefining symbol {name} as a namespace, originally defined at {existing.location}");
94
_logger.error(existing.location, "symbol {name} is redefined as namespace at {location}");
95
fi
96
97
_prefixes.push(qualified_name);
98
99
return ns;
100
si
101
102
pop_all_namespaces() is
103
// leave global namespace on top
104
while _prefixes.count > 1 do
105
_prefixes.pop();
106
od
107
si
108
109
enter_namespace(location: LOCATION, name: string) -> Symbols.NAMESPACE is
110
let qualified_name = get_qualified_name(name);
111
let ns = find_namespace(qualified_name);
112
113
_prefixes.push(qualified_name);
114
115
return ns;
116
si
117
118
leave_namespace(location: LOCATION, name: string) is
119
let ns = find_namespace(_current_prefix);
120
121
_prefixes.pop();
122
si
123
124
find_or_add_namespace(name: string, qualified_name: string, is_compiler_generated: bool) -> Symbols.NAMESPACE is
125
if _namespaces.contains_key(qualified_name) then
126
return _namespaces[qualified_name];
127
else
128
129
let result = Symbols.NAMESPACE(LOCATION.internal, name, _symbol_table.current_scope, qualified_name, is_compiler_generated);
130
_namespaces[qualified_name] = result;
131
return result;
132
fi
133
si
134
135
find_namespace(qualified_name: string) -> Symbols.NAMESPACE is
136
assert _namespaces.contains_key(qualified_name) else "aggregate namespace {qualified_name} should already exist";
137
138
return _namespaces[qualified_name];
139
si
140
141
try_find_namespace(qualified_name: string) -> Symbols.NAMESPACE? =>
142
if _namespaces.contains_key(qualified_name) then _namespaces[qualified_name] else null fi;
143
si
144
si