Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Logging; | |
| 3 | use Source; | |
| 4 | use Trees; | |
| 5 | ||
| 6 | use Ghul.Pipes; | |
| 7 | ||
| 8 | // Resolves use clauses into their namespace block's scope. Runs | |
| 9 | // twice: a first round after declare-symbols binds every import that | |
| 10 | // refers to a type - classes, structs, unions, variants, enums - and | |
| 11 | // namespaces, which is everything resolve-type-expressions needs. A | |
| 12 | // name that fails to bind is left for the second round (`_final` | |
| 13 | // unset marks the first-round instance), which runs after | |
| 14 | // declare-members, so an import can also name a static method, a | |
| 15 | // global function or an enum member - including one an impl or | |
| 16 | // partial block injects; anything still unresolved then is an error. | |
| 17 | class RESOLVE_USES: ScopeVisitorBase is | |
| 18 | _logger: Logger; | |
| 19 | _symbol_table: Semantic.SYMBOL_TABLE; | |
| 20 | _symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS; | |
| 21 | _final: bool; | |
| 22 | ||
| 23 | init( | |
| 24 | logger: Logger, | |
| 25 | symbol_table: Semantic.SYMBOL_TABLE, | |
| 26 | namespaces: Semantic.NAMESPACES, | |
| 27 | symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS, | |
| 28 | final: bool | |
| 29 | ) is | |
| 30 | super.init(symbol_table, namespaces); | |
| 31 | _logger = logger; | |
| 32 | _symbol_table = symbol_table; | |
| 33 | _symbol_use_locations = symbol_use_locations; | |
| 34 | _final = final; | |
| 35 | si | |
| 36 | ||
| 37 | apply(node: Node) is | |
| 38 | node.walk(self); | |
| 39 | si | |
| 40 | ||
| 41 | pre(`namespace: Definitions.NAMESPACE) -> bool is | |
| 42 | let namespace_scope = enter_namespace(`namespace); | |
| 43 | ||
| 44 | // FIXME: these searches probably should start at the scope immediately enclosing the namespace | |
| 45 | for u in `namespace.body.uses do | |
| 46 | if !u.`use? then | |
| 47 | continue; | |
| 48 | fi | |
| 49 | ||
| 50 | if !_final then | |
| 51 | u.is_import_resolved = _resolve_use(u, namespace_scope); | |
| 52 | elif !u.is_import_resolved then | |
| 53 | _resolve_use(u, namespace_scope); | |
| 54 | fi | |
| 55 | od | |
| 56 | return false; | |
| 57 | si | |
| 58 | ||
| 59 | visit(`namespace: Definitions.NAMESPACE) is | |
| 60 | leave_namespace(`namespace); | |
| 61 | si | |
| 62 | ||
| 63 | // Returns true when the clause was definitively handled - a | |
| 64 | // successful import or, in the final round, a reported error. | |
| 65 | _resolve_use(u: Definitions.USE, namespace_scope: Semantic.NAMESPACE_SCOPE) -> bool is | |
| 66 | let used_name = u.`use; | |
| 67 | ||
| 68 | if !used_name? then | |
| 69 | return true; | |
| 70 | fi | |
| 71 | ||
| 72 | let used_symbol = find_enclosing(used_name); | |
| 73 | ||
| 74 | if !used_symbol? then | |
| 75 | if _final then | |
| 76 | _logger.error(used_name.location, "used identifier {used_name} is not defined "); | |
| 77 | fi | |
| 78 | ||
| 79 | return false; | |
| 80 | fi | |
| 81 | ||
| 82 | let use_name mut = used_symbol.name; | |
| 83 | let alias = u.name; | |
| 84 | ||
| 85 | if alias? then | |
| 86 | use_name = alias.name; | |
| 87 | fi | |
| 88 | ||
| 89 | if isa Semantic.Symbols.NAMESPACE(used_symbol) then | |
| 90 | _symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol); | |
| 91 | ||
| 92 | if namespace_scope.contains_used_symbol(use_name) then | |
| 93 | if alias? then | |
| 94 | _logger.error(alias.location, "duplicate use"); | |
| 95 | else | |
| 96 | _logger.error(used_name.location, "duplicate use"); | |
| 97 | fi | |
| 98 | elif alias? then | |
| 99 | namespace_scope.add(alias.name, used_symbol); | |
| 100 | else | |
| 101 | namespace_scope.add(used_symbol); | |
| 102 | fi | |
| 103 | elif used_symbol.is_function_group then | |
| 104 | let fg = cast Semantic.Symbols.FUNCTION_GROUP?(used_symbol)!; | |
| 105 | ||
| 106 | if !fg.functions |> any(f => !f.is_instance) then | |
| 107 | if fg.functions.count == 1 then | |
| 108 | _logger.error(used_name.location, "cannot use instance function"); | |
| 109 | else | |
| 110 | _logger.error(used_name.location, "cannot use function group comprising only instance functions"); | |
| 111 | fi | |
| 112 | fi | |
| 113 | ||
| 114 | _symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol.collapse_group_if_single_member()); | |
| 115 | ||
| 116 | let existing_used_symbol = namespace_scope.get_used_symbol(use_name); | |
| 117 | ||
| 118 | let use_function_group: Semantic.Symbols.FUNCTION_GROUP mut; | |
| 119 | ||
| 120 | if existing_used_symbol? then | |
| 121 | use_function_group = cast Semantic.Symbols.FUNCTION_GROUP?(existing_used_symbol)!; | |
| 122 | else | |
| 123 | use_function_group = Semantic.Symbols.FUNCTION_GROUP(LOCATION.unknown, namespace_scope, use_name); | |
| 124 | namespace_scope.add(use_name, use_function_group); | |
| 125 | fi | |
| 126 | ||
| 127 | use_function_group.add(fg); | |
| 128 | elif !used_symbol.is_instance then | |
| 129 | if namespace_scope.contains_used_symbol(use_name) then | |
| 130 | if alias? then | |
| 131 | _logger.error(alias.location, "duplicate use"); | |
| 132 | else | |
| 133 | _logger.error(used_name.location, "duplicate use"); | |
| 134 | fi | |
| 135 | else | |
| 136 | _symbol_use_locations.add_symbol_use(used_name.right_location, used_symbol); | |
| 137 | namespace_scope.add(use_name, used_symbol); | |
| 138 | fi | |
| 139 | else | |
| 140 | _logger.error(used_name.location, "cannot use instance member"); | |
| 141 | fi | |
| 142 | ||
| 143 | return true; | |
| 144 | si | |
| 145 | si | |
| 146 | si |