This is an old revision of the document!
Building Parsers
The relision::parser module provides very, very, very simple parser primitives for building recursive descent parsers.
The module provides three key structs and one specialized type.
ParseErrorencapsulates a parse errorLocrepresents a location in the parse (line and column)Parserprovides parsing services around some streamResultspecializes the more general result type to parsers
Parser Primitives
There are two basic parser primitives.
- You can peek at upcoming characters
- You can consume characters
A simple application of this is recognizing an integer. Here's some pseudocode.
-- The best pseudocode is written in Ada for some reason. while peek is a digit loop consume; end loop;
Composites of these primitives are available to simplify things. For example,
the implementation of the above pseudocode might look like the code below, where the integer parsing is broken out into a separate function so we can use the ? operator.
use std::io; use relision::parser; fn parse_unsigned_integer<R: io::Read>(parser: &mut parser::Parser<R>) -> parser::Result<u64> { let result = parser.take_while(|ch| ch.is_digit(10))?; match result.parse::<u64>() { Ok(number) => Ok(number), Err(err) => Err(parser.error(err.to_string())), } } fn main() { // Make a new parser and wrap the standard input. let mut parser = parser::Parser::new("console".to_string(), std::io::stdin()); match parse_unsigned_integer(&mut parser) { Err(err) => { println!("{}", err); } Ok(value) => { println!("{}", value); } } }
Here the take_while peeks at and consumes the next character while it is a digit. It works pretty well.
If nothing is entered we get console:1:1: cannot parse integer from empty string. If we enter a huge number like 99999999999999999999 (that's 20 nines) we get console:1:1: number too large to fit in target type. If we enter something like 65fred then we get 65, with the parser left pointing at the f.