Appearance
| 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 |