Appearance
| 1 | namespace Semantic is | |
| 2 | use IR.Values.Value | |
| 3 | use Ghul.Disposable | |
| 4 | ||
| 5 | use Types.Type | |
| 6 | ||
| 7 | // Resolves an index whose argument is a `System.Range`, `Ghul.INT_RANGE` | |
| 8 | // or `Ghul.INT_RANGE_INCLUSIVE` to a slice of the source: | |
| 9 | // `Ghul.Pipes.slice(source, range)`. | |
| 10 | // | |
| 11 | // The slice cannot be supplied as a member of the types that want it. | |
| 12 | // `Collections.List[E]` is the interface every list-shaped receiver | |
| 13 | // satisfies, and a member added there does not reach the types that | |
| 14 | // implement it: a reflected type arrives from .NET with its inherited | |
| 15 | // members already pulled down, so nothing propagates a later addition. | |
| 16 | // Supplying it per receiver instead reaches an array and a string, | |
| 17 | // which are the receiver types themselves, and then owes the same work | |
| 18 | // to the next collection and to every user type. Resolving it as an | |
| 19 | // ordinary call lets the receiver's own type select the overload. | |
| 20 | class RANGE_SLICE_RESOLVER( | |
| 21 | _innate_symbol_lookup: Lookups.InnateSymbolLookup, | |
| 22 | _overload_resolver: OVERLOAD_RESOLVER, | |
| 23 | _function_caller: FUNCTION_CALLER, | |
| 24 | _logger: Logging.Logger | |
| 25 | ) is | |
| 26 | // The `slice` overload serving this index, or null when there is | |
| 27 | // none: the argument is not a range, or nothing in scope takes one | |
| 28 | // over this source. A caller reports its own diagnostic then. | |
| 29 | try_resolve( | |
| 30 | location: Source.LOCATION, | |
| 31 | source: Value, | |
| 32 | index_type: Type | |
| 33 | ) -> OVERLOAD_RESOLVE_RESULT? is | |
| 34 | if !is_range(index_type) then | |
| 35 | return null | |
| 36 | fi | |
| 37 | ||
| 38 | let functions = _innate_symbol_lookup.get_slice_functions() | |
| 39 | ||
| 40 | if !functions? then | |
| 41 | return null | |
| 42 | fi | |
| 43 | ||
| 44 | let source_type = source.type | |
| 45 | ||
| 46 | if !source_type? then | |
| 47 | return null | |
| 48 | fi | |
| 49 | ||
| 50 | let types = Collections.LIST[Type]([source_type, index_type]) | |
| 51 | ||
| 52 | let use logger_snapshot = _logger.speculate_then_backtrack() | |
| 53 | ||
| 54 | let resolved = _overload_resolver.resolve(location, functions, types, false, false, false) | |
| 55 | ||
| 56 | logger_snapshot.backtrack() | |
| 57 | ||
| 58 | return resolved | |
| 59 | si | |
| 60 | ||
| 61 | is_range(index_type: Type) -> bool => | |
| 62 | index_type.compare(_innate_symbol_lookup.get_range_type()) == Types.MATCH.SAME \/ | |
| 63 | index_type.compare(_innate_symbol_lookup.get_int_range_type()) == Types.MATCH.SAME \/ | |
| 64 | index_type.compare(_innate_symbol_lookup.get_int_range_inclusive_type()) == Types.MATCH.SAME | |
| 65 | ||
| 66 | // The call itself, once the caller has recorded the use it wants | |
| 67 | // recorded against the resolved function. | |
| 68 | call( | |
| 69 | location: Source.LOCATION, | |
| 70 | resolved: OVERLOAD_RESOLVE_RESULT, | |
| 71 | source: Value, | |
| 72 | range: Value | |
| 73 | ) -> Value => | |
| 74 | resolved.function.call( | |
| 75 | location, | |
| 76 | null, | |
| 77 | Collections.LIST[Value]([source, range]), | |
| 78 | null, | |
| 79 | _function_caller) | |
| 80 | si | |
| 81 | si |