Skip to content

Commit d48babe

Browse files
giacomocavalierilpil
authored andcommitted
parse blocks in case guards
1 parent 66d97b8 commit d48babe

File tree

6 files changed

+200
-29
lines changed

6 files changed

+200
-29
lines changed

compiler-core/src/format/tests.rs

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4653,26 +4653,15 @@ fn do_not_remove_required_braces_case_guard() {
46534653
}
46544654

46554655
#[test]
4656-
fn remove_braces_case_guard() {
4657-
assert_format_rewrite!(
4658-
"fn main() {
4659-
let is_enabled = False
4660-
let is_confirmed = False
4661-
let is_admin = True
4662-
case is_enabled, is_confirmed, is_admin {
4663-
is_enabled, is_confirmed, is_admin if { is_enabled && is_confirmed } || is_admin ->
4664-
Nil
4665-
_, _, _ -> Nil
4666-
}
4667-
}
4668-
",
4656+
fn do_not_remove_braces_from_case_guard() {
4657+
assert_format!(
46694658
"fn main() {
46704659
let is_enabled = False
46714660
let is_confirmed = False
46724661
let is_admin = True
46734662
case is_enabled, is_confirmed, is_admin {
46744663
is_enabled, is_confirmed, is_admin
4675-
if is_enabled && is_confirmed || is_admin
4664+
if { is_enabled && is_confirmed } || is_admin
46764665
-> Nil
46774666
_, _, _ -> Nil
46784667
}
@@ -4682,23 +4671,15 @@ fn remove_braces_case_guard() {
46824671
}
46834672

46844673
#[test]
4685-
fn remove_braces_case_guard_2() {
4686-
assert_format_rewrite!(
4674+
fn do_not_remove_braces_from_case_guard_2() {
4675+
assert_format!(
46874676
"fn main() {
46884677
let wibble = #(10, [0])
46894678
case wibble {
46904679
wibble if True && { wibble.0 == 10 } -> Nil
46914680
_ -> Nil
46924681
}
46934682
}
4694-
",
4695-
"fn main() {
4696-
let wibble = #(10, [0])
4697-
case wibble {
4698-
wibble if True && wibble.0 == 10 -> Nil
4699-
_ -> Nil
4700-
}
4701-
}
47024683
"
47034684
);
47044685
}

compiler-core/src/parse.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,12 +1809,9 @@ where
18091809
}
18101810
}
18111811

1812-
Some((_, Token::LeftBrace, _)) => {
1813-
// Nested guard expression
1812+
Some((start, Token::LeftBrace, _)) => {
18141813
self.advance();
1815-
let guard = self.parse_clause_guard_inner();
1816-
let _ = self.expect_one(&Token::RightBrace)?;
1817-
guard
1814+
Ok(Some(self.parse_case_clause_guard_block(start)?))
18181815
}
18191816

18201817
t0 => {
@@ -1830,6 +1827,31 @@ where
18301827
}
18311828
}
18321829

1830+
fn parse_case_clause_guard_block(
1831+
&mut self,
1832+
start: u32,
1833+
) -> Result<UntypedClauseGuard, ParseError> {
1834+
let body = self.parse_clause_guard_inner()?;
1835+
1836+
let Some(body) = body else {
1837+
let location = match self.next_tok() {
1838+
Some((_, Token::RightBrace, end)) => SrcSpan { start, end },
1839+
Some((_, _, _)) | None => SrcSpan {
1840+
start,
1841+
end: start + 1,
1842+
},
1843+
};
1844+
1845+
return parse_error(ParseErrorType::EmptyGuardBlock, location);
1846+
};
1847+
1848+
let (_, end) = self.expect_one(&Token::RightBrace)?;
1849+
Ok(ClauseGuard::Block {
1850+
location: SrcSpan { start, end },
1851+
value: Box::new(body),
1852+
})
1853+
}
1854+
18331855
fn parse_record_in_clause_guard(
18341856
&mut self,
18351857
module: &EcoString,

compiler-core/src/parse/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ pub enum ParseErrorType {
112112
module: EcoString,
113113
item: EcoString,
114114
},
115+
/// This can happen when there's an empty block in a case clause guard.
116+
/// For example: `_ if a == {}`
117+
EmptyGuardBlock,
115118
}
116119

117120
pub(crate) struct ParseErrorDetails {
@@ -627,6 +630,13 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u
627630
label_text: "I was expecting either `/` or `.{` here.".into(),
628631
extra_labels: vec![],
629632
},
633+
634+
ParseErrorType::EmptyGuardBlock => ParseErrorDetails {
635+
text: "".into(),
636+
hint: None,
637+
label_text: "A clause guard block cannot be empty".into(),
638+
extra_labels: vec![],
639+
},
630640
}
631641
}
632642
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "case 1 {\n _ if a || {} -> 1\n}"
4+
---
5+
----- SOURCE CODE
6+
case 1 {
7+
_ if a || {} -> 1
8+
}
9+
10+
----- ERROR
11+
error: Syntax error
12+
┌─ /src/parse/error.gleam:2:13
13+
14+
2_ if a || {} -> 1
15+
^^ A clause guard block cannot be empty
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "case 1 {\n _ if { 1 || { 1 || 1 } } || 1 -> 1\n}"
4+
---
5+
[
6+
Expression(
7+
Case {
8+
location: SrcSpan {
9+
start: 0,
10+
end: 48,
11+
},
12+
subjects: [
13+
Int {
14+
location: SrcSpan {
15+
start: 5,
16+
end: 6,
17+
},
18+
value: "1",
19+
int_value: 1,
20+
},
21+
],
22+
clauses: Some(
23+
[
24+
Clause {
25+
location: SrcSpan {
26+
start: 11,
27+
end: 46,
28+
},
29+
pattern: [
30+
Discard {
31+
name: "_",
32+
location: SrcSpan {
33+
start: 11,
34+
end: 12,
35+
},
36+
type_: (),
37+
},
38+
],
39+
alternative_patterns: [],
40+
guard: Some(
41+
Or {
42+
location: SrcSpan {
43+
start: 16,
44+
end: 40,
45+
},
46+
left: Block {
47+
location: SrcSpan {
48+
start: 16,
49+
end: 35,
50+
},
51+
value: Or {
52+
location: SrcSpan {
53+
start: 18,
54+
end: 33,
55+
},
56+
left: Constant(
57+
Int {
58+
location: SrcSpan {
59+
start: 18,
60+
end: 19,
61+
},
62+
value: "1",
63+
int_value: 1,
64+
},
65+
),
66+
right: Block {
67+
location: SrcSpan {
68+
start: 23,
69+
end: 33,
70+
},
71+
value: Or {
72+
location: SrcSpan {
73+
start: 25,
74+
end: 31,
75+
},
76+
left: Constant(
77+
Int {
78+
location: SrcSpan {
79+
start: 25,
80+
end: 26,
81+
},
82+
value: "1",
83+
int_value: 1,
84+
},
85+
),
86+
right: Constant(
87+
Int {
88+
location: SrcSpan {
89+
start: 30,
90+
end: 31,
91+
},
92+
value: "1",
93+
int_value: 1,
94+
},
95+
),
96+
},
97+
},
98+
},
99+
},
100+
right: Constant(
101+
Int {
102+
location: SrcSpan {
103+
start: 39,
104+
end: 40,
105+
},
106+
value: "1",
107+
int_value: 1,
108+
},
109+
),
110+
},
111+
),
112+
then: Int {
113+
location: SrcSpan {
114+
start: 45,
115+
end: 46,
116+
},
117+
value: "1",
118+
int_value: 1,
119+
},
120+
},
121+
],
122+
),
123+
},
124+
),
125+
]

compiler-core/src/parse/tests.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,3 +1912,21 @@ fn correct_precedence_in_pattern_size() {
19121912
fn private_opaque_type_is_parsed() {
19131913
assert_parse_module!("opaque type Wibble { Wobble }");
19141914
}
1915+
1916+
#[test]
1917+
fn case_guard_with_nested_blocks() {
1918+
assert_parse!(
1919+
"case 1 {
1920+
_ if { 1 || { 1 || 1 } } || 1 -> 1
1921+
}"
1922+
);
1923+
}
1924+
1925+
#[test]
1926+
fn case_guard_with_empty_block() {
1927+
assert_error!(
1928+
"case 1 {
1929+
_ if a || {} -> 1
1930+
}"
1931+
);
1932+
}

0 commit comments

Comments
 (0)