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 {
|
macro_rules! match_token_kind {
|
||||||
($tokens_peekable: expr, $($p:pat),+) => {{
|
($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) => {
|
Some($p) => {
|
||||||
// consume the peeked token
|
// consume the peeked token
|
||||||
let token = $tokens_peekable.next().unwrap();
|
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> {
|
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 })
|
parse_statement_containing_expression(iter, |expression| Stmt::Print { expression })
|
||||||
} else {
|
} else {
|
||||||
parse_statement_containing_expression(iter, |expression| Stmt::Expression { expression })
|
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>,
|
iter: &mut Peekable<I>,
|
||||||
make_statement: F,
|
make_statement: F,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> 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)?;
|
let expression = parse_expression(iter)?;
|
||||||
if match_token_kind!(iter, TokenKind::SemiColon).is_some() {
|
match_token_kind!(iter, TokenKind::SemiColon)
|
||||||
Ok(make_statement(expression))
|
.map(|_semicolon| make_statement(expression))
|
||||||
} else {
|
.map_err(|maybe_token| ParseError {
|
||||||
Err(ParseError {
|
|
||||||
message: "Expected a ';' after expression".to_string(),
|
message: "Expected a ';' after expression".to_string(),
|
||||||
// this should always be valid, as the token must have existed if we successfully
|
line: maybe_token.map(Token::line),
|
||||||
// parsed some expression (there are no zero-token expressions)
|
|
||||||
line: Some(next_token_line.unwrap()),
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expression<I: Iterator<Item = Token>>(iter: &mut Peekable<I>) -> Result<Expr, ParseError> {
|
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> {
|
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 operator = token;
|
||||||
let right = parse_unary(iter)?;
|
let right = parse_unary(iter)?;
|
||||||
Ok(Expr::Unary {
|
Ok(Expr::Unary {
|
||||||
|
@ -193,7 +192,7 @@ fn parse_primary<I: Iterator<Item = Token>>(iter: &mut Peekable<I>) -> Result<Ex
|
||||||
// consume the left paren
|
// consume the left paren
|
||||||
iter.next();
|
iter.next();
|
||||||
let expr = parse_expression(iter)?;
|
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 {
|
Ok(Expr::Grouping {
|
||||||
expr: Box::new(expr),
|
expr: Box::new(expr),
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue