Skip to content
← Back

src/syntax/process/declare-members/declare_members_bodies.ghul

1
namespace Syntax.Process is
2
use Logging
3
use Source
4
use Trees
5
6
// The body half of DECLARE_MEMBERS: the block scopes, locals,
7
// formal and destructured arguments, closures and lambda
8
// parameters declared inside function bodies. The class head,
9
// state and the type-level member handlers are in
10
// declare_members.ghul.
11
partial DECLARE_MEMBERS is
12
visit(variable: Variables.VARIABLE) is
13
// A destructured formal argument is one physical parameter
14
// at the aggregate (tuple) type, unpacked into its leaf
15
// names at method entry - not one parameter per leaf. The
16
// leaves are ordinary body-scoped locals, declared here
17
// even though we're inside the function's `_declaring_
18
// arguments` window, so declare_variable doesn't turn them
19
// into LOCAL_ARGUMENTs.
20
if variable.is_argument /\ !variable.left.is_simple_name then
21
let function = cast Semantic.Symbols.Function?(current_declaration_context)
22
23
// Declaring into the enclosing function's rejecting scope
24
// (see pre(FUNCTION) above) reaches here too, with no
25
// function symbol to open a declaring-arguments window
26
// against — there is nothing to distinguish an argument
27
// from any other local in a block scope, so the window
28
// toggle is simply skipped.
29
assert function? \/ isa Semantic.BLOCK_SCOPE(current_declaration_context) else "destructured formal argument declared outside a function scope"
30
31
let group_symbol =
32
current_declaration_context.declare_variable(
33
variable.location,
34
next_argument_group_name(),
35
variable.is_static,
36
_symbol_definition_listener
37
)
38
39
group_symbol.mark_synthesized()
40
41
associate_node_with_scope(variable, group_symbol)
42
43
if function? then
44
function.end_declaring_arguments()
45
fi
46
47
for name in variable.names do
48
let is_discard = name.name =~ "_"
49
50
if is_discard then
51
name.name = next_discard_name()
52
fi
53
54
let declared_leaf = current_declaration_context.declare_variable(name.location, name.name, variable.is_static, _symbol_definition_listener)
55
56
if is_discard then
57
declared_leaf.mark_synthesized()
58
fi
59
od
60
61
if function? then
62
function.start_declaring_arguments()
63
fi
64
65
if variable.pragmas? then
66
_logger.error(variable.location, "attribute is not allowed on a destructured parameter")
67
fi
68
69
return
70
fi
71
72
let declared_symbol: Semantic.Symbols.Symbol? mut = null
73
74
for name in variable.names do
75
76
let is_discard = name.name =~ "_"
77
78
if is_discard then
79
name.name = next_discard_name()
80
fi
81
82
// A top-level `let` is declared into the file's namespace
83
// as a static field on the globals container rather than
84
// as a local of the synthesised entry, so sibling global
85
// functions can read it. The namespace is always found
86
// here: the entry only exists inside a file's root
87
// namespace.
88
let `namespace =
89
if variable.is_top_level then
90
_symbol_table.current_namespace_symbol
91
else
92
null
93
fi
94
95
let declared =
96
if `namespace? then
97
`namespace.declare_top_level_variable(name.location, name.name, _symbol_definition_listener)
98
else
99
current_declaration_context.declare_variable(name.location, name.name, variable.is_static, _symbol_definition_listener)
100
fi
101
102
if variable.is_synthesized \/ is_discard then
103
declared.mark_synthesized()
104
fi
105
106
if variable.is_mutable_marked then
107
if let v: Semantic.Symbols.Variable = declared then
108
v.is_mutable_marked = true
109
fi
110
fi
111
112
declared_symbol = declared
113
od
114
115
// Only a formal-argument VARIABLE can carry attribute
116
// pragmas (parsed only inside CONTEXT.in_formal_arguments);
117
// associate it with its declared symbol so compile-expressions
118
// and generate-il can find it again via symbol_for. A
119
// destructured parameter declares more than one name, so
120
// there is no single symbol an attribute could sensibly
121
// attach to.
122
if variable.pragmas? then
123
if declared_symbol? /\ variable.left.is_simple_name then
124
associate_node_with_scope(variable, declared_symbol)
125
else
126
_logger.error(variable.location, "attribute is not allowed on a destructured parameter")
127
fi
128
fi
129
130
// A nested named function's own name. The local is declared
131
// here, after the literal it initializes has been walked, so
132
// the closure is told which local names it now - references to
133
// the name from inside the body are compiled later, and read
134
// the function from its recurse field rather than from a local
135
// that is still empty there.
136
if let literal = cast Expressions.FUNCTION?(variable.initializer) then
137
if literal.nested_name? then
138
if let local: Semantic.Symbols.LOCAL_VARIABLE = declared_symbol then
139
local.is_nested_function = true
140
fi
141
142
if let closure: Semantic.Symbols.Closure = symbol_for(literal) then
143
closure.self_reference_variable = cast Semantic.Symbols.Variable?(declared_symbol)
144
fi
145
fi
146
fi
147
si
148
149
// Controlled walk: per clause, walk the clause's pieces and
150
// THEN declare its pattern names — so later clauses'
151
// scrutinees see earlier clauses' bindings during
152
// name-resolution. Mirrors what plain `let a = …; let b = …;`
153
// gets for free across separate statements (visit(VARIABLE) on
154
// the first runs before the second is walked).
155
pre(rb: Statements.REFUTABLE_BINDING) -> bool is
156
for c in rb.clauses do
157
if let c.narrow_type_expression? then
158
narrow_type_expression.walk(self)
159
fi
160
161
c.scrutinee.walk(self)
162
c.pattern.walk(self)
163
164
if let c.guard? then
165
guard.walk(self)
166
fi
167
168
for name in c.pattern.names! do
169
let is_discard = name.name =~ "_"
170
171
if is_discard then
172
name.name = next_discard_name()
173
fi
174
175
let declared = current_declaration_context.declare_variable(
176
name.location,
177
name.name,
178
false,
179
_symbol_definition_listener
180
)
181
182
if is_discard then
183
declared.mark_synthesized()
184
fi
185
od
186
od
187
188
return true
189
si
190
191
visit(rb: Statements.REFUTABLE_BINDING) is
192
si
193
194
visit(variable: Expressions.VARIABLE) is
195
si
196
197
pre(if_branch: Statements.IF_BRANCH) -> bool is
198
create_and_enter_block_scope(if_branch)
199
return false
200
si
201
202
visit(if_branch: Statements.IF_BRANCH) is
203
leave_scope(if_branch)
204
si
205
206
pre(`case: Statements.CASE) -> bool is
207
create_and_enter_block_scope(`case)
208
return false
209
si
210
211
visit(`case: Statements.CASE) is
212
leave_scope(`case)
213
si
214
215
pre(case_match: Statements.CASE_MATCH) -> bool is
216
create_and_enter_block_scope(case_match)
217
return false
218
si
219
220
visit(case_match: Statements.CASE_MATCH) is
221
leave_scope(case_match)
222
si
223
224
pre(`try: Statements.TRY) -> bool is
225
create_and_enter_block_scope(`try)
226
return false
227
si
228
229
visit(`try: Statements.TRY) is
230
leave_scope(`try)
231
si
232
233
pre(`catch: Statements.CATCH) -> bool is
234
create_and_enter_block_scope(`catch)
235
return false
236
si
237
238
visit(`catch: Statements.CATCH) is
239
leave_scope(`catch)
240
si
241
242
pre(`do: Statements.DO) -> bool is
243
create_and_enter_block_scope(`do)
244
_declare_pending_loop_label()
245
return false
246
si
247
248
visit(`do: Statements.DO) is
249
leave_scope(`do)
250
si
251
252
pre(`for: Statements.FOR) -> bool is
253
create_and_enter_block_scope(`for)
254
_declare_pending_loop_label()
255
return false
256
si
257
258
visit(`for: Statements.FOR) is
259
leave_scope(`for)
260
si
261
262
// A label names its loop's body, so it declares into the body
263
// scope the wrapped loop creates — visible inside (and under
264
// nested loops), gone once the loop ends, and sibling loops may
265
// reuse a name. The parser only wraps loops in LABELLED.
266
pre(labelled: Statements.LABELLED) -> bool is
267
_pending_labels.add(labelled.label)
268
return false
269
si
270
271
visit(labelled: Statements.LABELLED) is
272
si
273
274
_declare_pending_loop_label() is
275
if _pending_labels.count > 0 then
276
let label = _pending_labels[_pending_labels.count - 1]
277
_pending_labels.remove_at(_pending_labels.count - 1)
278
279
current_declaration_context.declare_label(label.location, label.name, _symbol_definition_listener)
280
fi
281
si
282
283
pre(variable: Expressions.VARIABLE) -> bool is
284
let is_discard = variable.name.name =~ "_"
285
286
if is_discard then
287
variable.name.name = next_discard_name()
288
fi
289
290
// A destructured lambda parameter is one physical argument
291
// under a synthesised name, unpacked into its leaves at
292
// entry - the same shape declare-members gives a
293
// destructured formal argument of a named function. The
294
// leaves are ordinary body locals, so they are declared
295
// outside the function's declaring-arguments window.
296
if let variable.left? then
297
variable.name.name = next_argument_group_name()
298
299
current_declaration_context.declare_variable(variable.name.location, variable.name.name, false, _symbol_definition_listener)
300
.mark_synthesized()
301
302
let function = cast Semantic.Symbols.Function?(current_declaration_context)
303
304
if function? then
305
function.end_declaring_arguments()
306
fi
307
308
for name in left.names! do
309
let leaf_is_discard = name.name =~ "_"
310
311
if leaf_is_discard then
312
name.name = next_discard_name()
313
fi
314
315
let declared_leaf = current_declaration_context.declare_variable(name.location, name.name, false, _symbol_definition_listener)
316
317
if leaf_is_discard then
318
declared_leaf.mark_synthesized()
319
fi
320
od
321
322
if function? then
323
function.start_declaring_arguments()
324
fi
325
326
return false
327
fi
328
329
let declared = current_declaration_context.declare_variable(variable.name.location, variable.name.name, false, _symbol_definition_listener)
330
331
if is_discard \/ variable.is_synthesized then
332
declared.mark_synthesized()
333
fi
334
335
return false
336
si
337
338
pre(function: Expressions.FUNCTION) -> bool is
339
// A lambda whose body contains `await` (not inside another
340
// nested lambda) is classified as `*_ASYNC_CLOSURE` so
341
// `async_state_machine_for` picks it up for state-machine
342
// IL emission. `contains_let_await` and `is_void_async`
343
// are propagated to the AST node so compile-lambdas can
344
// settle the inferred return type to `Tasks.TASK` /
345
// `Tasks.TASK[T]` shape.
346
let await_scanner = AWAIT_SCANNER()
347
if !function.body.is_null then
348
await_scanner.scan(function.body)
349
fi
350
351
let body_has_await = await_scanner.found
352
function.contains_let_await = body_has_await
353
function.is_void_async = body_has_await /\ !await_scanner.found_value_return
354
355
// A nested named function reaches itself by its own name, so
356
// whether it recurses is a fact about the body rather than
357
// something the source marked, and it has to be settled before
358
// the closure is built.
359
if let name = function.nested_name then
360
if NAME_REFERENCE_SCANNER().body_references(function.body, name.name) then
361
function.mark_recursive()
362
fi
363
fi
364
365
// a lambda expression always sits inside a function
366
let current_function = self.current_function!
367
368
let closure_symbol: Semantic.Symbols.Symbol mut
369
370
if body_has_await then
371
closure_symbol = current_function.declare_async_closure(
372
function.location,
373
next_anon_name(),
374
// FIXME:
375
cast Semantic.Scope?(current_closure_context)!,
376
current_scope,
377
function.is_recursive,
378
_symbol_definition_listener
379
)
380
else
381
closure_symbol = current_function.declare_closure(
382
function.location,
383
next_anon_name(),
384
// FIXME:
385
cast Semantic.Scope?(current_closure_context)!,
386
current_scope,
387
function.is_recursive,
388
_symbol_definition_listener
389
)
390
fi
391
392
closure_symbol.mark_synthesized()
393
394
associate_and_enter_scope(
395
function,
396
closure_symbol
397
)
398
399
return true
400
si
401
402
visit(function: Expressions.FUNCTION) is
403
let symbol = symbol_for(function)
404
405
if symbol? /\ isa Semantic.Symbols.Function(symbol) then
406
let function_symbol = symbol
407
408
let arguments = function.arguments.expressions
409
410
// we don't know if identifier expressions in a tuple are actually untyped
411
// anonymous function formal arguments until we know the context, so re-write
412
// them now to be variables:
413
for index in 0..arguments.count do
414
let a mut = arguments[index]
415
416
if isa Trees.Expressions.IDENTIFIER(a) then
417
let infer = Trees.TypeExpressions.INFER(a.location)
418
419
a = Trees.Expressions.VARIABLE(a.location, cast Syntax.Trees.Expressions.IDENTIFIER(a).identifier, infer, null)
420
421
arguments[index] = a
422
elif isa Trees.Expressions.DEFAULT(a) /\ a.could_be_formal_argument then
423
// A bare `_` formal (`_ => ...`) is parsed as a
424
// default-value expression and re-written here to
425
// an untyped discard parameter. Multi-arg and
426
// destructure formals reach this via
427
// rewrite_as_variables instead.
428
a = Trees.Expressions.VARIABLE(
429
a.location,
430
Trees.Identifiers.Identifier(a.location, "_"),
431
Trees.TypeExpressions.INFER(a.location),
432
null
433
)
434
435
arguments[index] = a
436
fi
437
od
438
439
function_symbol.start_declaring_arguments()
440
441
function.arguments.walk(self)
442
443
function_symbol.end_declaring_arguments()
444
fi
445
446
function.body.walk(self)
447
448
leave_scope(function)
449
si
450
451
pre(let_in: Expressions.LET_IN) -> bool is
452
create_and_enter_block_scope(let_in)
453
return false
454
si
455
456
visit(let_in: Expressions.LET_IN) is
457
leave_scope(let_in)
458
si
459
460
pre(expression: Bodies.EXPRESSION) -> bool is
461
create_and_enter_block_scope(expression)
462
return false
463
si
464
465
visit(expression: Bodies.EXPRESSION) is
466
leave_scope(expression)
467
si
468
469
pre(block: Bodies.BLOCK) -> bool is
470
create_and_enter_block_scope(block)
471
return false
472
si
473
474
visit(block: Bodies.BLOCK) is
475
leave_scope(block)
476
si
477
si
478
si