Skip to content

Commit 5ae27cc

Browse files
committed
xparser: Allow inner blocks to not end with a semicolon
1 parent 8a9b548 commit 5ae27cc

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

xparser/src/constructs.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn many_exprs(mut input: ParseInput) -> ParseResult<ParseInput, Vec<Ast>> {
5858
if input.is_empty() {
5959
return Ok((input, exprs));
6060
}
61-
let (new_input, expr) = expr_semicolon(input)?;
61+
let (new_input, expr) = expr_maybe_semi(input)?;
6262
input = new_input;
6363
exprs.push(expr);
6464
}
@@ -67,13 +67,25 @@ pub fn many_exprs(mut input: ParseInput) -> ParseResult<ParseInput, Vec<Ast>> {
6767
/// Parse an instruction and maybe the semicolon that follows.
6868
///
6969
/// expr_semicolon = expr [ ';' ]
70-
pub fn expr_semicolon(input: ParseInput) -> ParseResult<ParseInput, Ast> {
70+
pub fn expr_maybe_semi(input: ParseInput) -> ParseResult<ParseInput, Ast> {
7171
let (input, expr) = expr(input)?;
72+
let input = next(input);
7273
let (input, _) = opt(tokens::semicolon)(input)?;
7374

7475
Ok((input, expr))
7576
}
7677

78+
/// Parse an instruction and the semicolon that follows.
79+
///
80+
/// expr_semicolon = expr [ ';' ]
81+
pub fn expr_semicolon(input: ParseInput) -> ParseResult<ParseInput, Ast> {
82+
let (input, expr) = expr(input)?;
83+
let input = next(input);
84+
let (input, _) = tokens::semicolon(input)?;
85+
86+
Ok((input, expr))
87+
}
88+
7789
// expr = cmp ( '<' cmp | '>' cmp | '<=' cmp | '>=' cmp | '==' cmp | '!=' cmp)*
7890
pub fn expr(input: ParseInput) -> ParseResult<ParseInput, Ast> {
7991
let input = next(input);
@@ -748,6 +760,7 @@ pub fn block(input: ParseInput) -> ParseResult<ParseInput, Ast> {
748760
}
749761

750762
let stmt = |input| {
763+
let input = next(input);
751764
let (input, start_loc) = position(input)?;
752765

753766
if let Ok((input, _)) = tokens::if_tok(input) {
@@ -760,16 +773,15 @@ pub fn block(input: ParseInput) -> ParseResult<ParseInput, Ast> {
760773
// we don't update `input` here so that we can just call `block`
761774
block(input)
762775
} else {
763-
let (input, expr) = expr(input)?;
764-
let input = next(input);
765-
let (input, _) = tokens::semicolon(input)?;
766-
767-
Ok((input, expr))
776+
expr_semicolon(input)
768777
}
769778
};
770779

771780
let (input, stmts) = opt(many1(stmt))(input)?;
772781
let (input, last_expr) = opt(expr)(input)?;
782+
let input = next(input);
783+
let (input, _) = tokens::right_curly_bracket(input)?;
784+
773785
let last_is_expr = last_expr.is_some();
774786

775787
let (input, end_loc) = position(input)?;
@@ -2303,4 +2315,18 @@ mod tests {
23032315

23042316
assert!(expr(input).is_ok());
23052317
}
2318+
2319+
#[test]
2320+
fn block_in_block_does_not_require_extra_semicolon_395() {
2321+
let input = span!("func foo() { if true { 15 } else { 14 } }");
2322+
2323+
assert!(expr(input).is_ok());
2324+
}
2325+
2326+
#[test]
2327+
fn block_in_block_does_not_require_extra_semicolon_395_2() {
2328+
let input = span!("func foo() { { { where x = 14; } } }");
2329+
2330+
assert!(expr(input).is_ok());
2331+
}
23062332
}

0 commit comments

Comments
 (0)