Mercurial > lbo > hg > rcombinators
changeset 22:435e4e609128
Implement Then combinator and trait method for Parser.
author | Lewin Bormann <lewin@lewin-bormann.info> |
---|---|
date | Tue, 04 Jun 2019 23:55:55 +0200 |
parents | d90066bf03d0 |
children | 4cc1c97724f2 |
files | src/combinators.rs src/lib.rs src/parser.rs |
diffstat | 3 files changed, 54 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/src/combinators.rs Tue Jun 04 23:30:18 2019 +0200 +++ b/src/combinators.rs Tue Jun 04 23:55:55 2019 +0200 @@ -353,6 +353,36 @@ } } +/// Applies one parser, discards the result, and returns the second parser's results if the first +/// one succeeded. +pub struct Then<A: Parser, B: Parser> { + a: A, + b: B, +} + +impl<A: Parser, B: Parser> Then<A, B> { + pub fn new(first: A, second: B) -> Then<A, B> { + Then { + a: first, + b: second, + } + } +} + +impl<A: Parser, B: Parser> Parser for Then<A, B> { + type Result = B::Result; + fn parse( + &mut self, + st: &mut ParseState<impl Iterator<Item = char>>, + ) -> ParseResult<Self::Result> { + match self.a.parse(st) { + Ok(_) => (), + Err(e) => return Err(e), + } + self.b.parse(st) + } +} + #[cfg(test)] mod tests { use super::*; @@ -389,6 +419,16 @@ } #[test] + fn test_then() { + let mut ps = ParseState::new("abcdef 123"); + let mut p = StringParser::new("abc") + .then(StringParser::new("def")) + .then(whitespace()) + .then(Int32::new()); + assert_eq!(Ok(123), p.parse(&mut ps)); + } + + #[test] fn test_alternative() { let mut p = Alternative::new(( StringParser::new("ab"),
--- a/src/lib.rs Tue Jun 04 23:30:18 2019 +0200 +++ b/src/lib.rs Tue Jun 04 23:55:55 2019 +0200 @@ -55,7 +55,7 @@ pub mod primitives; mod state; -pub use combinators::{Alternative, PartialSequence, Repeat, Sequence, Transform}; +pub use combinators::{Alternative, Maybe, PartialSequence, Repeat, Sequence, Then, Transform}; pub use parser::{execerr, Parser}; pub use primitives::{float, string_none_of, string_of, whitespace, Int, StringParser}; pub use state::ParseState;
--- a/src/parser.rs Tue Jun 04 23:30:18 2019 +0200 +++ b/src/parser.rs Tue Jun 04 23:55:55 2019 +0200 @@ -1,6 +1,6 @@ use std::fmt; -use crate::combinators::Transform; +use crate::combinators::{Then, Transform}; use crate::state::ParseState; #[derive(Debug, PartialEq)] @@ -59,12 +59,14 @@ type Result; /// parse consumes input from `st` and returns a result or an error. + /// + /// NOTE: This could be generalized to apply to any item yielded by ParseState. fn parse( &mut self, st: &mut ParseState<impl Iterator<Item = char>>, ) -> ParseResult<Self::Result>; - /// apply transforms the result of this parser using a Transform combinator. + /// `apply` transforms the result of this parser using a Transform combinator. fn apply<R2, F: Fn(Self::Result) -> ParseResult<R2>>( self, f: F, @@ -74,4 +76,13 @@ { Transform::new(self, f) } + + /// `then` attempts to parse input, and if it succeeds, executes parser `p`, only returning + /// `p`'s result. This is useful for chaining parsers of which the results are not need. + fn then<R2, P: Parser<Result = R2>>(self, p: P) -> Then<Self, P> + where + Self: std::marker::Sized, + { + Then::new(self, p) + } }