I just started with Rust, and I might have some confusion surrounding what I can and cannot do. Excuse me for maybe asking the same question as someone else on this forum, I did a fair bit of searching but it was either the issue with keywords I was using, or the fact that the form of the question didn't quite match mine.
I'm implementing a parser, and somewhere inside the traits of my code I have this utility function for reducing an expression:
fn match_reduce<E, F>(&mut self, set: T, i: E, mut f: F) -> E
where
F: FnMut(E, Self::Item) -> E
{
let mut res = i;
while let Some(item) = self.match_pop(set) {
res = f(res, item)
}
res
}
This declaration is, as far as I understand from the lack of compiler messages, is completely fine. However, an issue rises when I try to use it to parse a right-associative expression:
let lhs = self.parse_expr_op(level - 1);
self.lexer.match_reduce(li.tokens, lhs, |lhs, tok| {
let op = find_op_by_token(li, tok);
Box::new(match li.arity {
Arity::Binary => Node::BinaryExpr(op, lhs, self.parse_expr_op(level)),
Arity::Unary => Node::UnaryExpr(op, lhs),
})
})
This code has a double mutable borrow. First time, when calling self.lexer.match_reduce
. The second time we borrow when calling self.parse_expr_op
. Both functions modify the internal state of the lexer. Since the reduce
borrows lexer as mutable and calls the closure, which again borrows lexer as mutable (through .lexer
field of the parser), we have two mutable borrows at the same time.
I know that I can rewrite this code such that it uses a simple while loop, and in fact, it actually becomes 1 line shorter. That's probably the best solution anyway. However as I'm new to Rust, I'm curious if there's a secret Jutsu to use here that would allow me to use the reduce abstraction.
I'm open to all kinds of advice. Thanks in advance.