0

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.

  • 2
    Please edit your question to include the full error. Also, please include all types and functions needed to compile your code. – PitaJ Jun 09 '23 at 03:21
  • I want to say you're running into [this issue](https://fasterthanli.me/articles/a-rust-match-made-in-hell), which stems from the fact that the match extends the lifetime of `c` for... a while. What happens if you dereference `c` in order to force the copy to take place? – BallpointBen Jun 09 '23 at 04:16
  • Can you give the precise signatures of the functions `PipelineParser::eof`, `PipelineParser::cur_char`, `CommandParser::new`, and the `parse` function which is being called in the definition of `new_cmd`? – Mark Saving Jun 09 '23 at 21:41

0 Answers0