diff options
Diffstat (limited to '')
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | pest_consume/Cargo.toml | 3 | ||||
-rw-r--r-- | pest_consume/examples/csv/csv.pest | 15 | ||||
-rw-r--r-- | pest_consume/examples/csv/main.rs | 64 | ||||
-rw-r--r-- | pest_consume/src/lib.rs | 14 |
5 files changed, 97 insertions, 0 deletions
@@ -244,6 +244,7 @@ version = "0.1.0" dependencies = [ "pest 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "pest_consume_macros 0.1.0", + "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/pest_consume/Cargo.toml b/pest_consume/Cargo.toml index 70bdd22..1e2b1af 100644 --- a/pest_consume/Cargo.toml +++ b/pest_consume/Cargo.toml @@ -12,3 +12,6 @@ repository = "https://github.com/Nadrieril/dhall-rust" pest = "2.1" proc-macro-hack = "0.5.9" pest_consume_macros = { path = "../pest_consume_macros" } + +[dev-dependencies] +pest_derive = "2.1" diff --git a/pest_consume/examples/csv/csv.pest b/pest_consume/examples/csv/csv.pest new file mode 100644 index 0000000..a67af8c --- /dev/null +++ b/pest_consume/examples/csv/csv.pest @@ -0,0 +1,15 @@ +WHITESPACE = _{ " "+ } +newline = _{ "\r\n" | "\n" } +number = { "-"? ~ (ASCII_DIGIT | ".")+ } +string = { (!"'" ~ ASCII)* } +field = ${ + number + | "'" ~ string ~ "'" +} +record = { + field ~ ("," ~ field)* + | "" +} +file = { + SOI ~ record ~ (newline ~ record)* ~ newline? ~ EOI +} diff --git a/pest_consume/examples/csv/main.rs b/pest_consume/examples/csv/main.rs new file mode 100644 index 0000000..037948b --- /dev/null +++ b/pest_consume/examples/csv/main.rs @@ -0,0 +1,64 @@ +#![feature(slice_patterns)] +use pest_consume::{match_inputs, Parser}; + +#[derive(pest_derive::Parser)] +#[grammar = "../examples/csv/csv.pest"] +struct CSVParser; + +type ParseResult<T> = Result<T, pest::error::Error<Rule>>; +type Node<'i> = pest_consume::Node<'i, Rule, ()>; + +#[derive(Debug)] +enum CSVField<'a> { + Number(f64), + String(&'a str), +} + +type CSVRecord<'a> = Vec<CSVField<'a>>; +type CSVFile<'a> = Vec<CSVRecord<'a>>; + +#[pest_consume::parser(CSVParser, Rule)] +impl CSVParser { + fn EOI(_input: Node) -> ParseResult<()> { + Ok(()) + } + + fn number(input: Node) -> ParseResult<f64> { + Ok(input.as_str().parse().unwrap()) + } + + fn string(input: Node) -> ParseResult<&str> { + Ok(input.as_str()) + } + + fn field(input: Node) -> ParseResult<CSVField> { + Ok(match_inputs!(input.children(); + [number(n)] => CSVField::Number(n), + [string(s)] => CSVField::String(s), + )) + } + + fn record(input: Node) -> ParseResult<CSVRecord> { + Ok(match_inputs!(input.children(); + [field(fields)..] => fields.collect(), + )) + } + + fn file(input: Node) -> ParseResult<CSVFile> { + Ok(match_inputs!(input.children(); + [record(records).., EOI(_)] => records.collect(), + )) + } +} + +fn parse_csv(input_str: &str) -> ParseResult<CSVFile> { + let inputs = CSVParser::parse(Rule::file, input_str)?; + Ok(match_inputs!(<CSVParser>; inputs; + [file(e)] => e, + )) +} + +fn main() { + let parsed = parse_csv("-273.15, ' a string '\n\n42, 0"); + println!("{:?}", parsed); +} diff --git a/pest_consume/src/lib.rs b/pest_consume/src/lib.rs index 425d8cf..f14f6f5 100644 --- a/pest_consume/src/lib.rs +++ b/pest_consume/src/lib.rs @@ -1,3 +1,7 @@ +/// `pest_consume` extends [pest] to make it easy to consume the resulting pest parse tree. +/// Given a grammar file, pest generates a parser that outputs an untyped parse tree. Then that +/// parse tree needs to be transformed into whatever datastructures your application uses. +/// `pest_consume` provides two powerful macros to make this easy. use pest::error::Error; use pest::Parser as PestParser; use pest::RuleType; @@ -85,6 +89,9 @@ mod node { pub fn as_pair(&self) -> &Pair<'i, R> { &self.pair } + pub fn into_pair(self) -> Pair<'i, R> { + self.pair + } pub fn as_span(&self) -> Span<'i> { self.pair.as_span() } @@ -135,6 +142,13 @@ mod node { { Node::new(new_pair, self.user_data.clone()) } + + pub fn as_pairs(&self) -> &Pairs<'i, R> { + &self.pairs + } + pub fn into_pairs(self) -> Pairs<'i, R> { + self.pairs + } } impl<'i, R, D> Iterator for Nodes<'i, R, D> |