Appearance
| 1 | namespace Semantic.DotNet is | |
| 2 | use TYPE = System.Type | |
| 3 | ||
| 4 | use System.Reflection.FieldInfo | |
| 5 | ||
| 6 | // What a reflected field turns out to be when asked for a constant | |
| 7 | // value. | |
| 8 | // | |
| 9 | // A constant whose value is null is a case of its own rather than a | |
| 10 | // reserved spelling inside the text: a constant string holds whatever | |
| 11 | // a library author wrote, so no word is available to stand for | |
| 12 | // something else. | |
| 13 | union ReflectedConstant is | |
| 14 | // Not a constant, or one whose value cannot be described as text | |
| 15 | // - an ordinary field either way. | |
| 16 | NONE | |
| 17 | ||
| 18 | // A constant whose value is null, which is the only constant of a | |
| 19 | // reference type metadata can hold. | |
| 20 | ABSENT | |
| 21 | ||
| 22 | VALUE(text: string) default | |
| 23 | si | |
| 24 | ||
| 25 | // Reads a reflected `const` field's value. | |
| 26 | // | |
| 27 | // A `const` is a compile-time literal: metadata carries the value and | |
| 28 | // no field is emitted to hold it, because a language that inlines a | |
| 29 | // constant at each use leaves nothing behind for anyone to load. So a | |
| 30 | // consumer has to take the value from here rather than read the field | |
| 31 | // it looks like. | |
| 32 | // | |
| 33 | // The value comes back as invariant-culture text, which is the form a | |
| 34 | // reflected argument default is carried in too - `text_of` is what | |
| 35 | // the two share, each deciding for itself what an absent value means. | |
| 36 | class REFLECTED_CONSTANTS is | |
| 37 | value_of(`field: FieldInfo) -> ReflectedConstant static is | |
| 38 | if !`field.is_literal then | |
| 39 | return ReflectedConstant.NONE | |
| 40 | fi | |
| 41 | ||
| 42 | let raw = `field.get_raw_constant_value() | |
| 43 | ||
| 44 | if !raw? then | |
| 45 | return ReflectedConstant.ABSENT | |
| 46 | fi | |
| 47 | ||
| 48 | if let text = text_of(raw, `field.field_type) then | |
| 49 | return ReflectedConstant.VALUE(text) | |
| 50 | fi | |
| 51 | ||
| 52 | return ReflectedConstant.NONE | |
| 53 | si | |
| 54 | ||
| 55 | // A reflected value as invariant-culture text, or null when it is | |
| 56 | // not one that can be described that way. Culture-independent | |
| 57 | // because this is read back by the compiler rather than shown to | |
| 58 | // anyone. | |
| 59 | text_of(value: object, type: TYPE) -> string? static is | |
| 60 | if | |
| 61 | !type.is_primitive /\ | |
| 62 | !type.is_enum /\ | |
| 63 | type.full_name !~ "System.String" | |
| 64 | then | |
| 65 | return null | |
| 66 | fi | |
| 67 | ||
| 68 | let convertible = cast System.IConvertible?(value) | |
| 69 | ||
| 70 | if !convertible? then | |
| 71 | return null | |
| 72 | fi | |
| 73 | ||
| 74 | return convertible.to_string( | |
| 75 | System.Globalization.CultureInfo.invariant_culture | |
| 76 | ) | |
| 77 | si | |
| 78 | si | |
| 79 | si |