Skip to content
← Back

src/ir/values/protected_region.ghul

1
namespace IR.Values is
2
use Semantic.Types.Type
3
4
// The extent of one `.try` block, shared by every handler attached
5
// to it — a `try` with three catches is three regions over a single
6
// extent.
7
//
8
// SRM delimits a region by four labels and the handler's type,
9
// added to the body's control-flow builder once every one of them
10
// is known — rather than by a nesting whose extents fall out of
11
// the walk. So the boundaries have to be recorded as the walk
12
// passes them and held somewhere until each region closes, which
13
// is what this and PROTECTED_REGION are for.
14
class TRY_EXTENT is
15
start: int public
16
end: int public
17
18
init() is
19
start = -1
20
end = -1
21
si
22
si
23
24
// One handler over an extent: a catch of `catch_type`, or — when
25
// that is null — a finally.
26
class PROTECTED_REGION is
27
extent: TRY_EXTENT
28
catch_type: Type?
29
30
// A catch over a framework type the compilation has no symbol
31
// for, named the way the assert helper names its exception.
32
// Set instead of `catch_type`, never alongside it.
33
catch_type_name: (assembly: string, `namespace: string, name: string)?
34
35
handler_start: int public
36
handler_end: int public
37
38
init(extent: TRY_EXTENT, catch_type: Type?) is
39
self.extent = extent
40
self.catch_type = catch_type
41
self.catch_type_name = null
42
43
handler_start = -1
44
handler_end = -1
45
si
46
47
init(
48
extent: TRY_EXTENT,
49
assembly: string,
50
`namespace: string,
51
name: string
52
) is
53
self.extent = extent
54
self.catch_type = null
55
self.catch_type_name = (assembly = assembly, `namespace = `namespace, name = name)
56
57
handler_start = -1
58
handler_end = -1
59
si
60
61
is_catch: bool => catch_type? \/ catch_type_name?
62
63
// The caught type as it reads in this value's description.
64
catch_type_il: string =>
65
if let type = catch_type then
66
"{type}"
67
elif let named = catch_type_name then
68
"{named.`namespace}.{named.name}"
69
else
70
""
71
fi
72
si
73
74
// `.try {`
75
class TRY_START: Value is
76
_extent: TRY_EXTENT
77
78
init(extent: TRY_EXTENT) is
79
super.init()
80
81
_extent = extent
82
si
83
84
gen(context: IR.CONTEXT) is
85
let body = context.current_srm_body_emitter!
86
_extent.start = body.mark_region_boundary()
87
si
88
89
to_string() -> string => ".try {{"
90
si
91
92
// The `}` closing a `.try` block.
93
class TRY_END: Value is
94
_extent: TRY_EXTENT
95
96
init(extent: TRY_EXTENT) is
97
super.init()
98
99
_extent = extent
100
si
101
102
gen(context: IR.CONTEXT) is
103
let body = context.current_srm_body_emitter!
104
_extent.end = body.mark_region_boundary()
105
si
106
107
to_string() -> string => "}} // try"
108
si
109
110
// `catch T {` or `finally {`
111
class HANDLER_START: Value is
112
_region: PROTECTED_REGION
113
114
init(region: PROTECTED_REGION) is
115
super.init()
116
117
_region = region
118
si
119
120
gen(context: IR.CONTEXT) is
121
let body = context.current_srm_body_emitter!
122
_region.handler_start = body.mark_region_boundary()
123
si
124
125
to_string() -> string =>
126
if _region.is_catch then
127
"catch {_region.catch_type_il} {{"
128
else
129
"finally {{"
130
fi
131
si
132
133
// The `}` closing a handler, and the point at which every boundary
134
// of the region is known — so this is where the region is added.
135
//
136
// Adding it here rather than in some later sweep is what keeps the
137
// ordering right: ECMA-335 requires regions be listed innermost
138
// first, and a region nested inside another closes before it does.
139
// Nothing validates the order, and getting it wrong produces an
140
// assembly that loads and then runs the wrong handler, so the
141
// ordering wants to fall out of the structure rather than be
142
// arranged separately.
143
class HANDLER_END: Value is
144
_region: PROTECTED_REGION
145
146
init(region: PROTECTED_REGION) is
147
super.init()
148
149
_region = region
150
si
151
152
gen(context: IR.CONTEXT) is
153
let body = context.current_srm_body_emitter!
154
_region.handler_end = body.mark_region_boundary()
155
156
if _region.is_catch then
157
let token =
158
if let catch_type = _region.catch_type then
159
context.resolve_type_token(catch_type)
160
else
161
(
162
let named = _region.catch_type_name!
163
164
context.resolve_type_token_by_name(
165
named.assembly, named.`namespace, named.name)
166
)
167
fi
168
169
body.add_catch_region(
170
_region.extent.start,
171
_region.extent.end,
172
_region.handler_start,
173
_region.handler_end,
174
token)
175
else
176
body.add_finally_region(
177
_region.extent.start,
178
_region.extent.end,
179
_region.handler_start,
180
_region.handler_end)
181
fi
182
si
183
184
to_string() -> string => "}} // handler"
185
si
186
si