Fix parsing of empty switch

This commit is contained in:
Nicolas Abril 2024-05-16 13:47:28 +02:00
parent 530f8d777f
commit 08480c40e1
5 changed files with 50 additions and 43 deletions

View File

@ -451,7 +451,39 @@ impl<'a> TermParser<'a> {
// Switch
if self.try_parse_keyword("switch") {
unexpected_tag(self)?;
return self.parse_switch();
let (bnd, arg, with) = self.parse_match_header()?;
self.consume("{")?;
self.try_consume("|");
self.consume("0")?;
self.consume(":")?;
let zero = self.parse_term()?;
self.try_consume(";");
let mut arms = vec![zero];
let mut expected_num = 1;
loop {
self.try_consume("|");
// case _
if self.try_consume("_") {
self.consume(":")?;
arms.push(self.parse_term()?);
self.try_consume(";");
self.consume("}")?;
break;
}
// case num
let val = self.parse_u32()?;
if val != expected_num {
return self.expected(&format!("'{}'", &expected_num.to_string()));
}
expected_num += 1;
self.consume(":")?;
arms.push(self.parse_term()?);
self.try_consume(";");
}
let pred = Some(Name::new(format!("{}-{}", bnd.as_ref().unwrap(), arms.len() - 1)));
return Ok(Term::Swt { arg: Box::new(arg), bnd, with, pred, arms });
}
// Do (monadic block)
@ -612,44 +644,6 @@ impl<'a> TermParser<'a> {
let bod = self.parse_term()?;
Ok((nam, vec![], bod))
}
fn parse_switch(&mut self) -> ParseResult<Term> {
let (bnd, arg, with) = self.parse_match_header()?;
self.consume("{")?;
let mut expected_num = 0;
let mut arms = vec![];
let mut to_continue = true;
self.skip_trivia();
while to_continue && !self.starts_with("}") {
self.try_consume("|");
self.skip_trivia();
let Some(head) = self.peek_one() else { return self.expected("switch pattern") };
match head {
'_' => {
if expected_num == 0 {
return self.expected("0");
} else {
self.consume("_")?;
to_continue = false;
}
}
c if c.is_ascii_digit() => {
let val = self.parse_u32()?;
if val != expected_num {
return self.expected(&expected_num.to_string());
}
}
_ => return self.expected("switch pattern"),
};
self.consume(":")?;
arms.push(self.parse_term()?);
self.try_consume(";");
expected_num += 1;
}
let pred = Some(Name::new(format!("{}-{}", bnd.as_ref().unwrap(), arms.len() - 1)));
self.consume("}")?;
Ok(Term::Swt { arg: Box::new(arg), bnd, with, pred, arms })
}
}
impl<'a> Parser<'a> for TermParser<'a> {

View File

@ -594,9 +594,11 @@ impl<'a> PyParser<'a> {
indent.enter_level();
self.consume_indent_exactly(*indent)?;
let ini_idx = *self.index();
let (fst_case, fst_stmt, mut nxt_indent) = self.parse_switch_case(indent)?;
let end_idx = *self.index();
if fst_case != Some(0) {
return self.expected("case 0");
return self.expected_spanned("case 0", ini_idx, end_idx);
}
let mut arms = vec![fst_stmt];
let mut should_continue = fst_case == Some(0);
@ -640,10 +642,10 @@ impl<'a> PyParser<'a> {
None
}
c if c.is_ascii_digit() => Some(self.parse_u32()?),
_ => return self.expected("Number pattern"),
_ => return self.expected("number or '_'"),
}
} else {
return self.expected("Switch pattern")?;
return self.expected("number or '_'")?;
};
self.advance_trivia_inline();

View File

@ -0,0 +1,2 @@
# This should be interpreted as a switch with a SUP argument that is missing its elements.
main = switch {}

View File

@ -4,6 +4,6 @@ input_file: tests/golden_tests/compile_file/switch_all_patterns.bend
---
Errors:
In tests/golden_tests/compile_file/switch_all_patterns.bend :
- expected: 0
- expected: '0'
- detected:
 7 | _: x-1

View File

@ -0,0 +1,9 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file/switch_incomplete.bend
---
Errors:
In tests/golden_tests/compile_file/switch_incomplete.bend :
- expected: term
- detected:
 2 | main = switch {}