Appearance
| 1 | namespace Semantic is | |
| 2 | use Symbols.Symbol; | |
| 3 | ||
| 4 | // Decides the scope that symbol names render relative to. By default | |
| 5 | // that is the scope currently being compiled (read on demand from the | |
| 6 | // symbol table, so it stays correct however the scope stack is | |
| 7 | // unwound), which is why a diagnostic reads relative to where it is | |
| 8 | // reported. An override replaces that default for the duration of a | |
| 9 | // language-service render (targeting the cursor's scope) or a region | |
| 10 | // that needs scope-independent output (`with_scope(null)` forces fully | |
| 11 | // qualified names, e.g. for a canonical ordering). | |
| 12 | class NAME_DISPLAY is | |
| 13 | _override_scope: Scope?; | |
| 14 | _has_override: bool; | |
| 15 | ||
| 16 | init() is | |
| 17 | si | |
| 18 | ||
| 19 | render_scope: Scope? => | |
| 20 | if _has_override then | |
| 21 | _override_scope; | |
| 22 | else | |
| 23 | _current_build_scope; | |
| 24 | fi; | |
| 25 | ||
| 26 | _current_build_scope: Scope? is | |
| 27 | let symbol_table = IoC.CONTAINER.instance.symbol_table; | |
| 28 | ||
| 29 | return symbol_table.current_scope; | |
| 30 | si | |
| 31 | ||
| 32 | name_for(symbol: Symbol) -> string => | |
| 33 | symbol.render_name(render_scope); | |
| 34 | ||
| 35 | // The scope-relative name without its type-argument suffix — for | |
| 36 | // rendering a constructed generic's head, which then appends its own | |
| 37 | // actual arguments. | |
| 38 | bare_name_for(symbol: Symbol) -> string => | |
| 39 | symbol._render_scope_relative_name(render_scope); | |
| 40 | ||
| 41 | // Render relative to `scope` (null forces fully qualified) until the | |
| 42 | // returned holder is disposed. Consume with `let use` so the | |
| 43 | // previous render scope is restored on every exit path, including | |
| 44 | // when rendering throws. | |
| 45 | with_scope(scope: Scope?) -> RENDER_SCOPE_HOLDER is | |
| 46 | let holder = RENDER_SCOPE_HOLDER(self, _override_scope, _has_override); | |
| 47 | ||
| 48 | _override_scope = scope; | |
| 49 | _has_override = true; | |
| 50 | ||
| 51 | return holder; | |
| 52 | si | |
| 53 | ||
| 54 | restore_override(scope: Scope?, has_override: bool) is | |
| 55 | _override_scope = scope; | |
| 56 | _has_override = has_override; | |
| 57 | si | |
| 58 | si | |
| 59 | ||
| 60 | struct RENDER_SCOPE_HOLDER: Disposable is | |
| 61 | _display: NAME_DISPLAY?; | |
| 62 | _previous_scope: Scope?; | |
| 63 | _previous_has_override: bool; | |
| 64 | ||
| 65 | init(display: NAME_DISPLAY, previous_scope: Scope?, previous_has_override: bool) is | |
| 66 | _display = display; | |
| 67 | _previous_scope = previous_scope; | |
| 68 | _previous_has_override = previous_has_override; | |
| 69 | si | |
| 70 | ||
| 71 | dispose() is | |
| 72 | // A value-type disposable must be safe on its default value: | |
| 73 | // `let use` disposal null-checks reference types before calling | |
| 74 | // dispose but not value types, so an early return past the | |
| 75 | // `let use` hands dispose a zero-initialized holder. A null | |
| 76 | // display means the holder was never constructed and so set no | |
| 77 | // override to restore. | |
| 78 | let display = _display; | |
| 79 | ||
| 80 | if display? then | |
| 81 | display.restore_override(_previous_scope, _previous_has_override); | |
| 82 | fi | |
| 83 | si | |
| 84 | si | |
| 85 | si |