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", existing.location, "symbol declared here")
94
_logger.error(existing.location, "symbol {name} is redefined as a namespace", location, "redefined here")
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