Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Semantic.Types.Type | |
| 3 | use IR.Values.Value | |
| 4 | ||
| 5 | // Splits an operand into the two things a presence test needs: is | |
| 6 | // it here, and what is the value if it is. | |
| 7 | // | |
| 8 | // The three optional lowerings answer both differently. A reference | |
| 9 | // optional is the value, tested against null. A `NULLABLE[T]` or | |
| 10 | // `MAYBE[T]` carries presence in a `has_value` member and the value | |
| 11 | // in a `value` member, both reached through the operand's address - | |
| 12 | // which is why the operand has to be something addressable, a | |
| 13 | // spilled temp rather than an expression. A non-optional operand is | |
| 14 | // simply always here. | |
| 15 | class OPTIONAL_OPERAND(_symbol_loader: Semantic.SYMBOL_LOADER, _bool_type: Type) is | |
| 16 | // Answers null when the operand is not optional at all, which | |
| 17 | // the caller reads as always present rather than as a failure. | |
| 18 | presence(location: Source.LOCATION, operand: Value) -> Value? is | |
| 19 | let type = operand.type | |
| 20 | ||
| 21 | if !type? \/ !type.is_optional then | |
| 22 | return null | |
| 23 | fi | |
| 24 | ||
| 25 | if !type.is_value_type then | |
| 26 | return IR.Values.HAS_VALUE(operand, _bool_type) | |
| 27 | fi | |
| 28 | ||
| 29 | let has_value_member = type.find_member("has_value") | |
| 30 | ||
| 31 | if !has_value_member? \/ !isa Semantic.Symbols.Property(has_value_member) then | |
| 32 | return null | |
| 33 | fi | |
| 34 | ||
| 35 | return has_value_member.load(location, operand, _symbol_loader) | |
| 36 | si | |
| 37 | ||
| 38 | // The value to hand the operator. A reference optional is | |
| 39 | // already it; a value-shape one is projected out of its | |
| 40 | // carrier, which is only sound once presence is established - | |
| 41 | // `Nullable[T].Value` throws when absent. | |
| 42 | // | |
| 43 | // The carrier cannot reliably go across instead. A reflected | |
| 44 | // `Ghul.Equatable[T].=~` takes a bare `T` at IL whatever its | |
| 45 | // optionality says, so handing it one produces an invalid | |
| 46 | // program; a user-declared `=~(other: T?)` on a struct does | |
| 47 | // take the carrier. Rather than have the answer turn on which, | |
| 48 | // the caller settles presence for every value-shape operand. | |
| 49 | payload(location: Source.LOCATION, operand: Value) -> Value? is | |
| 50 | let type = operand.type | |
| 51 | ||
| 52 | if !type? \/ !type.is_optional \/ !type.is_value_type then | |
| 53 | return operand | |
| 54 | fi | |
| 55 | ||
| 56 | let value_member = type.find_member("value") | |
| 57 | ||
| 58 | if !value_member? then | |
| 59 | return null | |
| 60 | fi | |
| 61 | ||
| 62 | return value_member.load(location, operand, _symbol_loader) | |
| 63 | si | |
| 64 | ||
| 65 | // Whether an operand has to have its presence settled here | |
| 66 | // rather than being handed to the operator absent. A value- | |
| 67 | // shape one always does, per `payload` above - and always, | |
| 68 | // rather than only when the other operand happens to be | |
| 69 | // optional, so one comparison does not answer two ways. | |
| 70 | // Reads nothing but the operand, so it needs no instance: a | |
| 71 | // caller deciding whether to build one at all can ask first. | |
| 72 | must_be_guarded(operand: Value) -> bool static is | |
| 73 | let type = operand.type | |
| 74 | ||
| 75 | return type? /\ type.is_optional /\ type.is_value_type | |
| 76 | si | |
| 77 | ||
| 78 | // Whether both halves can be built for this operand. A | |
| 79 | // value-shape optional missing either member is not one this | |
| 80 | // can drive, so the caller leaves the comparison alone. | |
| 81 | can_split(location: Source.LOCATION, operand: Value) -> bool is | |
| 82 | let type = operand.type | |
| 83 | ||
| 84 | if !type? then | |
| 85 | return false | |
| 86 | fi | |
| 87 | ||
| 88 | if !type.is_optional \/ !type.is_value_type then | |
| 89 | return true | |
| 90 | fi | |
| 91 | ||
| 92 | return presence(location, operand)? /\ payload(location, operand)? | |
| 93 | si | |
| 94 | si | |
| 95 | si |