Appearance
| 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 |