Compare commits
1 Commits
1107c7d93d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| cde0ff5582 |
@@ -234,6 +234,15 @@ pub enum StatementKind<P: Phase> {
|
||||
value: Option<Expression<P>>,
|
||||
},
|
||||
|
||||
/// A braced block of statements, e.g. `{ let x = 1; f(x); }`.
|
||||
///
|
||||
/// Compound statements introduce a new scope and can appear anywhere a
|
||||
/// statement is expected.
|
||||
Compound {
|
||||
/// The statements contained within the block, in source order.
|
||||
inner: Vec<Statement<P>>,
|
||||
},
|
||||
|
||||
/// A bare expression statement, e.g. `f(x);`.
|
||||
///
|
||||
/// The trailing `;` is not stored in the node but is included in
|
||||
|
||||
@@ -34,5 +34,10 @@ fn main() {
|
||||
Ok(ast) => println!("{ast:#?}"),
|
||||
Err(diag) => diag.report(file, &content),
|
||||
}
|
||||
|
||||
parser
|
||||
.errors
|
||||
.into_iter()
|
||||
.for_each(|diag| diag.report(file, &content));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ pub struct Parser<'src> {
|
||||
/// Diagnostics accumulated during parsing. Non-fatal errors are pushed here
|
||||
/// so that the parser can attempt to continue and surface multiple issues
|
||||
/// in a single pass.
|
||||
errors: Vec<Diagnostic>,
|
||||
pub errors: Vec<Diagnostic>,
|
||||
}
|
||||
|
||||
impl<'src> Parser<'src> {
|
||||
@@ -110,12 +110,14 @@ impl<'src> Parser<'src> {
|
||||
/// Dispatches to the appropriate specialised parser based on the leading
|
||||
/// token:
|
||||
/// - `let` → [`parse_let_statement`](Self::parse_let_statement)
|
||||
/// - `{` → [`parse_compound_statement`](Self::parse_compound_statement)
|
||||
/// - anything else → an expression followed by a mandatory `;`
|
||||
pub fn parse_statement(&mut self) -> Result<ast::ParsedStatement, Diagnostic> {
|
||||
let peek = self.peek_no_eof()?;
|
||||
|
||||
match peek.kind {
|
||||
TokenKind::KwLet => self.parse_let_statement(),
|
||||
TokenKind::LCurly => self.parse_compound_statement(),
|
||||
|
||||
_ => {
|
||||
let expr = self.parse_expression(0)?;
|
||||
@@ -171,6 +173,36 @@ impl<'src> Parser<'src> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a braced block of statements: `{ <stmt>* }`.
|
||||
///
|
||||
/// Each inner statement is parsed with [`parse_statement`](Self::parse_statement).
|
||||
/// If a statement fails, the diagnostic is pushed onto [`errors`](Parser::errors)
|
||||
/// and [`synchronize`](Self::synchronize) is called so that parsing can
|
||||
/// continue with the next statement. The block span runs from `{` to `}`.
|
||||
fn parse_compound_statement(&mut self) -> Result<ast::ParsedStatement, Diagnostic> {
|
||||
let lcurly_token = self.expect(TokenKind::LCurly)?;
|
||||
let mut inner = Vec::new();
|
||||
|
||||
while !self.is_at_eof() && !self.is_peek(TokenKind::RCurly) {
|
||||
match self.parse_statement() {
|
||||
Ok(stmt) => inner.push(stmt),
|
||||
Err(diag) => {
|
||||
self.errors.push(diag);
|
||||
self.synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let rcurly_token = self.expect(TokenKind::RCurly)?;
|
||||
let span = lcurly_token.span.extend(rcurly_token.span);
|
||||
|
||||
Ok(ast::ParsedStatement {
|
||||
kind: ast::StatementKind::Compound { inner },
|
||||
span,
|
||||
extra: (),
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a type annotation, e.g. `u8`, `i64`, `bool`, or a user-defined
|
||||
/// named type.
|
||||
///
|
||||
@@ -193,7 +225,11 @@ impl<'src> Parser<'src> {
|
||||
|
||||
TokenKind::Identifier => ast::TypeKind::Named(peek.text.to_string()),
|
||||
|
||||
_ => return Err(Diagnostic::new(Severity::Error, "expected a type")),
|
||||
_ => {
|
||||
return Err(
|
||||
Diagnostic::new(Severity::Error, "expected a type").with_span(peek.span)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let span = self.advance().span;
|
||||
|
||||
Reference in New Issue
Block a user