Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use System.Exception; | |
| 3 | use System.Text.StringBuilder; | |
| 4 | ||
| 5 | use Logging; | |
| 6 | use Source; | |
| 7 | ||
| 8 | use IR.Values.Value; | |
| 9 | ||
| 10 | use Types.Type; | |
| 11 | ||
| 12 | class Property: Symbol, Types.SettableTyped abstract is | |
| 13 | _overriders: Collections.MutableList[Symbol]?; | |
| 14 | _overridees: Collections.MutableList[Symbol]?; | |
| 15 | ||
| 16 | span: LOCATION; | |
| 17 | type: Type?; | |
| 18 | ||
| 19 | // Incremental body re-walk override: also shift the declaration | |
| 20 | // span when the retained interface symbol is relocated. | |
| 21 | set_span(span_location: LOCATION) is | |
| 22 | span = span_location; | |
| 23 | si | |
| 24 | ||
| 25 | set_type(value: Type) is type = value; si | |
| 26 | ||
| 27 | short_description: string => "{name}: {if type? then type!.short_description else "?" fi}"; | |
| 28 | symbol_kind: SymbolKind => SymbolKind.PROPERTY; | |
| 29 | completion_kind: CompletionKind => CompletionKind.PROPERTY; | |
| 30 | is_private: bool; | |
| 31 | is_assignable: bool public; | |
| 32 | is_workspace_visible: bool => !name.starts_with('_'); | |
| 33 | ||
| 34 | read_function: Function? public; | |
| 35 | read_function_il_name_override: string? public; | |
| 36 | ||
| 37 | assign_function: Function? public; | |
| 38 | assign_function_il_name_override: string? public; | |
| 39 | ||
| 40 | overriders: Collections.Iterable[Symbol]? => _overriders; | |
| 41 | overridees: Collections.Iterable[Symbol]? => _overridees; | |
| 42 | ||
| 43 | has_overriders: bool => _overriders? /\ _overriders.count > 0; | |
| 44 | ||
| 45 | // Prefixes the description's trailing kind comment when the | |
| 46 | // getter is proven store-free — diagnostic surfacing only, | |
| 47 | // deliberately inside the comment so it does not read as | |
| 48 | // source syntax. | |
| 49 | pure_prefix: string => | |
| 50 | if read_function? /\ read_function.is_store_free then | |
| 51 | "pure " | |
| 52 | else | |
| 53 | "" | |
| 54 | fi; | |
| 55 | ||
| 56 | // Shared body for the three concrete Property kinds. Delegates | |
| 57 | // to Symbol._describe_typed so a narrowed property (path | |
| 58 | // narrowing over a `T?` getter) surfaces the same | |
| 59 | // `declared → narrowed` display a variable use gets. | |
| 60 | _describe_property(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 61 | _describe_typed(context, PARTS.name(self), type); | |
| 62 | ||
| 63 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is | |
| 64 | super.init(location, owner, name); | |
| 65 | ||
| 66 | self.span = span; | |
| 67 | self.is_assignable = is_assignable; | |
| 68 | self.is_private = is_private; | |
| 69 | si | |
| 70 | ||
| 71 | add_overrider(overrider: Symbol mut) is | |
| 72 | let rsf = root_specialized_from; | |
| 73 | if rsf != self then | |
| 74 | rsf.add_overrider(overrider); | |
| 75 | return; | |
| 76 | fi | |
| 77 | ||
| 78 | let overriders mut = _overriders; | |
| 79 | ||
| 80 | if !overriders? then | |
| 81 | overriders = Collections.LIST[Symbol](); | |
| 82 | _overriders = overriders; | |
| 83 | fi | |
| 84 | ||
| 85 | overrider = overrider.root_specialized_from; | |
| 86 | ||
| 87 | if overriders.contains(overrider) then | |
| 88 | return; | |
| 89 | fi | |
| 90 | ||
| 91 | overriders.add(overrider); | |
| 92 | ||
| 93 | if let journal = INHERITANCE_JOURNAL.current then | |
| 94 | journal.record(InheritanceOp.PROPERTY_OVERRIDER_ADDED(self, overrider)); | |
| 95 | fi | |
| 96 | si | |
| 97 | ||
| 98 | remove_overrider(overrider: Symbol) is | |
| 99 | let rsf = root_specialized_from; | |
| 100 | if rsf != self then | |
| 101 | rsf.remove_overrider(overrider); | |
| 102 | return; | |
| 103 | fi | |
| 104 | ||
| 105 | let overriders = _overriders; | |
| 106 | ||
| 107 | if overriders? then | |
| 108 | overriders.remove(overrider.root_specialized_from); | |
| 109 | fi | |
| 110 | si | |
| 111 | ||
| 112 | add_overridee(overridee: Symbol mut) is | |
| 113 | let rsf = root_specialized_from; | |
| 114 | if rsf != self then | |
| 115 | rsf.add_overridee(overridee); | |
| 116 | return; | |
| 117 | fi | |
| 118 | ||
| 119 | let overridees mut = _overridees; | |
| 120 | ||
| 121 | if !overridees? then | |
| 122 | overridees = Collections.LIST[Symbol](); | |
| 123 | _overridees = overridees; | |
| 124 | fi | |
| 125 | ||
| 126 | overridee = overridee.root_specialized_from; | |
| 127 | ||
| 128 | if overridees.contains(overridee) then | |
| 129 | return; | |
| 130 | fi | |
| 131 | ||
| 132 | overridees.add(overridee); | |
| 133 | ||
| 134 | if let journal = INHERITANCE_JOURNAL.current then | |
| 135 | journal.record(InheritanceOp.PROPERTY_OVERRIDEE_ADDED(self, overridee)); | |
| 136 | fi | |
| 137 | si | |
| 138 | ||
| 139 | remove_overridee(overridee: Symbol) is | |
| 140 | let rsf = root_specialized_from; | |
| 141 | if rsf != self then | |
| 142 | rsf.remove_overridee(overridee); | |
| 143 | return; | |
| 144 | fi | |
| 145 | ||
| 146 | let overridees = _overridees; | |
| 147 | ||
| 148 | if overridees? then | |
| 149 | overridees.remove(overridee.root_specialized_from); | |
| 150 | fi | |
| 151 | si | |
| 152 | ||
| 153 | specialize(type_map: Collections.Map[string,Type], owner: GENERIC) -> Symbol is | |
| 154 | let result = cast Property?(self.memberwise_clone())!; | |
| 155 | ||
| 156 | result.specialized_from = self; | |
| 157 | ||
| 158 | if type? then | |
| 159 | result.type = type.specialize(type_map); | |
| 160 | fi | |
| 161 | ||
| 162 | if read_function? then | |
| 163 | result.read_function = read_function.specialize_function(type_map, owner); | |
| 164 | fi | |
| 165 | ||
| 166 | if assign_function? then | |
| 167 | result.assign_function = assign_function.specialize_function(type_map, owner); | |
| 168 | fi | |
| 169 | ||
| 170 | // Attribute the specialized property to the constructed generic so | |
| 171 | // its owner renders with the actual type arguments | |
| 172 | // (`Iterator[char].current`, not `Iterator[T].current`), matching | |
| 173 | // how fields and methods specialize. | |
| 174 | result.owner = owner; | |
| 175 | ||
| 176 | return result; | |
| 177 | si | |
| 178 | ||
| 179 | gen_reference(buffer: StringBuilder) => throw System.NotImplementedException("properties cannot be referenced directly"); | |
| 180 | gen_definition_header(buffer: StringBuilder) is | |
| 181 | buffer.append(".property "); | |
| 182 | ||
| 183 | gen_access(buffer); | |
| 184 | ||
| 185 | gen_flags(buffer); | |
| 186 | ||
| 187 | type!.gen_type(buffer); | |
| 188 | ||
| 189 | gen_name(buffer); | |
| 190 | ||
| 191 | buffer.append("() {{ "); | |
| 192 | ||
| 193 | if let self.read_function? then | |
| 194 | buffer.append(".get "); | |
| 195 | read_function.gen_reference_for_property(buffer); | |
| 196 | fi | |
| 197 | ||
| 198 | buffer.append(' '); | |
| 199 | ||
| 200 | if let self.assign_function? then | |
| 201 | buffer.append(".set "); | |
| 202 | assign_function.gen_reference_for_property(buffer); | |
| 203 | fi | |
| 204 | ||
| 205 | buffer.append('}'); | |
| 206 | si | |
| 207 | ||
| 208 | gen_access(buffer: StringBuilder) is | |
| 209 | si | |
| 210 | ||
| 211 | gen_flags(buffer: StringBuilder) is | |
| 212 | si | |
| 213 | ||
| 214 | to_string() -> string is | |
| 215 | let result = System.Text.StringBuilder(); | |
| 216 | ||
| 217 | try | |
| 218 | result.append(IoC.CONTAINER.instance.name_display.name_for(self)); | |
| 219 | result.append(": "); | |
| 220 | result.append(type); | |
| 221 | ||
| 222 | return result.to_string(); | |
| 223 | catch ex: Exception | |
| 224 | return "[garbled property: {result}]"; | |
| 225 | yrt | |
| 226 | si | |
| 227 | si | |
| 228 | ||
| 229 | class INSTANCE_PROPERTY: Property is | |
| 230 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 231 | _describe_property(context); | |
| 232 | ||
| 233 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 234 | "{pure_prefix}instance property"; | |
| 235 | ||
| 236 | is_instance: bool => true; | |
| 237 | ||
| 238 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is | |
| 239 | super.init(location, span, owner, name, is_assignable, is_private); | |
| 240 | si | |
| 241 | ||
| 242 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_instance_property(location, from, self); | |
| 243 | ||
| 244 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_instance_property(location, from, self, value); | |
| 245 | ||
| 246 | gen_flags(buffer: StringBuilder) is | |
| 247 | buffer.append("instance callconv(8) "); | |
| 248 | si | |
| 249 | si | |
| 250 | ||
| 251 | class STATIC_PROPERTY: Property is | |
| 252 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 253 | _describe_property(context); | |
| 254 | ||
| 255 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 256 | "{pure_prefix}class property"; | |
| 257 | ||
| 258 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is | |
| 259 | super.init(location, span, owner, name, is_assignable, is_private); | |
| 260 | si | |
| 261 | ||
| 262 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_static_property(location, self); | |
| 263 | ||
| 264 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_static_property(location, self, value); | |
| 265 | ||
| 266 | gen_flags(buffer: StringBuilder) is | |
| 267 | buffer.append("callconv(8) "); | |
| 268 | si | |
| 269 | si | |
| 270 | ||
| 271 | class GLOBAL_PROPERTY: Property is | |
| 272 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 273 | _describe_property(context); | |
| 274 | ||
| 275 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 276 | "{pure_prefix}global property"; | |
| 277 | ||
| 278 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool) is | |
| 279 | super.init(location, span, owner, name, is_assignable, false); | |
| 280 | si | |
| 281 | ||
| 282 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_global_property(location, self); | |
| 283 | ||
| 284 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_global_property(location, self, value); | |
| 285 | ||
| 286 | gen_flags(buffer: StringBuilder) is | |
| 287 | buffer.append("callconv(8) "); | |
| 288 | si | |
| 289 | si | |
| 290 | si |