Make match_token_kind! macro preserve the token in case of error

master
Nick Krichevsky 2024-05-21 15:35:41 -04:00
parent d497e19564
commit 0a8a493bad
1 changed files with 15 additions and 16 deletions

View File

@ -43,15 +43,20 @@ pub fn parse_program<I: Iterator<Item = Token>, F: FnMut(ScriptError)>(
macro_rules! match_token_kind {
($tokens_peekable: expr, $($p:pat),+) => {{
match $tokens_peekable.peek().map(|token| token.kind()) {
let peeked = $tokens_peekable.peek();
match peeked.map(|token| token.kind()) {
$(
Some($p) => {
// consume the peeked token
let token = $tokens_peekable.next().unwrap();
Some(token)
Ok(token)
}
)+
_ => None
Some(_kind) => {
// this must be valid, because peeked.map will only give None if this is None.
Err(Some(peeked.unwrap()))
},
_ => Err(None)
}
}};
}
@ -66,7 +71,7 @@ fn synchronize_to_next_statement<I: Iterator<Item = Token>>(iter: &mut I) {
}
fn parse_statement<I: Iterator<Item = Token>>(iter: &mut Peekable<I>) -> Result<Stmt, ParseError> {
if match_token_kind!(iter, TokenKind::Print).is_some() {
if match_token_kind!(iter, TokenKind::Print).is_ok() {
parse_statement_containing_expression(iter, |expression| Stmt::Print { expression })
} else {
parse_statement_containing_expression(iter, |expression| Stmt::Expression { expression })
@ -77,19 +82,13 @@ fn parse_statement_containing_expression<I: Iterator<Item = Token>, F: Fn(Expr)
iter: &mut Peekable<I>,
make_statement: F,
) -> Result<Stmt, ParseError> {
// Snatch the next token before we parse it, so we have line information
let next_token_line = iter.peek().map(Token::line);
let expression = parse_expression(iter)?;
if match_token_kind!(iter, TokenKind::SemiColon).is_some() {
Ok(make_statement(expression))
} else {
Err(ParseError {
match_token_kind!(iter, TokenKind::SemiColon)
.map(|_semicolon| make_statement(expression))
.map_err(|maybe_token| ParseError {
message: "Expected a ';' after expression".to_string(),
// this should always be valid, as the token must have existed if we successfully
// parsed some expression (there are no zero-token expressions)
line: Some(next_token_line.unwrap()),
line: maybe_token.map(Token::line),
})
}
}
fn parse_expression<I: Iterator<Item = Token>>(iter: &mut Peekable<I>) -> Result<Expr, ParseError> {
@ -146,7 +145,7 @@ fn parse_binary<I: Iterator<Item = Token>, F: Fn(&mut Peekable<I>) -> Result<Exp
}
fn parse_unary<I: Iterator<Item = Token>>(iter: &mut Peekable<I>) -> Result<Expr, ParseError> {
if let Some(token) = match_token_kind!(iter, TokenKind::Bang, TokenKind::Minus) {
if let Ok(token) = match_token_kind!(iter, TokenKind::Bang, TokenKind::Minus) {
let operator = token;
let right = parse_unary(iter)?;
Ok(Expr::Unary {
@ -193,7 +192,7 @@ fn parse_primary<I: Iterator<Item = Token>>(iter: &mut Peekable<I>) -> Result<Ex
// consume the left paren
iter.next();
let expr = parse_expression(iter)?;
if match_token_kind!(iter, TokenKind::RightParen).is_some() {
if match_token_kind!(iter, TokenKind::RightParen).is_ok() {
Ok(Expr::Grouping {
expr: Box::new(expr),
})