m4rw3r / chomp

A fast monadic-style parser combinator designed to work on stable Rust.
Apache License 2.0
244 stars 19 forks source link

Be able to unwrap Input from InputPosition. #61

Closed dashed closed 7 years ago

dashed commented 8 years ago

Hi!

I have a usecase where I'd need to adapt chomp::buffer::InputBuf to chomp::types::numbering::InputPosition (via wrapping) and back again (via unwrapping).

However, I'm unable to unwrap Input from InputPosition.

I simply add impl IntoInner trait to InputPosition: https://github.com/dashed/chomp/commit/e5dfe7e6d161f79d004e7315e35771edcfee0777


My use case is as follows; I'd love any feedback or better alternative approaches:

struct SourceFile {
    input: chomp::buffer::Source<
        chomp::buffer::data_source::ReadDataSource<std::fs::File>,
        chomp::buffer::FixedSizeBuffer<u8>>,
    position: CurrentPosition
}

impl SourceFile {
    fn new(path_to_file: &Path) -> Self {

        let reason = format!("Failed to open file: {:?}", path_to_file);
        let file: File  = File::open(path_to_file).expect(&reason);

        let input = chomp::buffer::Source::new(file);

        SourceFile {
            input: input,
            position: CurrentPosition::new()
        }
    }

    fn __parse_token<'a>(&'a mut self) -> Result<Token, StreamError<&'a [u8], ParseError>>  {

        let mut this_position = self.position;

        let result = {
            let m = |old_input: chomp::buffer::InputBuf<'a, u8>| {

                let input_override = InputPosition::new(old_input, this_position);
                let (input_override, parse_result_raw) = token_parser(input_override).into_inner();
                let (old_input, new_position) = input_override.into_inner();

                this_position = new_position;

                old_input.from_result(parse_result_raw)
            };

            self.input.parse(m)
        };

        self.position = this_position.clone();

        result
    }

    fn parse(&mut self) {
        loop {
            match self.__parse_token() {
                Ok(t) => {
                    print!("{:?}", t);
                    continue;
                },
                Err(StreamError::Retry) => {
                    // Needed to refill buffer when necessary
                    continue;
                },
                Err(StreamError::EndOfInput) => {
                    break;
                },
                Err(StreamError::ParseError(_buf, err)) => {
                    panic!("{}", err);
                },
                Err(StreamError::Incomplete) => {
                    panic!("Parser failed to complete with the available data.");
                },
                Err(StreamError::IoError(err)) => {
                    panic!("{:?}", err);
                }
            }

            // NOTE: should continue from above
            unreachable!();
        }
    }
}
m4rw3r commented 8 years ago

into_inner seems to be a good solution to the fundamental parts of this problem (since you need to disassemble it and reassemble it anyway), though a wrapper for buffer::Source and/or buffer::Stream would probably be handy.

If you'd like you can submit the into_inner implementation as a PR?

dashed commented 8 years ago

If you'd like you can submit the into_inner implementation as a PR?

Sure definitely; I'll see if I can PR with some tests this weekend.