Reputation: 1012
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.
Upvotes: 1
Views: 467
Reputation: 68
Is there a particular reason you only want to reference lexed strings to the source? It seems like you are progressing chars anyway and throwing the returned owned object when you bump while "eating". A more idiomatic way would be just to use those owned values with something like:
fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) -> String {
let mut string = String::new();
while predicate(self.first()) {
write!(string, "{}", self.bump().unwrap());
}
string
}
Upvotes: 1