From 6c6a262c4238c4fce8f5afdfadb18ce6c68d4d90 Mon Sep 17 00:00:00 2001 From: Akuli Date: Wed, 15 Jan 2025 15:42:00 +0200 Subject: [PATCH] Allow parentheses in match cases --- bootstrap_compiler/parse.c | 9 ++++++++- compiler/parser.jou | 13 +++++++++++-- tests/should_succeed/match.jou | 10 ++++++++++ tests/syntax_error/match_bad_case_parens.jou | 9 +++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/syntax_error/match_bad_case_parens.jou diff --git a/bootstrap_compiler/parse.c b/bootstrap_compiler/parse.c index 8cb8f794..45786347 100644 --- a/bootstrap_compiler/parse.c +++ b/bootstrap_compiler/parse.c @@ -722,13 +722,20 @@ static AstMatchStatement parse_match_statement(ParserState *ps) ps->tokens++; result.case_underscore = parse_body(ps); } else { + bool parens = is_operator(ps->tokens, "("); + if (parens) + ps->tokens++; List(AstExpression) case_objs = {0}; while(1){ Append(&case_objs, parse_expression(ps)); if (is_operator(ps->tokens, "|")) ps->tokens++; - else if (is_operator(ps->tokens, ":")) + else if (!parens && is_operator(ps->tokens, ":")) + break; + else if (parens && is_operator(ps->tokens, ")") && is_operator(&ps->tokens[1], ":")) { + ps->tokens++; break; + } else fail_with_parse_error(ps->tokens, "'|' or ':'"); } diff --git a/compiler/parser.jou b/compiler/parser.jou index 67ada548..22b99646 100644 --- a/compiler/parser.jou +++ b/compiler/parser.jou @@ -884,6 +884,9 @@ class Parser: assert result.case_underscore != NULL *result.case_underscore = self->parse_body() else: + parens = self->tokens->is_operator("(") + if parens: + self->tokens++ case_objs: AstExpression* = NULL n_case_objs = 0 while True: @@ -891,10 +894,16 @@ class Parser: case_objs[n_case_objs++] = self->parse_expression() if self->tokens->is_operator("|"): self->tokens++ - elif self->tokens->is_operator(":"): + elif (not parens) and self->tokens->is_operator(":"): + break + elif parens and self->tokens->is_operator(")") and self->tokens[1].is_operator(":"): + self->tokens++ # skip ')' break else: - self->tokens->fail_expected_got("'|' or ':'") + if parens: + self->tokens->fail_expected_got("'|' or '):'") + else: + self->tokens->fail_expected_got("'|' or ':'") result.cases = realloc(result.cases, sizeof result.cases[0] * (result.ncases + 1)) result.cases[result.ncases++] = AstCase{ case_objs = case_objs, diff --git a/tests/should_succeed/match.jou b/tests/should_succeed/match.jou index 29309412..29c4ee34 100644 --- a/tests/should_succeed/match.jou +++ b/tests/should_succeed/match.jou @@ -34,6 +34,16 @@ def main() -> int: case _: printf("nope\n") + match Foo.Baz: + # This syntax is useful if you have many values in the same case. + case ( + Foo.Bar + | Foo.Baz + ): + printf("yay\n") # Output: yay + case _: + printf("nope\n") + f = 69 as Foo match f: case Foo.Bar: diff --git a/tests/syntax_error/match_bad_case_parens.jou b/tests/syntax_error/match_bad_case_parens.jou new file mode 100644 index 00000000..292abb63 --- /dev/null +++ b/tests/syntax_error/match_bad_case_parens.jou @@ -0,0 +1,9 @@ +enum Foo: + One + Two + Three + +def blah(f: Foo) -> None: + match f: + case (Foo.One Foo.Two): # Error: expected '|' or '):', got a variable name 'Foo' + printf("hi\n")