Appearance
| 1 | namespace IR.Values.Literal is | |
| 2 | use System.Reflection.Metadata.ILOpCode | |
| 3 | use TypeTyped = Semantic.Types.Typed | |
| 4 | use Semantic.Types.Type | |
| 5 | ||
| 6 | // The constant a numeric literal loads, at the width it is loaded at. | |
| 7 | // | |
| 8 | // An integer is held at the width its load asks for rather than as a | |
| 9 | // magnitude, because the two are not the same: `0xFF00FF00` is a | |
| 10 | // `uint` in range, and the constant `ldc.i4` takes is the 32-bit | |
| 11 | // pattern, which read as a magnitude is negative. | |
| 12 | union CONSTANT is | |
| 13 | I4(value: int) | |
| 14 | I8(value: long) | |
| 15 | R4(value: single) | |
| 16 | R8(value: double) | |
| 17 | si | |
| 18 | ||
| 19 | // A numeric constant, held as the value rather than as the way it was | |
| 20 | // written down. A source literal can be written in any radix and with | |
| 21 | // any suffix, so the spelling and the value are not the same thing, | |
| 22 | // and reading that spelling back is not something emission should | |
| 23 | // have to do. | |
| 24 | class NUMBER: Value, TypeTyped is | |
| 25 | constant: CONSTANT | |
| 26 | type: Type | |
| 27 | ||
| 28 | // Narrows the loaded constant to the literal's declared type, | |
| 29 | // where the width it is loaded at is wider than that type. | |
| 30 | conv: ILOpCode? | |
| 31 | ||
| 32 | is_lightweight_pure: bool => true | |
| 33 | ||
| 34 | is_real: bool => | |
| 35 | case constant | |
| 36 | when _: CONSTANT.R4 then true | |
| 37 | when _: CONSTANT.R8 then true | |
| 38 | else false | |
| 39 | esac | |
| 40 | ||
| 41 | // The constant written out, used to render an attribute | |
| 42 | // argument and as a key for comparing case-arm constants. | |
| 43 | rendered: string => | |
| 44 | case constant | |
| 45 | when i4: CONSTANT.I4 then "{i4.value}" | |
| 46 | when i8: CONSTANT.I8 then "{i8.value}" | |
| 47 | when r4: CONSTANT.R4 then "{r4.value}" | |
| 48 | when r8: CONSTANT.R8 then "{r8.value}" | |
| 49 | esac | |
| 50 | ||
| 51 | init(constant: CONSTANT, type: Type, conv: ILOpCode?) is | |
| 52 | super.init() | |
| 53 | ||
| 54 | self.constant = constant | |
| 55 | self.type = type | |
| 56 | self.conv = conv | |
| 57 | si | |
| 58 | ||
| 59 | init(constant: CONSTANT, type: Type) is | |
| 60 | self.init(constant, type, null) | |
| 61 | si | |
| 62 | ||
| 63 | init(value: int, type: Type) is | |
| 64 | self.init(CONSTANT.I4(value), type, null) | |
| 65 | si | |
| 66 | ||
| 67 | init(value: long, type: Type) is | |
| 68 | self.init(CONSTANT.I8(value), type, null) | |
| 69 | si | |
| 70 | ||
| 71 | init(value: single, type: Type) is | |
| 72 | self.init(CONSTANT.R4(value), type, null) | |
| 73 | si | |
| 74 | ||
| 75 | init(value: double, type: Type) is | |
| 76 | self.init(CONSTANT.R8(value), type, null) | |
| 77 | si | |
| 78 | ||
| 79 | gen(context: IR.CONTEXT) is | |
| 80 | let body = context.current_srm_body_emitter! | |
| 81 | ||
| 82 | case constant | |
| 83 | when i4: CONSTANT.I4 then body.ldc_i4(i4.value) | |
| 84 | when i8: CONSTANT.I8 then body.ldc_i8(i8.value) | |
| 85 | when r4: CONSTANT.R4 then body.ldc_r4(r4.value) | |
| 86 | when r8: CONSTANT.R8 then body.ldc_r8(r8.value) | |
| 87 | esac | |
| 88 | ||
| 89 | if let narrowing = conv then | |
| 90 | body.op(narrowing) | |
| 91 | fi | |
| 92 | si | |
| 93 | ||
| 94 | to_string() -> string => | |
| 95 | "literal:[{type}]({constant})" | |
| 96 | si | |
| 97 | si |