Make match_token_kind! macro preserve the token in case of error
parent
d497e19564
commit
0a8a493bad
31
src/parse.rs
31
src/parse.rs
|
@ -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),
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue