Appearance
| 1 | namespace IR.Values is | |
| 2 | use Semantic.Types.Type | |
| 3 | ||
| 4 | // Declares one CLR local. | |
| 5 | // | |
| 6 | // A body header points at a StandAloneSig listing the local types | |
| 7 | // in slot order, and every load and store addresses a slot by | |
| 8 | // index, so a declaration has to reach the emitter as data rather | |
| 9 | // than as anything textual. | |
| 10 | // | |
| 11 | // Being in the block gets the ordering right for free: a | |
| 12 | // declaration is emitted before the loads that follow it, so the | |
| 13 | // slot exists by the time one is encoded. | |
| 14 | class DECLARE_LOCAL: Value is | |
| 15 | name: string | |
| 16 | type: Type | |
| 17 | ||
| 18 | init(name: string, type: Type) is | |
| 19 | super.init() | |
| 20 | ||
| 21 | self.name = name | |
| 22 | self.type = type | |
| 23 | si | |
| 24 | ||
| 25 | gen(context: IR.CONTEXT) is | |
| 26 | let body = context.current_srm_body_emitter! | |
| 27 | body.declare_local(name, type) | |
| 28 | si | |
| 29 | ||
| 30 | to_string() -> string => "declare-local:[{type}]({name})" | |
| 31 | si | |
| 32 | ||
| 33 | // Stores the top of the stack into a named local. The counterpart | |
| 34 | // of DECLARE_LOCAL, and raw text for the same reason. | |
| 35 | class STORE_TEMP: Value is | |
| 36 | name: string | |
| 37 | type: Type | |
| 38 | ||
| 39 | init(name: string, type: Type) is | |
| 40 | super.init() | |
| 41 | ||
| 42 | self.name = name | |
| 43 | self.type = type | |
| 44 | si | |
| 45 | ||
| 46 | gen(context: IR.CONTEXT) is | |
| 47 | let body = context.current_srm_body_emitter! | |
| 48 | body.stloc(name) | |
| 49 | si | |
| 50 | ||
| 51 | to_string() -> string => "store-temp:[{type}]({name})" | |
| 52 | si | |
| 53 | ||
| 54 | // Returns from the enclosing method. A value for the same reason | |
| 55 | // as DECLARE_LOCAL: silently dropping an instruction produces a | |
| 56 | // body that fails verification with nothing to point at. | |
| 57 | class RET: Value is | |
| 58 | init() is | |
| 59 | super.init() | |
| 60 | si | |
| 61 | ||
| 62 | gen(context: IR.CONTEXT) is | |
| 63 | let body = context.current_srm_body_emitter! | |
| 64 | body.ret() | |
| 65 | si | |
| 66 | ||
| 67 | to_string() -> string => "ret" | |
| 68 | si | |
| 69 | ||
| 70 | // The value a non-void function falls out of the bottom with: a | |
| 71 | // fresh local of the return type, never assigned, loaded so the | |
| 72 | // trailing `ret` has something to return. The local is anonymous | |
| 73 | // and used once, so it is declared and loaded together rather than | |
| 74 | // through the usual declare-then-load pair. | |
| 75 | class DEFAULT_RETURN: Value is | |
| 76 | type: Type | |
| 77 | ||
| 78 | init(type: Type) is | |
| 79 | super.init() | |
| 80 | ||
| 81 | self.type = type | |
| 82 | si | |
| 83 | ||
| 84 | gen(context: IR.CONTEXT) is | |
| 85 | let body = context.current_srm_body_emitter! | |
| 86 | body.declare_local(".default", type) | |
| 87 | body.ldloc(".default") | |
| 88 | si | |
| 89 | ||
| 90 | to_string() -> string => "default-return:[{type}]()" | |
| 91 | si | |
| 92 | si |