Appearance
| 1 | namespace Semantic.DotNet is | |
| 2 | use TYPE = System.Type | |
| 3 | ||
| 4 | use IO.Std | |
| 5 | ||
| 6 | use Collections.MAP | |
| 7 | ||
| 8 | class SYMBOL_STORE is | |
| 9 | _symbols_by_dotnet_type: MAP[TYPE,Symbols.Scoped] | |
| 10 | // The by-name entries are three-state: no entry at all, an | |
| 11 | // entry with no symbol (the no-result marker cache_no_result | |
| 12 | // writes), or a symbol. | |
| 13 | _symbols_by_ghul_name: MAP[string,Symbols.Scoped?] | |
| 14 | ||
| 15 | count: int => _symbols_by_ghul_name.count | |
| 16 | ||
| 17 | init() is | |
| 18 | _symbols_by_dotnet_type = MAP() | |
| 19 | _symbols_by_ghul_name = MAP() | |
| 20 | si | |
| 21 | ||
| 22 | get_symbol(dotnet_type: TYPE) -> Symbols.Scoped? is | |
| 23 | let result: Symbols.Scoped mut | |
| 24 | ||
| 25 | _symbols_by_dotnet_type.try_get_value(dotnet_type, result ref) | |
| 26 | ||
| 27 | return result | |
| 28 | si | |
| 29 | ||
| 30 | ||
| 31 | // True when the name has a by-name cache entry, including a | |
| 32 | // null no-result marker. Distinct from get_symbol returning | |
| 33 | // null, which conflates "cached no-result" with "never seen". | |
| 34 | has_symbol(ghul_name: string) -> bool => | |
| 35 | _symbols_by_ghul_name.contains_key(ghul_name) | |
| 36 | ||
| 37 | get_symbol(ghul_name: string) -> Symbols.Scoped? is | |
| 38 | let result: Symbols.Scoped? mut = null | |
| 39 | ||
| 40 | _symbols_by_ghul_name.try_get_value(ghul_name, result ref) | |
| 41 | ||
| 42 | return result | |
| 43 | si | |
| 44 | ||
| 45 | // Drops every remembered miss, returning the names that were | |
| 46 | // dropped: a name that resolved to nothing can resolve to | |
| 47 | // something once another assembly has been imported. | |
| 48 | forget_no_results() -> Collections.LIST[string] is | |
| 49 | let forgotten = Collections.LIST[string]() | |
| 50 | ||
| 51 | for entry in _symbols_by_ghul_name do | |
| 52 | if !entry.value? then | |
| 53 | forgotten.add(entry.key) | |
| 54 | fi | |
| 55 | od | |
| 56 | ||
| 57 | for name in forgotten do | |
| 58 | _symbols_by_ghul_name.remove(name) | |
| 59 | od | |
| 60 | ||
| 61 | return forgotten | |
| 62 | si | |
| 63 | ||
| 64 | cache_no_result(ghul_name: string) is | |
| 65 | _symbols_by_ghul_name.add(ghul_name, null) | |
| 66 | si | |
| 67 | ||
| 68 | add_symbol(type: TYPE, ghul_name: string, symbol: Symbols.Scoped) is | |
| 69 | // Idempotent: re-adding the same dotnet_type is a no-op. | |
| 70 | // The backtick-suffix fallback path re-enters create_symbol | |
| 71 | // for a .NET type already materialized via direct lookup | |
| 72 | // (e.g. `Lazy\`1` source after `Lazy` was looked up); the | |
| 73 | // earlier entry stays and the redundant add is skipped. | |
| 74 | if !_symbols_by_dotnet_type.contains_key(type) then | |
| 75 | _symbols_by_dotnet_type.add(type, symbol) | |
| 76 | fi | |
| 77 | ||
| 78 | // Argument-count overloading: when two reflected types share | |
| 79 | // a ghul name (their `\`N` suffix was stripped on import), | |
| 80 | // the first member to be materialized wins the bare-name | |
| 81 | // cache slot. The caller | |
| 82 | // (`symbol_table.materialize_type_group`) is responsible for | |
| 83 | // then overwriting the entry with the assembled TYPE_GROUP | |
| 84 | // via `set_name_symbol`. | |
| 85 | if !_symbols_by_ghul_name.contains_key(ghul_name) then | |
| 86 | _symbols_by_ghul_name.add(ghul_name, symbol) | |
| 87 | fi | |
| 88 | si | |
| 89 | ||
| 90 | set_name_symbol(ghul_name: string, symbol: Symbols.Scoped) is | |
| 91 | _symbols_by_ghul_name[ghul_name] = symbol | |
| 92 | si | |
| 93 | si | |
| 94 | si |