I am basically tring to make a bash parser. I have a thing setup where a top level parser calls a parser for the next level down, for roughly three levels (script, pipeline, command). I am not getting any errors on the CommandParser bit, but on the Pipeline parser, it is throwing mutable reference issues.
There are plenty of logic errors in the code regarding its eventual functionality, but I can't fix those until it compiles. This code is supposed to eventually parse pipelines (this is the file that is giving errors):
pub(crate) struct PipelineParser<'a> {
root: &'a mut Parser,
pipeline: Pipeline,
}
impl<'a> ParseTools for PipelineParser<'a> {
fn chars(&self) -> &Vec<char> {
return self.root.chars();
}
fn idx(&self) -> usize {
return self.root.idx();
}
fn idx_mut(&mut self) -> &mut usize {
return self.root.idx_mut();
}
}
impl<'a> PipelineParser<'a> {
...
pub fn parse(mut self) -> Pipeline {
while !self.eof() { <-- Immutable reference, gets current pos
let c = self.cur_char(); <-- Immutable reference, gets current character at pos
match c {
C_SPACE => {},
C_PIPE => panic!(),
_ => {
let new_cmd= {
let parser = CommandParser::new(&mut self); <-- Mutable reference,
parser.parse() parses command,
}; returns output,
let end_type = new_cmd.end_type.clone(); position in file
// self.pipeline.commands.push(new_cmd); has been modified.
match end_type {
EndCmd | None => {
break
}
Pipe => {}
}
}
}
}
return self.pipeline;
}
}
I would think that the two immutable refernces would be immediately discarded, since I am trying to get the contents behind the reference (adding clone did not fix the issue) and then forget the references. The compiler doesn't agree.
For context, this code is roughly able to handle individual commands:
impl<'a> ParseTools for CommandParser<'a> {
fn chars(&self) -> &Vec<char> {
return self.root.chars();
}
fn idx(&self) -> usize {
return self.root.idx();
}
fn idx_mut(&mut self) -> &mut usize {
return self.root.idx_mut();
}
}
impl<'a> CommandParser<'a> {
pub fn new(root: &'a mut PipelineParser<'a>) -> CommandParser<'a> {
return CommandParser {
root: root,
command: Command::default(),
};
}
pub fn parse(mut self) -> Command{
let mut components = Vec::new();
while !self.eof() {
let c = self.cur_char();
match c {
C_SPACE => {
self.command.tokens.push(Token { components });
components = Vec::new();
}
C_LIT_QUOTE => components.push(self.parse_lit_quoted()),
C_QUOTE => components.push(self.parse_quoted()),
C_END_CMD => {
self.increment();
break;
},
_ => components.push(self.parse_string()),
};
self.increment();
}
if components.len() > 0 {
self.command.tokens.push(Token { components });
}
return self.command;
}
...
}
I've tried cloning the values behind the immutable reference, as well as putting the references in their own scope so they would drop. I've changed and added some lifetimes, but no mutations to that seemed to work.