I'm trying to implement the Monkey toy language in Rust. I'm now trying to generate and AST, but before that, I need to have a functioning parser. I already have my lexer.
So the relevant part of my parser looks like this:
struct Parser<'a> {
lexer: lexer::Lexer<'a>,
current_token: Token<'a>,
peek_token: Token<'a>,
}
impl<'a> Parser<'a> {
// Create a new parser.
// Depends on a lexer capable of iterating over
// the tokens.
pub fn new(mut lexer: lexer::Lexer<'a>) -> Parser {
// constructor
}
// Read the next token.
//
// Returns self to avoid weird `move out of
// borrowed content` issue?
fn next_token(mut self) -> Self {
self.current_token = self.peek_token;
self.peek_token = self.lexer.next_token();
self
}
}
The problem is in the next_token
function. I would really like it to work with a borrowed &self
, like this:
// Read the next token.
fn next_token(&mut self) {
self.current_token = self.peek_token;
self.peek_token = self.lexer.next_token();
}
But the compiler complaints about moving out of a borrowed content. Now, I understand why this is happening: I'm only borrowing self
, I cannot perform the move from self.peek_token
to self.current_token
because I do not own it.
My question though, is, is returning Self
the best strategy? The code which returns Self
works fine, but the interface just got very very ugly.
#[test]
fn test_next_token() {
let l = lexer::Lexer::new("let answer = 42;");
let p = Parser::new(l);
assert_eq!(p.current_token, Token::Let);
let p = p.next_token();
assert_eq!(p.current_token, Token::Ident("answer"));
}
Is there an alternative I'm not seeing? Is this a common idiom in Rust?
Here is a link to the playground.