Appearance
| 1 | namespace Syntax.Parsers.Expressions is | |
| 2 | use IO.Std; | |
| 3 | ||
| 4 | use Source; | |
| 5 | ||
| 6 | use Ghul.Pipes; | |
| 7 | ||
| 8 | class TUPLE( | |
| 9 | expression_list_parser: Parser[Trees.Expressions.LIST], | |
| 10 | type_parser: Parser[Trees.TypeExpressions.TypeExpression] | |
| 11 | ): Base[Trees.Expressions.TUPLE] is | |
| 12 | description: string => "tuple"; | |
| 13 | ||
| 14 | super(); | |
| 15 | ||
| 16 | parse(context: CONTEXT) -> Trees.Expressions.TUPLE is | |
| 17 | let start = context.location; | |
| 18 | ||
| 19 | // Parsing the elements runs the enclosing list loop again, | |
| 20 | // which clears `allow_tuple_element`, so capture here | |
| 21 | // whether this group is itself in a position that could be | |
| 22 | // a lambda's formal parameter. | |
| 23 | let could_be_formal_argument = context.allow_tuple_element; | |
| 24 | ||
| 25 | context.next_token(Lexical.TOKEN.PAREN_OPEN, syntax_error_message); | |
| 26 | ||
| 27 | let expressions: Trees.Expressions.LIST mut; | |
| 28 | ||
| 29 | if context.current.token != Lexical.TOKEN.PAREN_CLOSE then | |
| 30 | expressions = expression_list_parser.parse(context)!; | |
| 31 | else | |
| 32 | expressions = Trees.Expressions.LIST(context.location, Collections.LIST[Trees.Expressions.Expression]()); | |
| 33 | fi | |
| 34 | ||
| 35 | expressions.rewrite_as_tuple_elements(); | |
| 36 | ||
| 37 | context.next_token(Lexical.TOKEN.PAREN_CLOSE, syntax_error_message); | |
| 38 | ||
| 39 | let end mut = context.location; | |
| 40 | ||
| 41 | // `(a, b): T` - a type ascription on a parenthesised group. | |
| 42 | // Only meaningful where the group could be a lambda's | |
| 43 | // formal parameter, which is exactly where | |
| 44 | // `allow_tuple_element` is set, so restrict it to there and | |
| 45 | // leave the `:` for the caller to report anywhere else. A | |
| 46 | // group destructures anything positionally, not just a | |
| 47 | // tuple, so the ascription takes the full type syntax. | |
| 48 | let type_expression: Trees.TypeExpressions.TypeExpression? mut = null; | |
| 49 | ||
| 50 | // ... and only when every element could be a pattern | |
| 51 | // element. `(1, 2): T` cannot be a parameter however it is | |
| 52 | // used, so leave its `:` to be reported where it always | |
| 53 | // was rather than consuming it and dropping the type. | |
| 54 | let could_be_pattern = | |
| 55 | expressions.expressions.count > 1 /\ | |
| 56 | expressions.expressions |> all(e => e.try_copy_as_variable_left()?); | |
| 57 | ||
| 58 | if | |
| 59 | could_be_formal_argument /\ | |
| 60 | could_be_pattern /\ | |
| 61 | context.current.token == Lexical.TOKEN.COLON | |
| 62 | then | |
| 63 | context.next_token(); | |
| 64 | ||
| 65 | type_expression = type_parser.parse(context)!; | |
| 66 | end = type_expression.location; | |
| 67 | fi | |
| 68 | ||
| 69 | let result = Trees.Expressions.TUPLE(start::end, expressions, false); | |
| 70 | ||
| 71 | if type_expression? then | |
| 72 | result.set_type_expression(type_expression); | |
| 73 | fi | |
| 74 | ||
| 75 | return result; | |
| 76 | si | |
| 77 | si | |
| 78 | si |