Appearance
| 1 | namespace Syntax.Trees.Expressions is | |
| 2 | use Source | |
| 3 | ||
| 4 | use Logging | |
| 5 | ||
| 6 | class TUPLE: Expression is | |
| 7 | is_function_arguments: bool public | |
| 8 | ||
| 9 | // A single-element TUPLE node is a parenthesised expression, | |
| 10 | // not a 1-tuple — TUPLE.visit collapses its value to the inner | |
| 11 | // element. Reflect that here so callers driving tuple-shaped | |
| 12 | // LUB / inference (SEQUENCE elements, IF branches with | |
| 13 | // uniformly-tupled bodies) don't reach for a non-existent | |
| 14 | // tuple arity and ICE in get_tuple_type. The parentheses are | |
| 15 | // transparent: what they hold is a tuple literal when the inner | |
| 16 | // expression is one - a parenthesised `if` or block whose arms | |
| 17 | // or tail are tuple literals. | |
| 18 | is_tuple_literal: bool => | |
| 19 | if elements.expressions.count == 1 then | |
| 20 | elements.expressions[0].is_tuple_literal | |
| 21 | else | |
| 22 | true | |
| 23 | fi | |
| 24 | ||
| 25 | elements: LIST | |
| 26 | ||
| 27 | // Type ascription written after the closing paren, as in | |
| 28 | // `((a, b): (int, int)) => …`. Only ever parsed in a position | |
| 29 | // that could turn out to be a lambda parameter list, where it | |
| 30 | // declares the type of the one physical argument the pattern | |
| 31 | // unpacks. Null everywhere else; if the surrounding syntax | |
| 32 | // turns out not to be a lambda, `rewrite_as_expression` | |
| 33 | // reports it rather than dropping it. | |
| 34 | type_expression: TypeExpressions.TypeExpression? public | |
| 35 | ||
| 36 | could_be_formal_argument: bool => true | |
| 37 | ||
| 38 | set_type_expression(type_expression: TypeExpressions.TypeExpression) is | |
| 39 | self.type_expression = type_expression | |
| 40 | si | |
| 41 | ||
| 42 | try_copy_as_variable_left() -> Variables.VariableLeft? is | |
| 43 | let elements_left = Collections.LIST[Variables.VariableLeft]() | |
| 44 | ||
| 45 | for e in elements.expressions do | |
| 46 | let element_left = e.try_copy_as_variable_left() | |
| 47 | ||
| 48 | if !element_left? then | |
| 49 | return null | |
| 50 | fi | |
| 51 | ||
| 52 | elements_left.add(element_left) | |
| 53 | od | |
| 54 | ||
| 55 | return Variables.DESTRUCTURING_VARIABLE_LEFT(location, elements_left) | |
| 56 | si | |
| 57 | ||
| 58 | // A lambda parameter written as a parenthesised group is a | |
| 59 | // destructure pattern over one physical argument. The group's | |
| 60 | // own name is synthesised - declare-members renames it to a | |
| 61 | // unique slot, the same way it renames a `_` discard - since | |
| 62 | // the source only names the leaves. | |
| 63 | try_copy_as_variable() -> VARIABLE? is | |
| 64 | let left = try_copy_as_variable_left() | |
| 65 | ||
| 66 | if !left? then | |
| 67 | return null | |
| 68 | fi | |
| 69 | ||
| 70 | let result = | |
| 71 | VARIABLE( | |
| 72 | location, | |
| 73 | Identifiers.Identifier(location, "$destructured_argument"), | |
| 74 | type_expression ?? TypeExpressions.INFER(location), | |
| 75 | null | |
| 76 | ) | |
| 77 | ||
| 78 | result.mark_synthesized() | |
| 79 | result.set_left(left) | |
| 80 | ||
| 81 | return result | |
| 82 | si | |
| 83 | ||
| 84 | init(location: LOCATION, elements: LIST, is_function_arguments: bool) is | |
| 85 | super.init(location) | |
| 86 | ||
| 87 | self.elements = elements | |
| 88 | self.is_function_arguments = is_function_arguments | |
| 89 | si | |
| 90 | ||
| 91 | // A one-element group is a parenthesised expression rather than | |
| 92 | // a 1-tuple, so it stands for its element wherever a context | |
| 93 | // type is offered or asked for. Without this, parenthesising a | |
| 94 | // `cast(v)` hides that it is still waiting for a type and hands | |
| 95 | // it the surrounding context's instead. | |
| 96 | awaits_context_type: bool => | |
| 97 | elements.expressions.count == 1 /\ elements.expressions[0].awaits_context_type | |
| 98 | ||
| 99 | set_expected_type(expected_type: Semantic.Types.Type?, expected_type_error_message: string?) is | |
| 100 | compile_expressions_state.set_expected_type(expected_type, expected_type_error_message) | |
| 101 | ||
| 102 | if elements.expressions.count == 1 then | |
| 103 | elements.expressions[0].set_expected_type(expected_type, expected_type_error_message) | |
| 104 | fi | |
| 105 | si | |
| 106 | ||
| 107 | set_expects_pack(depth: int) is | |
| 108 | super.set_expects_pack(depth) | |
| 109 | ||
| 110 | if elements.expressions.count == 1 then | |
| 111 | elements.expressions[0].set_expects_pack(depth) | |
| 112 | fi | |
| 113 | si | |
| 114 | ||
| 115 | rewrite_as_assignment_left() -> AssignmentLeftExpression is | |
| 116 | if elements.expressions.count == 1 then | |
| 117 | return SIMPLE_LEFT_EXPRESSION(location, elements.expressions[0]) | |
| 118 | fi | |
| 119 | ||
| 120 | let result = Collections.LIST[AssignmentLeftExpression](elements.expressions.count) | |
| 121 | ||
| 122 | for element in elements.expressions do | |
| 123 | let expression = element.rewrite_as_expression() | |
| 124 | if element.is_tuple_literal then | |
| 125 | result.add(expression.rewrite_as_assignment_left()) | |
| 126 | else | |
| 127 | result.add(SIMPLE_LEFT_EXPRESSION(element.location, expression)) | |
| 128 | fi | |
| 129 | od | |
| 130 | ||
| 131 | return DESTRUCTURING_LEFT_EXPRESSION(location, result) | |
| 132 | si | |
| 133 | ||
| 134 | replace_element(index: int, value: Expression) is | |
| 135 | elements.replace_element(index, value) | |
| 136 | si | |
| 137 | ||
| 138 | accept(visitor: Visitor) is | |
| 139 | visitor.visit(self) | |
| 140 | si | |
| 141 | ||
| 142 | walk(visitor: Visitor) is | |
| 143 | if !visitor.pre(self) then | |
| 144 | elements.walk(visitor) | |
| 145 | fi | |
| 146 | ||
| 147 | accept(visitor) | |
| 148 | si | |
| 149 | si | |
| 150 | si |