How should I solve this problem where I end up making a mutable borrow followed by an immutable borrow.
Using clone() or adding different scope is not working still getting a compile error.
I have added the complete code in the playground below: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f576dd99feec48c86e5ef4e986aefa17
Code:
use std::str::Chars;
pub(crate) struct Cursor<'a> {
source: &'a str,
cursor_pos: usize,
chars: Chars<'a>,
}
pub(crate) const EOF_CHAR: char = '\0';
impl<'a> Cursor<'a> {
pub(crate) fn new(input: &'a str) -> Cursor<'a> {
Cursor {
source: input,
cursor_pos: 0,
chars: input.chars(),
}
}
fn nth_char(&self, n: usize) -> char {
self.chars().nth(n).unwrap_or(EOF_CHAR)
}
pub(crate) fn first(&self) -> char {
self.nth_char(0)
}
fn chars(&self) -> Chars<'a> {
self.chars.clone()
}
pub(crate) fn bump(&mut self) -> Option<char> {
let c = self.chars.next()?;
self.cursor_pos += 1;
Some(c)
}
pub(crate) fn cursor_pos(&self) -> usize {
self.cursor_pos
}
pub(crate) fn substring(&self, start_pos: usize, end_pos: usize) -> &str {
&self.source[start_pos .. end_pos]
}
}
#[derive(Debug)]
pub enum TokenType<'a> {
Equal,
StringLiteral { value: &'a str },
Unexpected,
}
#[derive(Debug)]
pub struct Token<'a> {
token_type: TokenType<'a>,
lexeme: &'a str,
start_pos: usize,
size: usize,
}
impl<'a> Token<'a> {
pub fn new(token_type: TokenType<'a>, lexeme: &'a str, start_pos: usize, size: usize) -> Token<'a> {
Token { token_type, lexeme, start_pos, size }
}
}
impl Cursor<'_> {
fn advance_token(&mut self) -> Token {
let start_pos = self.cursor_pos();
let c = self.bump().unwrap();
let token_type = match c {
'=' => TokenType::Equal,
'"' => self.string(),
_ => TokenType::Unexpected,
};
let end_pos = self.cursor_pos(); // comment this to remove compile-error
// let end_pos = self.cursor_pos().cloned(); // comment this to remove compile-error
// let end_pos = 10; // uncomment this to run successfully
let size = end_pos - start_pos;
let lexeme = "a"; // self.substring(start_pos, end_pos);
Token::new(token_type, lexeme, start_pos, size)
}
fn string(&mut self) -> TokenType {
let start_pos = self.cursor_pos();
self.eat_while(|c| c != '"');
let end_pos = self.cursor_pos();
TokenType::StringLiteral { value: self.substring(start_pos, end_pos) }
}
fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
while predicate(self.first()) {
self.bump();
}
}
}
fn main() {
let source = "a = \"123\"";
let mut lexer = Cursor::new(source);
let tok = lexer.advance_token();
println!("{:?}", tok);
let tok = lexer.advance_token();
println!("{:?}", tok);
let tok = lexer.advance_token();
println!("{:?}", tok);
let tok = lexer.advance_token();
println!("{:?}", tok);
let tok = lexer.advance_token();
println!("{:?}", tok);
}
Error:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/main.rs:81:23
|
70 | fn advance_token(&mut self) -> Token {
| - let's call the lifetime of this reference `'1`
...
77 | '"' => self.string(),
| ---- mutable borrow occurs here
...
81 | let end_pos = self.cursor_pos(); // comment this to remove compile-error
| ^^^^ immutable borrow occurs here
...
88 | Token::new(token_type, lexeme, start_pos, size)
| ----------------------------------------------- returning this value requires that `*self` is borrowed for `'1`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground`
To learn more, run the command again with --verbose.