From 0a8a493bad84304673044bda6b337867bf556363 Mon Sep 17 00:00:00 2001 From: Nick Krichevsky Date: Tue, 21 May 2024 15:35:41 -0400 Subject: [PATCH] Make match_token_kind! macro preserve the token in case of error --- src/parse.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index c4e50ae..5060c11 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -43,15 +43,20 @@ pub fn parse_program, 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>(iter: &mut I) { } fn parse_statement>(iter: &mut Peekable) -> Result { - 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, F: Fn(Expr) iter: &mut Peekable, make_statement: F, ) -> Result { - // 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>(iter: &mut Peekable) -> Result { @@ -146,7 +145,7 @@ fn parse_binary, F: Fn(&mut Peekable) -> Result>(iter: &mut Peekable) -> Result { - 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>(iter: &mut Peekable) -> Result