Skip to content
← Back

src/syntax/trees/definitions/variables/variable.ghul

1
// FIXME: correct this namespace:
2
namespace Syntax.Trees.Variables is
3
4
use Source;
5
6
use Ghul.Pipes;
7
8
class VARIABLE: Trees.Definitions.Definition, ScopeCarrier is
9
scope: Semantic.Scope? public;
10
11
left: VariableLeft;
12
// Null on a destructure-pattern variable — only a SIMPLE_VARIABLE_LEFT
13
// has a single name. Callers that work only on simple variables can
14
// check `is_simple_name` first; callers that need to iterate every
15
// bound identifier should use `names`.
16
name: Identifiers.Identifier? => left.name;
17
18
// every concrete VariableLeft subclass overrides names to non-null
19
names: Collections.Iterator[Identifiers.Identifier] => left.names!;
20
21
type_expression: TypeExpressions.TypeExpression;
22
initializer: Expressions.Expression?;
23
is_static: bool;
24
is_explicit_type: bool;
25
is_variable: bool => true;
26
want_dispose: bool;
27
is_mutable_marked: bool;
28
// Set on the binding of an `if let` arm so the compile pass can
29
// treat the initializer's optionality as already-checked: a
30
// refutable destructure unwraps `T?` to `T` before resolving
31
// element members.
32
is_refutable: bool;
33
// Set on every formal-argument VARIABLE. A formal argument's
34
// initializer is its declared default value (consumed by
35
// callers), not code to run at function entry.
36
is_argument: bool;
37
// Set on a VARIABLE that represents the `..` splice marker in
38
// a secondary `init` formal-argument list. Carries only its
39
// location; the rewrite pass expands it into the surrounding
40
// class's primary parameters before any downstream phase
41
// observes it.
42
is_splice: bool;
43
44
// Set on a variant field VARIABLE inserted by expanding a `..`
45
// splice against the enclosing union's primary-constructor
46
// parameters. The variant's synthesised init forwards these
47
// names to super.init(...) and skips the self.<field>=
48
// assignment the union base already performs.
49
is_inherited_primary: bool;
50
51
// Populated only for primary-ctor parameters. Carries the
52
// trailing modifier suffixes (`public` / `field` / `init`) that
53
// describe the auto-generated body field/property the rewrite
54
// pass will synthesise for this parameter. Null in every other
55
// variable-parsing context.
56
modifiers: Modifiers.LIST? public;
57
58
// Attribute pragmas (`@Foo() name: T`) written directly before a
59
// formal-argument VARIABLE — only ever populated when the parser
60
// is inside a function/method parameter list (see
61
// CONTEXT.in_formal_arguments); null everywhere else.
62
pragmas: Collections.LIST[Pragmas.PRAGMA]? public;
63
64
init(
65
location: LOCATION,
66
left: VariableLeft,
67
type_expression: TypeExpressions.TypeExpression,
68
is_static: bool,
69
is_explicit_type: bool,
70
initializer: Expressions.Expression?
71
) is
72
super.init(location);
73
74
75
self.left = left;
76
self.type_expression = type_expression;
77
self.is_static = is_static;
78
self.is_explicit_type = is_explicit_type;
79
self.initializer = initializer;
80
si
81
82
init(
83
location: LOCATION,
84
name: Identifiers.Identifier,
85
type_expression: TypeExpressions.TypeExpression,
86
is_static: bool,
87
is_explicit_type: bool,
88
initializer: Expressions.Expression?
89
) is
90
init(
91
location,
92
SIMPLE_VARIABLE_LEFT(location, name),
93
type_expression,
94
is_static,
95
is_explicit_type,
96
initializer
97
);
98
si
99
100
set_type_expression(type_expression: TypeExpressions.TypeExpression) is
101
self.type_expression = type_expression;
102
si
103
104
mark_want_dispose() is
105
want_dispose = true;
106
si
107
108
mark_mutable() is
109
is_mutable_marked = true;
110
si
111
112
mark_refutable() is
113
is_refutable = true;
114
si
115
116
mark_argument() is
117
is_argument = true;
118
si
119
120
mark_splice() is
121
is_splice = true;
122
si
123
124
mark_inherited_primary() is
125
is_inherited_primary = true;
126
si
127
128
set_modifiers(modifiers: Modifiers.LIST) is
129
self.modifiers = modifiers;
130
si
131
132
set_pragmas(pragmas: Collections.LIST[Pragmas.PRAGMA]) is
133
self.pragmas = pragmas;
134
si
135
136
copy() -> VARIABLE is
137
assert initializer == null else "cannot copy a variable node with non null initializer";
138
139
let result =
140
VARIABLE(
141
location,
142
left.copy(),
143
type_expression.copy(),
144
is_static,
145
is_explicit_type,
146
null
147
);
148
149
if let self_pragmas = pragmas then
150
result.set_pragmas(self_pragmas);
151
fi
152
153
return result;
154
si
155
156
accept(visitor: Visitor) is
157
visitor.visit(self);
158
si
159
160
walk(visitor: Visitor) is
161
// Inherited-primary entries in a variant's field list
162
// exist purely to feed init synthesis (the variant's
163
// init forwards them to super.init). The union base
164
// owns the storage and visits all the symbol-side
165
// processing (declare_symbols, resolve types, etc.)
166
// through the union's own field declarations. Walking
167
// them at the variant level would double-process the
168
// same name and trip "set type twice" / shadow checks.
169
if is_inherited_primary then
170
return;
171
fi
172
if !visitor.pre(self) then
173
if pragmas? then
174
for pragma in pragmas do
175
pragma.walk(visitor);
176
od
177
fi
178
left.walk(visitor);
179
type_expression.walk(visitor);
180
if initializer? then
181
initializer.walk(visitor);
182
fi
183
fi
184
accept(visitor);
185
si
186
si
187
188
class VariableLeft: Trees.Node is
189
is_simple_name: bool => false;
190
name: Identifiers.Identifier? => null;
191
names: Collections.Iterator[Identifiers.Identifier]? => null;
192
elements: Collections.List[VariableLeft]? => null;
193
194
// Per-element type ascription. Allowed on any element of a
195
// destructure pattern, at any nesting depth. In an ordinary
196
// `let`, this is a static type assertion on the bound slot;
197
// in an `if let` arm (parent VARIABLE.is_refutable), it is
198
// additionally a runtime narrowing test on that element.
199
type_expression: TypeExpressions.TypeExpression?;
200
201
// Set on every element of a by-name destructure group:
202
// `(local = field, …) = source` records `field` here so the
203
// resolver pulls `source.field` rather than the positional
204
// slot. Null on positional-group elements. The parser
205
// enforces all-or-nothing per `(...)` group; mixing is a
206
// parse error.
207
source_field_name: Identifiers.Identifier? public;
208
209
set_source_field_name(name: Identifiers.Identifier) is
210
self.source_field_name = name;
211
si
212
213
// Compile-expressions output for this node lives in the pass's
214
// own VARIABLE_LEFT_STATE_STORE, keyed by this node, not here.
215
216
// Propagated from the parent VARIABLE for `if let` arms.
217
is_refutable: bool public;
218
219
// Propagated from the parent VARIABLE when it's a formal
220
// argument. A destructured formal argument has no initializer
221
// to derive a value from - the leaves' types are assigned
222
// directly from the parameter's aggregate type by resolve-
223
// explicit-types, and generate-il sources the unpack from the
224
// synthesised parameter symbol rather than a walked value - so
225
// compile-expressions' usual initializer-driven handling of a
226
// destructure pattern doesn't apply and skips this subtree.
227
is_argument_left: bool public;
228
229
init(location: LOCATION) is
230
super.init(location);
231
si
232
233
set_type_expression(type_expression: TypeExpressions.TypeExpression) is
234
self.type_expression = type_expression;
235
si
236
237
// Propagate `is_refutable` to every leaf of a destructure tree
238
// so a `LITERAL_VARIABLE_LEFT` nested inside a tuple destructure
239
// (`if let (1, y) = pair`) knows it sits in a refutable
240
// context and is not a silent no-op.
241
mark_refutable_recursive() is
242
is_refutable = true;
243
si
244
245
// Propagate `is_argument_left` to every leaf, same shape as
246
// mark_refutable_recursive above.
247
mark_argument_recursive() is
248
is_argument_left = true;
249
si
250
251
// True when this node, or any nested destructure group at any
252
// depth, is a by-name group (source_field_name set on its own
253
// first element - the parser enforces all-or-nothing per
254
// group, so checking the first element is enough for that
255
// group). Used to reject named destructuring anywhere in a
256
// formal-argument pattern, not just at its outermost level.
257
has_named_group: bool => false;
258
259
get_names_into(into: Collections.MutableList[Identifiers.Identifier]);
260
261
copy() -> VariableLeft;
262
263
copy_base_values_from(other: VariableLeft) is
264
if let other_type_expression = other.type_expression then
265
type_expression = other_type_expression.copy();
266
fi
267
268
if let other_source_field_name = other.source_field_name then
269
source_field_name = other_source_field_name.copy();
270
fi
271
si
272
si
273
274
class SIMPLE_VARIABLE_LEFT: VariableLeft is
275
name: Identifiers.Identifier;
276
is_simple_name: bool => true;
277
278
elements: Collections.List[VariableLeft] => System.Array.empty`[VariableLeft]();
279
names: Collections.Iterator[Identifiers.Identifier] => [name].iterator;
280
281
init(
282
location: LOCATION,
283
name: Identifiers.Identifier
284
) is
285
super.init(location);
286
287
self.name = name;
288
si
289
290
get_names_into(into: Collections.MutableList[Identifiers.Identifier]) is
291
into.add(name);
292
si
293
294
accept(visitor: Visitor) is
295
visitor.visit(self);
296
si
297
298
walk(visitor: Visitor) is
299
if !visitor.pre(self) then
300
name.walk(visitor);
301
302
if let self.type_expression? then
303
type_expression.walk(visitor);
304
fi
305
fi
306
307
accept(visitor);
308
si
309
310
copy() -> VariableLeft is
311
let result = SIMPLE_VARIABLE_LEFT(location, name);
312
result.copy_base_values_from(self);
313
return result;
314
si
315
si
316
317
// A literal / `null` / enum-member leaf inside a destructure
318
// pattern. Has no binding name — at runtime, the source's
319
// corresponding element is value-equality tested against the
320
// wrapped expression, and the arm only matches when the test
321
// succeeds. Visible only on the LHS of refutable bindings
322
// (`if let` / `case`-when patterns); a plain `let` never has
323
// a refutable element.
324
class LITERAL_VARIABLE_LEFT: VariableLeft is
325
expression: Expressions.Expression;
326
327
is_simple_name: bool => false;
328
elements: Collections.List[VariableLeft] => System.Array.empty`[VariableLeft]();
329
names: Collections.Iterator[Identifiers.Identifier] => System.Array.empty`[Identifiers.Identifier]().iterator;
330
331
init(location: LOCATION, expression: Expressions.Expression) is
332
super.init(location);
333
334
self.expression = expression;
335
si
336
337
get_names_into(into: Collections.MutableList[Identifiers.Identifier]) is
338
si
339
340
accept(visitor: Visitor) is
341
visitor.visit(self);
342
si
343
344
walk(visitor: Visitor) is
345
if !visitor.pre(self) then
346
expression.walk(visitor);
347
fi
348
349
accept(visitor);
350
si
351
352
copy() -> VariableLeft is
353
let result = LITERAL_VARIABLE_LEFT(location, expression);
354
result.copy_base_values_from(self);
355
return result;
356
si
357
si
358
359
class DESTRUCTURING_VARIABLE_LEFT: VariableLeft is
360
elements: Collections.List[VariableLeft];
361
362
names: Collections.Iterator[Identifiers.Identifier] => _flatten_names();
363
364
_flatten_names() -> Ghul.Pipes.Pipe[Identifiers.Identifier] is
365
for element in elements do
366
let element_names = element.names;
367
368
if element_names? then
369
for n in element_names do
370
yield n;
371
od
372
fi
373
od
374
si
375
376
get_names_into(into: Collections.MutableList[Identifiers.Identifier]) is
377
for e in elements do
378
e.get_names_into(into);
379
od
380
si
381
382
mark_refutable_recursive() is
383
is_refutable = true;
384
for e in elements do
385
e.mark_refutable_recursive();
386
od
387
si
388
389
mark_argument_recursive() is
390
is_argument_left = true;
391
for e in elements do
392
e.mark_argument_recursive();
393
od
394
si
395
396
has_named_group: bool =>
397
(elements.count > 0 /\ elements[0].source_field_name?) \/
398
elements |> any(e => e.has_named_group);
399
400
init(location: LOCATION, elements: Collections.List[VariableLeft]) is
401
super.init(location);
402
403
404
self.elements = elements;
405
si
406
407
accept(visitor: Visitor) is
408
visitor.visit(self);
409
si
410
411
walk(visitor: Visitor) is
412
if !visitor.pre(self) then
413
for e in elements do
414
e.walk(visitor);
415
od
416
417
if let self.type_expression? then
418
type_expression.walk(visitor);
419
fi
420
fi
421
accept(visitor);
422
si
423
424
copy() -> VariableLeft is
425
let new_elements = Collections.LIST[VariableLeft](elements.count);
426
427
for e in elements do
428
new_elements.add(e.copy());
429
od
430
431
let result = DESTRUCTURING_VARIABLE_LEFT(location, new_elements);
432
result.copy_base_values_from(self);
433
return result;
434
si
435
si
436
si