Skip to content
← Back

src/syntax/process/body_declarer.ghul

1
namespace Syntax.Process is
2
use Logging
3
4
use Trees
5
6
// Walks the edited file's declaration skeleton, entering the retained
7
// scopes, and re-declares each function's body through DECLARE_MEMBERS -
8
// the declare-symbols half of the incremental body re-walk.
9
//
10
// The interface declarations are not re-declared: ScopedVisitor's
11
// inherited `pre`/`visit` for namespace / class / trait / … only *enter*
12
// the retained scopes (a lookup, not a fresh declaration), so the
13
// retained interface symbols are kept and declare-symbols' non-idempotency
14
// is never exercised. Only the new body subtrees get fresh block scopes
15
// and locals.
16
class BODY_DECLARER: ScopedVisitor is
17
_declare_members: DECLARE_MEMBERS
18
19
init(
20
logger: Logger,
21
symbol_table: Semantic.SYMBOL_TABLE,
22
namespaces: Semantic.NAMESPACES,
23
declare_members: DECLARE_MEMBERS
24
) is
25
super.init(logger, symbol_table, namespaces)
26
27
_declare_members = declare_members
28
si
29
30
// At a function: enter its retained scope, declare the new body, and
31
// return true so the skeleton walk does not also descend the body.
32
// `visit(function)` (inherited) leaves the scope.
33
pre(function: Trees.Definitions.FUNCTION) -> bool is
34
enter_scope(function)
35
36
if function.is_top_level_entry then
37
_remove_top_level_variables()
38
fi
39
40
_declare_members.declare_body(function)
41
42
return true
43
si
44
45
// A top-level `let` is declared into the file's namespace from
46
// inside the synthesised entry's body, so re-declaring that body
47
// declares each of them again. The ones the previous build left
48
// are removed first: the entry is the only thing that declares a
49
// variable of this kind into the namespace, so all of them are
50
// its own, and an edit that renamed or removed one leaves nothing
51
// behind for a sibling function to resolve against. The namespace
52
// block remembers what each name resolved to, so that goes too.
53
_remove_top_level_variables() is
54
if let scope = _symbol_table.current_namespace_block then
55
scope.forget_lookups()
56
fi
57
58
let `namespace = _symbol_table.current_namespace_symbol
59
60
if !`namespace? then
61
return
62
fi
63
64
let stale = Collections.LIST[string]()
65
66
for symbol in `namespace.symbols do
67
if isa Semantic.Symbols.TOP_LEVEL_VARIABLE(symbol) then
68
stale.add(symbol.name)
69
fi
70
od
71
72
for name in stale do
73
`namespace.remove_direct(name)
74
od
75
si
76
77
// Property and indexer accessor bodies are reached through the
78
// synthesised sibling `$get_`/`$set_` (and `get_`/`set_`) FUNCTION
79
// nodes, so the declaration node itself is not descended.
80
pre(property: Trees.Definitions.PROPERTY) -> bool => true
81
82
pre(indexer: Trees.Definitions.INDEXER) -> bool => true
83
si
84
si