Appearance
| 1 | namespace Syntax.Process is | |
| 2 | use Source; | |
| 3 | use Logging; | |
| 4 | use Trees; | |
| 5 | ||
| 6 | // Synthesises a global entry point from a file's top-level statements. | |
| 7 | // | |
| 8 | // A file with no namespace may carry bare statements at file scope. The | |
| 9 | // parser collects them, in source order, onto the root definition list; | |
| 10 | // this rewriter wraps them into a global function named after the | |
| 11 | // configured entry point, so every downstream phase sees an ordinary | |
| 12 | // function. Runs before expand_namespaces, which then wraps the | |
| 13 | // synthesised function into the file's root namespace alongside any other | |
| 14 | // global definitions. | |
| 15 | // | |
| 16 | // Top-level statements and namespaces are mutually exclusive in a file: | |
| 17 | // a file that carries both is a compile error and no entry is synthesised. | |
| 18 | class SYNTHESISE_TOP_LEVEL_ENTRY(_ir_context: IR.CONTEXT, _logger: Logger) is | |
| 19 | apply(node: Node) is | |
| 20 | if !isa Definitions.LIST(node) then | |
| 21 | return; | |
| 22 | fi | |
| 23 | ||
| 24 | let list = cast Definitions.LIST(node); | |
| 25 | let statements = list.top_level_statements; | |
| 26 | ||
| 27 | if !statements? then | |
| 28 | return; | |
| 29 | fi | |
| 30 | ||
| 31 | list.top_level_statements = null; | |
| 32 | ||
| 33 | for definition in list do | |
| 34 | if isa Definitions.NAMESPACE(definition) then | |
| 35 | _logger.error( | |
| 36 | statements.location, | |
| 37 | "top-level statements cannot appear in a file with a namespace" | |
| 38 | ); | |
| 39 | ||
| 40 | return; | |
| 41 | fi | |
| 42 | od | |
| 43 | ||
| 44 | list.add(_synthesise_entry(statements)); | |
| 45 | si | |
| 46 | ||
| 47 | _synthesise_entry(statements: Statements.LIST) -> Definitions.FUNCTION => | |
| 48 | let location = statements.location in | |
| 49 | Definitions.FUNCTION( | |
| 50 | location, | |
| 51 | // The entry has no declaration the source names, so its | |
| 52 | // identifier carries an internal location: a name at the | |
| 53 | // statement span would record a hover use covering the whole | |
| 54 | // region, and any hover on a non-symbol position there would | |
| 55 | // report the synthesised entry. | |
| 56 | Identifiers.Identifier(LOCATION.internal, _ir_context.entry_point_name), | |
| 57 | TypeExpressions.LIST(location, Collections.LIST[TypeExpressions.TypeExpression](0)), | |
| 58 | Variables.LIST(location, Collections.LIST[Variables.VARIABLE](0)), | |
| 59 | TypeExpressions.INFER(location), | |
| 60 | Modifiers.LIST(location, null, null), | |
| 61 | Bodies.BLOCK(location, statements) | |
| 62 | ); | |
| 63 | si | |
| 64 | si |