I have the following file in my interpreter for a personal programming language. The program itself is meant to take the output of the parser and convert it into an active parse tree.
use crate::errors::{ActiveParserError, FileLocation};
use crate::parser::{Term, Type};
use std::collections::HashMap;
pub enum ActiveParse {
File { active_terms: Vec<ActiveParse> },
Function {},
Class {},
VarDeclation,
VarUpdate,
Return,
UpdateVar,
If,
Loop,
ReadLn,
Break,
Continue,
Call,
}
struct VarRegistry<'a> {
tree_connection: VarRegistryTreeConnection<'a>,
object: HashMap<u32, ObjectOption<'a>>,
}
impl<'a> VarRegistry<'a> {
fn new() -> Self {
Self {
tree_connection: VarRegistryTreeConnection::Base { uid_counter: 0 },
object: HashMap::new(),
}
}
fn create_child(&'a mut self) -> Self {
Self {
tree_connection: VarRegistryTreeConnection::Child { parent: self },
object: HashMap::new(),
}
}
fn add_var(&mut self, name: String, _type: Type) {
todo!()
}
fn add_typevar(&mut self, name: String) {
todo!()
}
fn uid(&mut self) -> u32 {
match &mut self.tree_connection {
VarRegistryTreeConnection::Child { parent } => return parent.uid(),
VarRegistryTreeConnection::Base { uid_counter } => {
*uid_counter += 1;
return *uid_counter;
}
}
}
}
enum ObjectOption<'a> {
Var {
var_type: String,
name: String,
},
TypeVar {
requirements: Vec<ObjectOption<'a>>,
},
Class {
parent: Option<&'a ObjectOption<'a>>,
},
Func {
type_args: Vec<String>,
args: Vec<String>,
return_type: FuncReturnTypeOption,
name: String,
},
}
enum VarRegistryTreeConnection<'a> {
Child { parent: &'a mut VarRegistry<'a> },
Base { uid_counter: u32 },
}
enum FuncReturnTypeOption {
TypeArg(u32),
Static(u32),
}
fn activeate_func_parse<'a>(
func_term: Term,
var_registry: &'a mut VarRegistry<'a>,
) -> Result<ActiveParse, ActiveParserError> {
if let Term::Func {
name,
returntype,
typeargs,
args,
block,
} = func_term
{
let mut var_registry = var_registry.create_child();
for arg in args {
var_registry.add_var(arg.identity, arg.argtype)
}
for typearg in typeargs {
var_registry.add_typevar(typearg)
}
todo!()
} else {
Err(ActiveParserError(
"Expected function term".to_string(),
FileLocation::None,
))
}
}
fn activate_file_block(file_block: Term) -> Result<ActiveParse, ActiveParserError> {
let mut var_registry = VarRegistry::new();
let active_terms = Vec::<ActiveParse>::new();
if let Term::Block { terms } = file_block {
for term in terms {
{
let out = match term {
Term::Func { .. } => activeate_func_parse(term, &mut var_registry),
Term::Class { .. } => todo!(),
_ => todo!(),
};
}
}
Ok(ActiveParse::File { active_terms })
} else {
Err(ActiveParserError(
"Expected block as wrapper parse object".to_string(),
FileLocation::None,
))
}
}
pub fn activate_parse(program: Term) -> Result<ActiveParse, ActiveParserError> {
activate_file_block(program)
}
The program fails to pass the barrow checker with the following error:
error[E0499]: cannot borrow `var_registry` as mutable more than once at a time
--> src/avtive_parser/mod.rs:127:69
|
127 | Term::Func { .. } => activeate_func_parse(term, &mut var_registry),
| ^^^^^^^^^^^^^^^^^
| |
| `var_registry` was mutably borrowed here in the previous iteration of the loop
| first borrow used here, in later iteration of loop
I understand the error itself but I cannot find a way to work around this. I need all function calls to create a new child on the base VarRegistry tree.
Is there a way to allow this barrow to safely or an alternative work around?
I have already tried using scopes to stop the borrowing error
fn activate_file_block(file_block: Term) -> Result<ActiveParse, ActiveParserError> {
let mut var_registry = VarRegistry::new();
let active_terms = Vec::<ActiveParse>::new();
if let Term::Block { terms } = file_block {
for term in terms {
{
let mut local_reg = &mut var_registry;
let out = match term {
Term::Func { .. } => activeate_func_parse(term, &mut local_reg),
Term::Class { .. } => todo!(),
_ => todo!(),
};
}
}
Ok(ActiveParse::File { active_terms })
} else {
Err(ActiveParserError(
"Expected block as wrapper parse object".to_string(),
FileLocation::None,
))
}
}
but this code results in two errors:
A new borrowing error
error[E0499]: cannot borrow `var_registry` as mutable more than once at a time
--> src/avtive_parser/mod.rs:126:37
|
126 | let mut local_reg = &mut var_registry;
| ^^^^^^^^^^^^^^^^^
| |
| `var_registry` was mutably borrowed here in the previous iteration of the loop
| first borrow used here, in later iteration of loop
And a new lifetime error
error[E0597]: `local_reg` does not live long enough
--> src/avtive_parser/mod.rs:128:69
|
126 | let mut local_reg = &mut var_registry;
| ------------- ----------------- borrow later used here
| |
| binding `local_reg` declared here
127 | let out = match term {
128 | Term::Func { .. } => activeate_func_parse(term, &mut local_reg),
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
132 | }
| - `local_reg` dropped here while still borrowed