diff --git a/Cargo.toml b/Cargo.toml index 2e39f92..748368a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "parsell" -version = "0.3.2-SNAPSHOT" +version = "0.4.0-SNAPSHOT" authors = [ "Alan Jeffrey " ] description = "Parsell LL(1) streaming parser combinators" diff --git a/README.md b/README.md index 86565ac..9313d39 100644 --- a/README.md +++ b/README.md @@ -20,25 +20,31 @@ It is based on: ```rust extern crate parsell; -use parsell::{character,Parser,Uncommitted,Committed,Stateful}; +use parsell::{character,Parser,UncommittedStr,StatefulStr}; use parsell::ParseResult::{Done,Continue}; #[allow(non_snake_case)] fn main() { // A sequence of alphanumerics, saved in a string buffer let ALPHANUMERIC = character(char::is_alphanumeric); - let ALPHANUMERICS = ALPHANUMERIC.star(String::new); + let ALPHANUMERICS = ALPHANUMERIC.plus(String::new); + + // If you provide unmatching input to the parser, you'll get back a None response: + match ALPHANUMERICS.init_str("!$?") { + None => (), + _ => panic!("Can't happen."), + } // If you provide complete input to the parser, you'll get back a Done response: - match ALPHANUMERICS.init().parse("abc123!") { - Done("!",result) => assert_eq!(result, "abc123"), + match ALPHANUMERICS.init_str("abc123!") { + Some(Done(result)) => assert_eq!(result, "abc123"), _ => panic!("Can't happen."), } // If you provide incomplete input to the parser, you'll get back a Continue response: - match ALPHANUMERICS.init().parse("abc") { - Continue("",parsing) => match parsing.parse("123!") { - Done("!",result) => assert_eq!(result, "abc123"), + match ALPHANUMERICS.init_str("abc") { + Some(Continue(parsing)) => match parsing.more_str("123!") { + Done(result) => assert_eq!(result, "abc123"), _ => panic!("Can't happen."), }, _ => panic!("Can't happen."), diff --git a/src/impls.rs b/src/impls.rs index da611bc..ad9c9e0 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -1,17 +1,17 @@ //! Provide implementations of parser traits. -use super::{Stateful, Parser, Uncommitted, Committed, Boxable, ParseResult, MaybeParseResult, - Factory, Function, Consumer, ToFromOwned}; -use super::ParseResult::{Continue, Done}; -use super::MaybeParseResult::{Abort, Commit, Empty}; +use super::{Parser, ParseResult}; +use super::{Stateful, Committed, Uncommitted, Boxable}; +use super::{Function, Consumer, Factory, PeekableIterator}; +use super::{Upcast, ToStatic}; +use super::ParseResult::{Done, Continue}; -use self::AndThenStatefulParser::{InLhs, InRhs}; -use self::OrElseStatefulParser::{Lhs, Rhs}; -use self::OrElseCommittedParser::{Uncommit, CommitLhs, CommitRhs}; +use self::OrElseState::{Lhs, Rhs}; +use self::AndThenState::{InLhs, InBetween, InRhs}; use std::borrow::Cow; use std::borrow::Cow::{Borrowed, Owned}; -use std::iter::Peekable; +use std::str::Chars; use std::fmt::{Formatter, Debug}; use std; @@ -143,361 +143,330 @@ impl Function<(Result, Result)> for TryZipTry { } } -// ----------- Map --------------- - -#[derive(Debug)] -pub struct MapStatefulParser(P, F); +// ----------- Deal with options --------------- -// A work around for functions implmenting copy but not clone -// https://github.com/rust-lang/rust/issues/28229 -impl Copy for MapStatefulParser - where P: Copy, - F: Copy -{} -impl Clone for MapStatefulParser - where P: Clone, - F: Copy +#[derive(Copy, Clone, Debug)] +pub struct MkSome; +impl Function for MkSome { - fn clone(&self) -> Self { - MapStatefulParser(self.0.clone(), self.1) + type Output = Option; + fn apply(&self, arg: T) -> Option { + Some(arg) } } -impl Stateful for MapStatefulParser - where P: Stateful, - F: Function -{ - type Output = F::Output; - fn parse(self, value: S) -> ParseResult { - match self.0.parse(value) { - Done(rest, result) => Done(rest, self.1.apply(result)), - Continue(rest, parsing) => Continue(rest, MapStatefulParser(parsing, self.1)), - } - } - fn done(self) -> Self::Output { - self.1.apply(self.0.done()) - } -} +// ----------- Map --------------- -pub struct MapParser(P, F); +pub struct Map(P, F); // A work around for functions implmenting copy but not clone // https://github.com/rust-lang/rust/issues/28229 -impl Copy for MapParser +impl Copy for Map where P: Copy, F: Copy {} -impl Clone for MapParser +impl Clone for Map where P: Clone, F: Copy { fn clone(&self) -> Self { - MapParser(self.0.clone(), self.1) + Map(self.0.clone(), self.1) } } // A work around for named functions not implmenting Debug // https://github.com/rust-lang/rust/issues/31522 -impl Debug for MapParser +impl Debug for Map where P: Debug { fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - write!(fmt, "MapParser({:?}, ...)", self.0) + write!(fmt, "Map({:?}, ...)", self.0) } } -impl Parser for MapParser {} -impl Uncommitted for MapParser - where P: Uncommitted, - F: Copy + Function +impl Parser for Map {} + +impl Stateful for Map + where P: Stateful, + F: Function, + Str: Iterator, { + type Output = F::Output; - type State = MapStatefulParser; - fn parse(&self, value: S) -> MaybeParseResult { - match self.0.parse(value) { - Empty(rest) => Empty(rest), - Commit(Done(rest, result)) => Commit(Done(rest, self.1.apply(result))), - Commit(Continue(rest, parsing)) => { - Commit(Continue(rest, MapStatefulParser(parsing, self.1))) - } - Abort(value) => Abort(value), + + fn done(self) -> F::Output { + self.1.apply(self.0.done()) + } + + fn more(self, string: &mut Str) -> ParseResult { + match self.0.more(string) { + Done(result) => Done(self.1.apply(result)), + Continue(state) => Continue(Map(state, self.1)), } } + } -impl Committed for MapParser - where P: Committed, - F: Copy + Function + +impl Committed for Map + where P: Committed, + F: 'static + Copy + Function, + Str: Iterator, { + + fn empty(&self) -> F::Output { + self.1.apply(self.0.empty()) + } + +} + +impl Uncommitted for Map + where P: Uncommitted, + F: 'static + Copy + Function, + Str: Iterator, +{ + type Output = F::Output; - type State = MapStatefulParser; - fn init(&self) -> Self::State { - MapStatefulParser(self.0.init(), self.1) + type State = Map; + + fn init(&self, string: &mut Str) -> Option> { + match self.0.init(string) { + None => None, + Some(Done(result)) => Some(Done(self.1.apply(result))), + Some(Continue(state)) => Some(Continue(Map(state, self.1))), + } } + } -impl MapParser { - pub fn new(parser: P, function: F) -> Self { - MapParser(parser, function) +impl Map { + pub fn new(p: P, f: F) -> Self { + Map(p, f) } } // ----------- Sequencing --------------- #[derive(Copy, Clone, Debug)] -pub struct AndThenParser(P, Q); - -impl Parser for AndThenParser {} -impl Committed for AndThenParser - where P: Committed, - Q: Committed, - P::Output: ToFromOwned, -{ - type Output = (P::Output,Q::Output); - type State = AndThenStatefulParser::Owned>; - fn init(&self) -> Self::State { - InLhs(self.0.init(), self.1.init()) - } -} -impl Uncommitted for AndThenParser - where P: Uncommitted, - Q: Committed, - P::Output: ToFromOwned, -{ - type Output = (P::Output,Q::Output); - type State = AndThenStatefulParser::Owned>; - fn parse(&self, value: S) -> MaybeParseResult { - match self.0.parse(value) { - Empty(rest) => Empty(rest), - Commit(Done(rest, result1)) => { - match self.1.init().parse(rest) { - Done(rest, result2) => Commit(Done(rest, (result1, result2))), - Continue(rest, parsing) => Commit(Continue(rest, InRhs(result1.to_owned(), parsing))), - } - } - Commit(Continue(rest, parsing)) => { - Commit(Continue(rest, InLhs(parsing, self.1.init()))) - } - Abort(value) => Abort(value), +pub struct AndThen(P, Q); + +impl Parser for AndThen {} + +impl Committed for AndThen + where P: Committed, + Q: 'static + Copy + Committed, + Str: Iterator, + PStaticOutput: 'static + Upcast, + P::Output: ToStatic, +{ + + fn empty(&self) -> Self::Output { + (self.0.empty(), self.1.empty()) + } + +} + +impl Uncommitted for AndThen + where P: Uncommitted, + Q: 'static + Copy + Committed, + Str: Iterator, + PStaticOutput: 'static + Upcast, + P::Output: ToStatic, +{ + + type Output = (P::Output, Q::Output); + type State = AndThenState; + + fn init(&self, string: &mut Str) -> Option> { + match self.0.init(string) { + None => None, + Some(Done(fst)) => match self.1.init(string) { + None => Some(Continue(InBetween(fst.to_static(), self.1))), + Some(Done(snd)) => Some(Done((fst, snd))), + Some(Continue(snd)) => Some(Continue(InRhs(fst.to_static(), snd))), + }, + Some(Continue(fst)) => Some(Continue(InLhs(fst, self.1))), } } + +} + +impl AndThen { + pub fn new(p: P, q: Q) -> Self { + AndThen(p, q) + } } #[derive(Copy, Clone, Debug)] -pub enum AndThenStatefulParser { - InLhs(P, Q), - InRhs(T, Q), +pub enum AndThenState { + InLhs(PState, Q), + InBetween(PStaticOutput, Q), + InRhs(PStaticOutput, QState), } -impl Stateful for AndThenStatefulParser::Owned> - where P: Stateful, - Q: Stateful, - P::Output: ToFromOwned, +impl Stateful for AndThenState + where PState: Stateful, + Q: Committed, + Str: Iterator, + PStaticOutput: 'static + Upcast, + PState::Output: ToStatic, + { - type Output = (P::Output,Q::Output); - fn parse(self, value: S) -> ParseResult { + + type Output = (PState::Output, Q::Output); + + fn done(self) -> Self::Output + { match self { - InLhs(lhs, rhs) => { - match lhs.parse(value) { - Done(rest, result1) => { - match rhs.parse(rest) { - Done(rest, result2) => Done(rest, (result1, result2)), - Continue(rest, parsing) => Continue(rest, InRhs(result1.to_owned(), parsing)), - } - } - Continue(rest, parsing) => Continue(rest, InLhs(parsing, rhs)), + InLhs(fst, snd) => (fst.done(), snd.empty()), + InBetween(fst, snd) => (fst.upcast(), snd.empty()), + InRhs(fst, snd) => (fst.upcast(), snd.done()), + } + } + + fn more(self, string: &mut Str) -> ParseResult + { + match self { + InLhs(fst, snd) => { + match fst.more(string) { + Done(fst) => match snd.init(string) { + None => Continue(InBetween(fst.to_static(), snd)), + Some(Done(snd)) => Done((fst, snd)), + Some(Continue(snd)) => Continue(InRhs(fst.to_static(), snd)), + }, + Continue(fst) => Continue(InLhs(fst, snd)), } } - InRhs(result1, rhs) => { - match rhs.parse(value) { - Done(rest, result2) => Done(rest, (ToFromOwned::from_owned(result1), result2)), - Continue(rest, parsing) => Continue(rest, InRhs(result1, parsing)), + InBetween(fst, snd) => { + match snd.init(string) { + None => Continue(InBetween(fst, snd)), + Some(Done(snd)) => Done((fst.upcast(), snd)), + Some(Continue(snd)) => Continue(InRhs(fst, snd)), + } + } + InRhs(fst, snd) => { + match snd.more(string) { + Done(snd) => Done((fst.upcast(), snd)), + Continue(snd) => Continue(InRhs(fst, snd)), } } } } - fn done(self) -> Self::Output { - match self { - InLhs(lhs, rhs) => (lhs.done(), rhs.done()), - InRhs(result1, rhs) => (ToFromOwned::from_owned(result1), rhs.done()), - } - } -} - -impl AndThenParser { - pub fn new(lhs: P, rhs: Q) -> Self { - AndThenParser(lhs, rhs) - } + } // ----------- Choice --------------- #[derive(Copy, Clone, Debug)] -pub struct OrElseParser(P, Q); +pub struct OrElse(P, Q); + +impl Parser for OrElse {} -impl Parser for OrElseParser {} -impl Committed for OrElseParser - where P: Copy + Uncommitted, - Q: Committed +impl Committed for OrElse + where P: Uncommitted, + Q: Committed, + Str: Iterator, { - type Output = P::Output; - type State = OrElseCommittedParser; - fn init(&self) -> Self::State { - Uncommit(self.0, self.1.init()) + + fn empty(&self) -> P::Output { + self.1.empty() } + } -impl Uncommitted for OrElseParser - where P: Uncommitted, - Q: Uncommitted + +impl Uncommitted for OrElse + where P: Uncommitted, + Q: Uncommitted, + Str: Iterator, { + type Output = P::Output; - type State = OrElseStatefulParser; - fn parse(&self, value: S) -> MaybeParseResult { - match self.0.parse(value) { - Empty(rest) => Empty(rest), - Commit(Done(rest, result)) => Commit(Done(rest, result)), - Commit(Continue(rest, parsing)) => Commit(Continue(rest, Lhs(parsing))), - Abort(value) => { - match self.1.parse(value) { - Empty(rest) => Empty(rest), - Commit(Done(rest, result)) => Commit(Done(rest, result)), - Commit(Continue(rest, parsing)) => Commit(Continue(rest, Rhs(parsing))), - Abort(value) => Abort(value), - } - } + type State = OrElseState; + + fn init(&self, string: &mut Str) -> Option> { + match self.0.init(string) { + Some(Done(result)) => Some(Done(result)), + Some(Continue(lhs)) => Some(Continue(Lhs(lhs))), + None => match self.1.init(string) { + Some(Done(result)) => Some(Done(result)), + Some(Continue(rhs)) => Some(Continue(Rhs(rhs))), + None => None, + }, } } + } -impl OrElseParser { +impl OrElse { pub fn new(lhs: P, rhs: Q) -> Self { - OrElseParser(lhs, rhs) + OrElse(lhs, rhs) } } #[derive(Copy, Clone, Debug)] -pub enum OrElseStatefulParser { +pub enum OrElseState { Lhs(P), Rhs(Q), } -impl Stateful for OrElseStatefulParser - where P: Stateful, - Q: Stateful +impl Stateful for OrElseState + where P: Stateful, + Q: Stateful, + Str: Iterator, { type Output = P::Output; - fn parse(self, value: S) -> ParseResult { + + fn more(self, string: &mut Str) -> ParseResult { match self { - Lhs(lhs) => { - match lhs.parse(value) { - Done(rest, result) => Done(rest, result), - Continue(rest, parsing) => Continue(rest, Lhs(parsing)), - } - } - Rhs(rhs) => { - match rhs.parse(value) { - Done(rest, result) => Done(rest, result), - Continue(rest, parsing) => Continue(rest, Rhs(parsing)), - } - } + Lhs(lhs) => match lhs.more(string) { + Done(result) => Done(result), + Continue(lhs) => Continue(Lhs(lhs)), + }, + Rhs(rhs) => match rhs.more(string) { + Done(result) => Done(result), + Continue(rhs) => Continue(Rhs(rhs)), + }, } } + fn done(self) -> Self::Output { match self { Lhs(lhs) => lhs.done(), Rhs(rhs) => rhs.done(), } } -} -#[derive(Copy, Clone, Debug)] -pub enum OrElseCommittedParser { - Uncommit(P, R), - CommitLhs(Q), - CommitRhs(R), -} - -impl Stateful for OrElseCommittedParser - where P: Uncommitted, - Q: Stateful -{ - type Output = P::Output; - fn parse(self, value: S) -> ParseResult { - match self { - Uncommit(lhs, rhs) => { - match lhs.parse(value) { - Empty(value) => Continue(value, Uncommit(lhs, rhs)), - Commit(Done(rest, result)) => Done(rest, result), - Commit(Continue(rest, parsing)) => Continue(rest, CommitLhs(parsing)), - Abort(value) => { - match rhs.parse(value) { - Done(rest, result) => Done(rest, result), - Continue(rest, parsing) => Continue(rest, CommitRhs(parsing)), - } - } - } - } - CommitLhs(lhs) => { - match lhs.parse(value) { - Done(rest, result) => Done(rest, result), - Continue(rest, parsing) => Continue(rest, CommitLhs(parsing)), - } - } - CommitRhs(rhs) => { - match rhs.parse(value) { - Done(rest, result) => Done(rest, result), - Continue(rest, parsing) => Continue(rest, CommitRhs(parsing)), - } - } - } - } - fn done(self) -> Self::Output { - match self { - Uncommit(_, rhs) => rhs.done(), - CommitLhs(lhs) => lhs.done(), - CommitRhs(rhs) => rhs.done(), - } - } } // ----------- Kleene star --------------- #[derive(Clone,Debug)] -pub struct StarStatefulParser(P, Option, T); +pub struct StarState(P, Option, T); -impl Stateful for StarStatefulParser - where P: Copy + Uncommitted, - T: Consumer +impl Stateful for StarState + where P: Copy + Uncommitted, + PState: 'static + Stateful, + T: Consumer, + Str: PeekableIterator, { type Output = T; - fn parse(mut self, mut value: S) -> ParseResult { + fn more(mut self, string: &mut Str) -> ParseResult { loop { match self.1.take() { None => { - match self.0.parse(value) { - Empty(rest) => { - return Continue(rest, StarStatefulParser(self.0, None, self.2)) - } - Commit(Continue(rest, parsing)) => { - return Continue(rest, - StarStatefulParser(self.0, Some(parsing), self.2)) - } - Commit(Done(rest, result)) => { - self.2.accept(result); - value = rest; - } - Abort(rest) => return Done(rest, self.2), + match self.0.init(string) { + Some(Continue(state)) => return Continue(StarState(self.0, Some(state), self.2)), + Some(Done(result)) => self.2.accept(result), + None => return if string.is_empty() { + Continue(self) + } else { + Done(self.2) + }, } } - Some(parser) => { - match parser.parse(value) { - Continue(rest, parsing) => { - return Continue(rest, - StarStatefulParser(self.0, Some(parsing), self.2)) - } - Done(rest, result) => { - self.2.accept(result); - value = rest; - } + Some(state) => { + match state.more(string) { + Continue(state) => return Continue(StarState(self.0, Some(state), self.2)), + Done(result) => self.2.accept(result), } } } @@ -508,291 +477,367 @@ impl Stateful for StarStatefulParser } } -pub struct PlusParser(P, F); +pub struct Plus(P, F); // A work around for functions implmenting copy but not clone // https://github.com/rust-lang/rust/issues/28229 -impl Copy for PlusParser +impl Copy for Plus where P: Copy, F: Copy {} -impl Clone for PlusParser +impl Clone for Plus where P: Clone, F: Copy { fn clone(&self) -> Self { - PlusParser(self.0.clone(), self.1) + Plus(self.0.clone(), self.1) } } // A work around for named functions not implmenting Debug // https://github.com/rust-lang/rust/issues/31522 -impl Debug for PlusParser +impl Debug for Plus where P: Debug { fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - write!(fmt, "PlusParser({:?}, ...)", self.0) + write!(fmt, "Plus({:?}, ...)", self.0) } } -impl Parser for PlusParser {} -impl Uncommitted for PlusParser - where P: Copy + Uncommitted, - F: Factory, - F::Output: Consumer +impl Parser for Plus {} + +impl Uncommitted for Plus + where P: 'static + Copy + Uncommitted, + F: 'static + Factory, + Str: PeekableIterator, + P::State: 'static + Stateful, + F::Output: Consumer<

>::Output>, { + type State = StarState; type Output = F::Output; - type State = StarStatefulParser; - fn parse(&self, value: S) -> MaybeParseResult { - match self.0.parse(value) { - Empty(rest) => Empty(rest), - Abort(rest) => Abort(rest), - Commit(Continue(rest, parsing)) => { - Commit(Continue(rest, - StarStatefulParser(self.0, Some(parsing), self.1.build()))) - } - Commit(Done(rest, result)) => { + + fn init(&self, string: &mut Str) -> Option> { + match self.0.init(string) { + None => None, + Some(Continue(state)) => Some(Continue(StarState(self.0, Some(state), self.1.build()))), + Some(Done(result)) => { let mut buffer = self.1.build(); buffer.accept(result); - Commit(StarStatefulParser(self.0, None, buffer).parse(rest)) - } + Some(StarState(self.0, None, buffer).more(string)) + }, } } } -impl PlusParser { +impl Plus { pub fn new(parser: P, factory: F) -> Self { - PlusParser(parser, factory) + Plus(parser, factory) } } -pub struct StarParser(P, F); +pub struct Star(P, F); // A work around for functions implmenting copy but not clone // https://github.com/rust-lang/rust/issues/28229 -impl Copy for StarParser +impl Copy for Star where P: Copy, F: Copy {} -impl Clone for StarParser +impl Clone for Star where P: Clone, F: Copy { fn clone(&self) -> Self { - StarParser(self.0.clone(), self.1) + Star(self.0.clone(), self.1) } } // A work around for named functions not implmenting Debug // https://github.com/rust-lang/rust/issues/31522 -impl Debug for StarParser +impl Debug for Star where P: Debug { fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - write!(fmt, "StarParser({:?}, ...)", self.0) + write!(fmt, "Star({:?}, ...)", self.0) } } -impl Parser for StarParser {} -impl Committed for StarParser - where P: Copy + Uncommitted, - F: Factory, - F::Output: Consumer +impl Parser for Star {} + +impl Uncommitted for Star + where P: 'static + Copy + Uncommitted, + F: 'static + Factory, + Str: PeekableIterator, + P::State: 'static + Stateful, + F::Output: Consumer<

>::Output>, { + + type State = StarState; type Output = F::Output; - type State = StarStatefulParser; - fn init(&self) -> Self::State { - StarStatefulParser(self.0, None, self.1.build()) + + fn init(&self, string: &mut Str) -> Option> { + if string.is_empty() { + None + } else { + Some(StarState(self.0, None, self.1.build()).more(string)) + } + } + +} + +impl Committed for Star + where P: 'static + Copy + Uncommitted, + F: 'static + Factory, + Str: PeekableIterator, + P::State: 'static + Stateful, + F::Output: Consumer<

>::Output>, +{ + + fn empty(&self) -> F::Output { + self.1.build() } + } -impl StarParser { +impl Star { pub fn new(parser: P, factory: F) -> Self { - StarParser(parser, factory) + Star(parser, factory) } } -// ----------- A type for empty parsers ------------- +// ----------- A type for parsers which immediately emit a result ------------- #[derive(Copy, Clone, Debug)] -enum Impossible {} +pub struct Emit(F); -impl Impossible { - fn cant_happen(&self) -> T { - match *self {} +impl Parser for Emit {} + +impl Stateful for Emit + where Str: Iterator, + F: Factory, +{ + + type Output = F::Output; + + fn more(self, _: &mut Str) -> ParseResult { + Done(self.0.build()) } + + fn done(self) -> F::Output { + self.0.build() + } + } -#[derive(Copy, Clone, Debug)] -pub struct ImpossibleStatefulParser(Impossible, T); +impl Uncommitted for Emit + where Str: PeekableIterator, + F: 'static + Copy + Factory, +{ -impl Stateful for ImpossibleStatefulParser { - type Output = T; - fn parse(self, _: S) -> ParseResult { - self.0.cant_happen() + type Output = F::Output; + type State = Self; + + fn init(&self, string: &mut Str) -> Option> { + if string.is_empty() { + None + } else { + Some(Done(self.0.build())) + } } - fn done(self) -> T { - self.0.cant_happen() + +} + +impl Committed for Emit + where Str: PeekableIterator, + F: 'static + Copy + Factory, +{ + + fn empty(&self) -> F::Output { + self.0.build() + } +} + +impl Emit { + pub fn new(t: T) -> Self { + Emit(t) } } // ----------- Character parsers ------------- -pub struct CharacterParser(F); +#[derive(Copy, Clone, Debug)] +pub struct CharacterState(StaticCh); + +impl Stateful for CharacterState + where Str: Iterator, + StaticCh: Upcast, +{ + type Output = Ch; + + fn more(self, _: &mut Str) -> ParseResult { + Done(self.0.upcast()) + } + + fn done(self) -> Ch { + self.0.upcast() + } +} + +impl CharacterState { + pub fn new(ch: StaticCh) -> Self { + CharacterState(ch) + } +} + +pub struct Character(F); // A work around for functions implmenting copy but not clone // https://github.com/rust-lang/rust/issues/28229 -impl Copy for CharacterParser where F: Copy -{} -impl Clone for CharacterParser where F: Copy +impl Copy for Character where F: Copy {} +impl Clone for Character where F: Copy { fn clone(&self) -> Self { - CharacterParser(self.0) + Character(self.0) } } // A work around for named functions not implmenting Debug // https://github.com/rust-lang/rust/issues/31522 -impl Debug for CharacterParser +impl Debug for Character { fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - write!(fmt, "CharacterParser(...)") + write!(fmt, "Character(...)") } } -impl Parser for CharacterParser {} -impl<'a, F> Uncommitted<&'a str> for CharacterParser where F: Function +impl Parser for Character {} + +impl Uncommitted for Character + where Str: PeekableIterator, + F: Copy + Function, + Ch: ToStatic + Copy, + StaticCh: 'static + Upcast, { - type Output = char; - type State = ImpossibleStatefulParser; - fn parse(&self, value: &'a str) -> MaybeParseResult { - match value.chars().next() { - None => Empty(value), - Some(ch) if self.0.apply(ch) => { - let len = ch.len_utf8(); - Commit(Done(&value[len..], ch)) - } - Some(_) => Abort(value), + type Output = Ch; + type State = CharacterState; + + fn init(&self, string: &mut Str) -> Option> { + match string.next_if(self.0) { + None => None, + Some(ch) => Some(Done(ch)), } } + } -impl CharacterParser { +impl Character { pub fn new(function: F) -> Self { - CharacterParser(function) + Character(function) } } -#[derive(Copy,Clone,Debug)] -pub struct AnyCharacterParser; - -impl Parser for AnyCharacterParser {} -impl<'a> Stateful<&'a str> for AnyCharacterParser { - type Output = Option; - fn parse(self, value: &'a str) -> ParseResult { - match value.chars().next() { - None => Continue(value, AnyCharacterParser), - Some(ch) => { - let len = ch.len_utf8(); - Done(&value[len..], Some(ch)) - } - } - } - fn done(self) -> Self::Output { - None - } -} -impl<'a> Committed<&'a str> for AnyCharacterParser { - type Output = Option; - type State = Self; - fn init(&self) -> Self { - AnyCharacterParser - } -} - -// ----------- Token parsers ------------- - -pub struct TokenParser(F); +pub struct CharacterRef(F); // A work around for functions implmenting copy but not clone // https://github.com/rust-lang/rust/issues/28229 -impl Copy for TokenParser where F: Copy -{} -impl Clone for TokenParser where F: Copy +impl Copy for CharacterRef where F: Copy {} +impl Clone for CharacterRef where F: Copy { fn clone(&self) -> Self { - TokenParser(self.0) + CharacterRef(self.0) } } // A work around for named functions not implmenting Debug // https://github.com/rust-lang/rust/issues/31522 -impl Debug for TokenParser +impl Debug for CharacterRef { fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - write!(fmt, "TokenParser(...)") + write!(fmt, "CharacterRef(...)") } } -impl Parser for TokenParser {} -impl Uncommitted> for TokenParser - where F: for<'a> Function<&'a I::Item, Output = bool>, - I: Iterator +impl Parser for CharacterRef {} + +impl Uncommitted for CharacterRef + where Str: PeekableIterator, + F: Copy + for<'a> Function<&'a Ch, Output = bool>, + Ch: ToStatic, + StaticCh: 'static + Upcast, { - type Output = I::Item; - type State = ImpossibleStatefulParser; - fn parse(&self, mut iterator: Peekable) -> MaybeParseResult> { - let matched = match iterator.peek() { + type Output = Ch; + type State = CharacterState; + + fn init(&self, string: &mut Str) -> Option> { + match string.next_if_ref(self.0) { None => None, - Some(tok) => Some(self.0.apply(tok)), - }; - match matched { - None => Empty(iterator), - Some(true) => { - let tok = iterator.next().unwrap(); - Commit(Done(iterator, tok)) - } - Some(false) => Abort(iterator), + Some(ch) => Some(Done(ch)), } } + } -impl TokenParser { +impl CharacterRef { pub fn new(function: F) -> Self { - TokenParser(function) + CharacterRef(function) } } #[derive(Copy,Clone,Debug)] -pub struct AnyTokenParser; +pub struct AnyCharacter; + +impl Parser for AnyCharacter {} -impl Parser for AnyTokenParser {} -impl Stateful for AnyTokenParser where I: Iterator +impl Stateful for AnyCharacter + where Str: Iterator, { - type Output = Option; - fn parse(self, mut iter: I) -> ParseResult { - match iter.next() { - None => Continue(iter, AnyTokenParser), - Some(tok) => Done(iter, Some(tok)), + type Output = Option; + + fn more(self, string: &mut Str) -> ParseResult> { + match string.next() { + None => Continue(self), + Some(ch) => Done(Some(ch)), } } - fn done(self) -> Self::Output { + + fn done(self) -> Option { None } } -impl Committed for AnyTokenParser where I: Iterator + +impl Uncommitted for AnyCharacter + where Str: Iterator, + Ch: ToStatic, + StaticCh: 'static + Upcast, { - type Output = Option; - type State = Self; - fn init(&self) -> Self { - AnyTokenParser + type Output = Option; + type State = AnyCharacter; + + fn init(&self, string: &mut Str) -> Option>> { + match string.next() { + None => None, + Some(ch) => Some(Done(Some(ch))), + } } + +} + +impl Committed for AnyCharacter + where Str: Iterator, + Ch: ToStatic, + StaticCh: 'static + Upcast, +{ + + fn empty(&self) -> Option { + None + } + } // ----------- Buffering ------------- -// If m is a Uncommitted<&'a str>, then -// m.buffer() is a Uncommitted<&'a str> with Output Cow<'a,str>. +// If p is a Uncommitted>, then +// m.buffer() is a Uncommitted> with Output (char, Cow<'a,str>). // It does as little buffering as it can, but it does allocate as buffer for the case // where the boundary marker of the input is misaligned with that of the parser. // For example, m is matching string literals, and the input is '"abc' followed by 'def"' @@ -801,186 +846,208 @@ impl Committed for AnyTokenParser where I: Iterator // TODO(ajeffrey): make this code generic. #[derive(Copy, Clone, Debug)] -pub struct BufferedParser

(P); - -impl

Parser for BufferedParser

{} -impl<'a, P> Uncommitted<&'a str> for BufferedParser

where P: Uncommitted<&'a str> -{ - type Output = Cow<'a,str>; - type State = BufferedStatefulParser; - fn parse(&self, value: &'a str) -> MaybeParseResult { - match self.0.parse(value) { - Empty(rest) => Empty(rest), - Commit(Done(rest, _)) => { - Commit(Done(rest, Borrowed(&value[..(value.len() - rest.len())]))) - } - Commit(Continue(rest, parsing)) => { - Commit(Continue(rest, BufferedStatefulParser(parsing, String::from(value)))) - } - Abort(value) => Abort(value), +pub struct Buffered

(P); + +impl

Parser for Buffered

where P: Parser {} + +impl<'a, P> Uncommitted> for Buffered

+ where P: Uncommitted>, +{ + type Output = Cow<'a, str>; + type State = BufferedState; + + fn init(&self, string: &mut Chars<'a>) -> Option> { + let string0 = string.as_str(); + match self.0.init(string) { + Some(Done(_)) => Some(Done(Borrowed(&string0[..(string0.len() - string.as_str().len())]))), + Some(Continue(state)) => Some(Continue(BufferedState(state, String::from(string0)))), + None => None, } } } -impl<'a, P> Committed<&'a str> for BufferedParser

where P: Committed<&'a str> + +impl<'a, P> Committed> for Buffered

+ where P: Committed>, { - type Output = Cow<'a,str>; - type State = BufferedStatefulParser; - fn init(&self) -> Self::State { - BufferedStatefulParser(self.0.init(), String::new()) - } + fn empty(&self) -> Cow<'a, str> { Borrowed("") } } -impl

BufferedParser

{ +impl

Buffered

{ pub fn new(parser: P) -> Self { - BufferedParser(parser) + Buffered(parser) } } #[derive(Clone,Debug)] -pub struct BufferedStatefulParser

(P, String); +pub struct BufferedState

(P, String); -impl<'a, P> Stateful<&'a str> for BufferedStatefulParser

where P: Stateful<&'a str> +impl<'a, P> Stateful> for BufferedState

+ where P: Stateful> { - type Output = Cow<'a,str>; - fn parse(mut self, value: &'a str) -> ParseResult { - match self.0.parse(value) { - Done(rest, _) if self.1.is_empty() => { - Done(rest, Borrowed(&value[..(value.len() - rest.len())])) - } - Done(rest, _) => { - self.1.push_str(&value[..(value.len() - rest.len())]); - Done(rest, Owned(self.1)) - } - Continue(rest, parsing) => { - self.1.push_str(value); - Continue(rest, BufferedStatefulParser(parsing, self.1)) - } + + type Output = Cow<'a, str>; + + fn more(mut self, string: &mut Chars<'a>) -> ParseResult { + let string0 = string.as_str(); + match self.0.more(string) { + Done(_) => { + self.1.push_str(&string0[..(string0.len() - string.as_str().len())]); + Done(Owned(self.1)) + }, + Continue(state) => { + self.1.push_str(string0); + Continue(BufferedState(state, self.1)) + }, } } + fn done(self) -> Self::Output { Owned(self.1) } + } // ----------- Parsers which are boxable ------------- #[derive(Debug)] -pub struct BoxableParser

(Option

); -impl Boxable for BoxableParser

where P: Stateful +pub struct BoxableState

(Option

); + +impl Boxable for BoxableState

+ where P: Stateful, + Str: Iterator, { type Output = P::Output; - fn parse_boxable(&mut self, value: S) -> (S, Option) { - match self.0.take().unwrap().parse(value) { - Done(rest, result) => (rest, Some(result)), - Continue(rest, parsing) => { - self.0 = Some(parsing); - (rest, None) + fn more_boxable(&mut self, string: &mut Str) -> ParseResult<(), P::Output> { + match self.0.take().unwrap().more(string) { + Done(result) => Done(result), + Continue(state) => { + self.0 = Some(state); + Continue(()) } } } - fn done_boxable(&mut self) -> Self::Output { + fn done_boxable(&mut self) -> P::Output { self.0.take().unwrap().done() } } -impl Stateful for Box

where P: Boxable +impl Stateful for Box

+ where P: Boxable, + Str: Iterator, { - type Output = P::Output; - fn parse(mut self, value: S) -> ParseResult { - match self.parse_boxable(value) { - (rest, Some(result)) => Done(rest, result), - (rest, None) => Continue(rest, self), + type Output = Output; + fn more(mut self, string: &mut Str) -> ParseResult { + match self.more_boxable(string) { + Done(result) => Done(result), + Continue(()) => Continue(self), } } - fn done(mut self) -> Self::Output { + fn done(mut self) -> Output { self.done_boxable() } } -impl

BoxableParser

{ +impl

BoxableState

{ pub fn new(parser: P) -> Self { - BoxableParser(Some(parser)) - } -} - -// ----------- Iterate over parse results ------------- - -#[derive(Copy, Clone, Debug)] -pub struct IterParser(P, Option<(Q, S)>); - -impl Iterator for IterParser where P: Copy + Committed -{ - type Item = P::Output; - fn next(&mut self) -> Option { - let (state, result) = match self.1.take() { - None => (None, None), - Some((parsing, data)) => { - match parsing.parse(data) { - Done(rest, result) => (Some((self.0.init(), rest)), Some(result)), - Continue(rest, parsing) => (Some((parsing, rest)), None), - } - } - }; - *self = IterParser(self.0, state); - result - } -} - -impl IterParser where P: Copy + Committed -{ - pub fn new(parser: P, data: S) -> Self { - IterParser(parser, Some((parser.init(), data))) - } -} - -// ----------- Pipe parsers ------------- - -#[derive(Copy, Clone, Debug)] -pub struct PipeStateful(P, Q, R); - -impl Stateful for PipeStateful - where P: Copy + Committed, - Q: for<'a> Stateful>, Output = T> -{ - type Output = T; - fn parse(self, data: S) -> ParseResult { - let mut iter = IterParser(self.0, Some((self.1, data))); - match self.2.parse(iter.by_ref().peekable()) { - Done(_, result) => Done(iter.1.unwrap().1, result), - Continue(_, parsing2) => { - let (parsing1, data) = iter.1.unwrap(); - Continue(data, PipeStateful(self.0, parsing1, parsing2)) - } - } - } - fn done(self) -> T { - // TODO: feed the output of self.1.done() into self.2. - self.1.done(); - self.2.done() - } -} - -#[derive(Copy, Clone, Debug)] -pub struct PipeParser(P, Q); - -impl Parser for PipeParser {} -impl Committed for PipeParser - where P: Copy + Committed, - Q: for<'a> Committed>, - State = R, - Output = T>, - R: for<'a> Stateful>, Output = T> -{ - type State = PipeStateful; - type Output = T; - fn init(&self) -> Self::State { - PipeStateful(self.0, self.0.init(), self.1.init()) - } -} - -impl PipeParser { - pub fn new(lhs: P, rhs: Q) -> Self { - PipeParser(lhs, rhs) - } -} + BoxableState(Some(parser)) + } +} + +// // ----------- Iterate over parse results ------------- + +// #[derive(Copy, Clone, Debug)] +// pub struct IterParser(P, Option<(Q, S)>); + +// impl Iterator for IterParser +// where P: Copy + Committed, +// Str: IntoPeekable, +// Str::Item: ToStatic, +// P::State: Stateful, +// { +// type Item = >::Output; +// fn next(&mut self) -> Option { +// let (state, result) = match self.1.take() { +// None => (None, None), +// Some((parsing, data)) => { +// match parsing.parse(data) { +// Done(rest, result) => (Some((self.0.init(), rest)), Some(result)), +// Continue(rest, parsing) => (Some((parsing, rest)), None), +// } +// } +// }; +// *self = IterParser(self.0, state); +// result +// } +// } + +// impl IterParser +// where P: Copy + Committed, +// Str: IntoPeekable, +// Str::Item: ToStatic, +// { +// pub fn new(parser: P, data: Str) -> Self { +// IterParser(parser, Some((parser.init(), data))) +// } +// } + +// // ----------- Pipe parsers ------------- + +// TODO: restore these + +// #[derive(Copy, Clone, Debug)] +// pub struct PipeStateful(P, Q, R); + +// impl Stateful for PipeStateful +// where P: Copy + Committed, +// Q: Stateful>>, +// Str: IntoPeekable, +// Str::Item: ToStatic, +// P::State: Stateful, +// { +// type Output = Q::Output; +// fn parse(self, data: Str) -> ParseResult { +// let iterator = Peekable::new(IterParser(self.0, Some((self.1, data)))); +// match self.2.parse(iterator) { +// Done(rest, result) => Done(rest.iter.1.unwrap().1, result), +// Continue(rest, parsing2) => { +// let (parsing1, data) = rest.iter.1.unwrap(); +// Continue(data, PipeStateful(self.0, parsing1, parsing2)) +// } +// } +// } +// fn done(self) -> Q::Output { +// // TODO: feed the output of self.1.done() into self.2. +// self.1.done(); +// self.2.done() +// } +// } + +// #[derive(Copy, Clone, Debug)] +// pub struct PipeParser(P, Q); + +// impl Parser for PipeParser +// where P: 'static + Parser, +// Q: Parser, +// { +// type State = PipeStateful; +// type StaticOutput = Q::StaticOutput; +// } + +// impl Committed for PipeParser +// where P: 'static + Copy + Committed, +// Q: for<'a> Committed>>, +// Str: IntoPeekable, +// Str::Item: ToStatic, +// P::State: Stateful, +// { +// fn init(&self) -> Self::State { +// PipeStateful(self.0, self.0.init(), self.1.init()) +// } +// } + +// impl PipeParser { +// pub fn new(lhs: P, rhs: Q) -> Self { +// PipeParser(lhs, rhs) +// } +// } diff --git a/src/lib.rs b/src/lib.rs index b9419e7..8036967 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,29 +19,32 @@ #![feature(unboxed_closures)] -use self::MaybeParseResult::{Empty, Abort, Commit}; use self::ParseResult::{Done, Continue}; -use std::fmt::{Formatter, Debug}; use std::borrow::Cow; +use std::str::Chars; +use std::iter::Peekable; pub mod impls; - // ----------- Types for parsers ------------ /// A trait for stateful parsers. /// -/// Stateful parsers are typically constructed by calling the `init` method of a stateless parser, +/// Stateful parsers are typically constructed by calling an `init` method of a stateless parser, /// for example: /// /// ``` -/// # use parsell::{character,Parser,Uncommitted,Committed}; +/// # use parsell::{character,Parser,Uncommitted,UncommittedStr,Committed,Stateful}; +/// # use parsell::ParseResult::{Continue,Done}; /// let stateless = character(char::is_alphanumeric).star(String::new); -/// let stateful = stateless.init(); +/// match stateless.init_str("abc").unwrap() { +/// Continue(stateful) => (), +/// _ => panic!("Can't happen"), +/// } /// ``` /// -/// Here, `stateless` is a `Committed<&str,Output=String>`, and `stateful` is a `Stateful<&str,Output=String>`. +/// Here, `stateless` is a `Committed>`, and `stateful` is a `Stateful>`. /// /// The reason for distinguishing between stateful and stateless parsers is that /// stateless parsers are usually copyable, whereas stateful parsers are usually not @@ -49,29 +52,30 @@ pub mod impls; /// Copying parsers is quite common, for example: /// /// ``` -/// # use parsell::{character,CHARACTER,Uncommitted,Parser,Committed,Stateful}; +/// # use parsell::{character,CHARACTER,Uncommitted,UncommittedStr,Parser,Committed,Stateful}; /// # use parsell::ParseResult::Done; /// fn mk_err(_: Option) -> Result { Err(String::from("Expecting a digit")) } /// let DIGIT = character(char::is_numeric).map(Ok).or_else(CHARACTER.map(mk_err)); /// let TWO_DIGITS = DIGIT.try_and_then_try(DIGIT); -/// match TWO_DIGITS.init().parse("123") { -/// Done("3",result) => assert_eq!(result,Ok(('1','2'))), +/// match TWO_DIGITS.init_str("123").unwrap() { +/// Done(result) => assert_eq!(result, Ok(('1','2'))), /// _ => panic!("Can't happen"), /// } /// ``` -pub trait Stateful { - +pub trait Stateful + where Str: Iterator, +{ + /// The type of the data being produced by the parser. type Output; /// Provides data to the parser. /// - /// If `parser: Stateful`, then `parser.parse(data)` either: + /// If `parser: Stateful` and `data: Str`, then `parser.parse(&mut data)` either: /// - /// * returns `Done(rest, result)` where `rest: S` is any remaining input, - /// and `result: T` is the parsed output, or - /// * returns `Continue(rest,parsing)` where `parsing: Self` is the new state of the parser. + /// * returns `Done(result)` where and `result: Self::Output` is the parsed output, or + /// * returns `Continue(parsing)` where `parsing: Self` is the new state of the parser. /// /// For example: /// @@ -79,43 +83,42 @@ pub trait Stateful { /// # use parsell::{character,Parser,Uncommitted,Committed,Stateful}; /// # use parsell::ParseResult::{Continue,Done}; /// let parser = character(char::is_alphabetic).star(String::new); - /// let stateful = parser.init(); - /// match stateful.parse("abc") { - /// Continue("",parsing) => match parsing.parse("def!") { - /// Done("!",result) => assert_eq!(result,"abcdef"), + /// let data1 = "ab"; + /// let data2 = "cd"; + /// let data3 = "ef!"; + /// match parser.init(&mut data1.chars()).unwrap() { + /// Continue(stateful) => match stateful.more(&mut data2.chars()) { + /// Continue(stateful) => match stateful.more(&mut data3.chars()) { + /// Done(result) => assert_eq!(result, "abcdef"), + /// _ => panic!("can't happen"), + /// }, /// _ => panic!("can't happen"), /// }, /// _ => panic!("can't happen"), /// } /// ``` /// - /// Note that `parser.parse(data)` consumes both the `parser` and the `data`. In particular, - /// the `parser` is no longer available, so the following does not typecheck: - /// - /// ```text - /// let parser = character(char::is_alphabetic).star(String::new); - /// let stateful = parser.init(); - /// stateful.parse("abc"); - /// stateful.parse("def!"); - /// ``` - /// - /// This helps with parser safety, as it stops a client from calling `parse` after a - /// a stateful parser has finished. - fn parse(self, value: S) -> ParseResult where Self: Sized; + /// Note that `parser.parse(data)` consumes the `parser`, but borrows the `data` + /// mutably. + + fn more(self, string: &mut Str) -> ParseResult + where Self: Sized; /// Tells the parser that it will not receive any more data. /// - /// If `parser: Stateful`, then `parser.done()` returns a result of type `T` + /// If `parser: Stateful`, then `parser.done()` returns a result of type `T` /// for example: /// /// ``` /// # use parsell::{character,Parser,Uncommitted,Committed,Stateful}; /// # use parsell::ParseResult::{Continue,Done}; /// let parser = character(char::is_alphabetic).star(String::new); - /// let stateful = parser.init(); - /// match stateful.parse("abc") { - /// Continue("",parsing) => match parsing.parse("def") { - /// Continue("",parsing) => assert_eq!(parsing.done(),"abcdef"), + /// let data1 = "ab"; + /// let data2 = "cd"; + /// let data3 = "ef"; + /// match parser.init(&mut data1.chars()).unwrap() { + /// Continue(stateful) => match stateful.more(&mut data2.chars()) { + /// Continue(stateful) => assert_eq!(stateful.last(&mut data3.chars()), "abcdef"), /// _ => panic!("can't happen"), /// }, /// _ => panic!("can't happen"), @@ -127,70 +130,109 @@ pub trait Stateful { /// /// ```text /// let parser = character(char::is_alphabetic).star(String::new); - /// let stateful = parser.init(); - /// stateful.done(); - /// stateful.parse("def!"); + /// match parser.init_str("abc").unwrap() { + /// Continue(parsing) => { + /// parsing.done(); + /// parsing.more_str("def!"); + /// } + /// } /// ``` /// - /// This helps with parser safety, as it stops a client from calling `parse` after a - /// a stateful parser has finished. - fn done(self) -> Self::Output where Self: Sized; + /// This helps with parser safety, as it stops a client from calling `more` after + /// `done`. + + fn done(self) -> Self::Output + where Self: Sized; - /// Make this parser boxable. - fn boxable(self) -> impls::BoxableParser + /// Provides the last data to the parser. + /// + /// If `parser: Stateful` and `data: Str`, then `parser.last(&mut data)` + /// calls `parser.more(&mut data)`, then calls `done()` if the parser continues. + + fn last(self, string: &mut Str) -> Self::Output where Self: Sized { - impls::BoxableParser::new(self) + match self.more(string) { + Continue(parsing) => parsing.done(), + Done(result) => result, + } } } -/// The result of a parse. -pub enum ParseResult - where P: Stateful -{ - /// The parse is finished. - Done(S, P::Output), - /// The parse can continue. - Continue(S, P), -} +/// A trait for stateful string parsers. -// Implement Debug for ParseResult without requiring P: Debug +pub trait StatefulStr<'a>: Stateful> { -impl Debug for ParseResult - where P: Stateful, - S: Debug, - P::Output: Debug, -{ - fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - match self { - &Done(ref rest, ref result) => write!(fmt, "Done({:?}, {:?})", rest, result), - &Continue(ref rest, _) => write!(fmt, "Continue({:?}, ...)", rest), - } + /// Provides a string to the parser. + /// + /// If `parser: Stateful>` and `data: &'a str`, then `parser.more_str(data)` + /// is short-hand for `parser.more(&mut data.chars())`. + /// + /// For example: + /// + /// ``` + /// # use parsell::{character,Parser,Uncommitted,UncommittedStr,Committed,Stateful,StatefulStr}; + /// # use parsell::ParseResult::{Continue,Done}; + /// let parser = character(char::is_alphabetic).star(String::new); + /// match parser.init_str("ab").unwrap() { + /// Continue(stateful) => match stateful.more_str("cd") { + /// Continue(stateful) => match stateful.more_str("ef!") { + /// Done(result) => assert_eq!(result, "abcdef"), + /// _ => panic!("can't happen"), + /// }, + /// _ => panic!("can't happen"), + /// }, + /// _ => panic!("can't happen"), + /// } + /// ``` + + fn more_str(self, string: &'a str) -> ParseResult + where Self: Sized, + { + self.more(&mut string.chars()) } -} -impl ParseResult where P: Stateful -{ - /// Apply a function the the `Continue` branch of a parse result. - pub fn map(self, f: F) -> ParseResult - where Q: Stateful, - F: Function + /// Provides the last string to the parser. + /// + /// If `parser: Stateful>` and `data: &'a str`, then `parser.last_str(data)` + /// is short-hand for `parser.last(&mut data.chars())`. + /// + /// For example: + /// + /// ``` + /// # use parsell::{character,Parser,Uncommitted,UncommittedStr,Committed,Stateful,StatefulStr}; + /// # use parsell::ParseResult::{Continue,Done}; + /// let parser = character(char::is_alphabetic).star(String::new); + /// match parser.init_str("ab").unwrap() { + /// Continue(parsing) => match parsing.more_str("cd") { + /// Continue(parsing) => assert_eq!(parsing.last_str("ef"),"abcdef"), + /// _ => panic!("can't happen"), + /// }, + /// _ => panic!("can't happen"), + /// } + /// ``` + + fn last_str(self, string: &'a str) -> Self::Output + where Self: Sized, { - match self { - Done(rest, result) => Done(rest, result), - Continue(rest, parsing) => Continue(rest, f.apply(parsing)), - } + self.last(&mut string.chars()) } + } -impl PartialEq for ParseResult where S: PartialEq, P: Stateful, P::Output: PartialEq { - fn eq(&self, other: &ParseResult) -> bool { - match (self, other) { - (&Done(ref rest1, ref result1), &Done(ref rest2, ref result2)) => (rest1 == rest2) && (result1 == result2), - _ => false, - } - } +impl<'a, P> StatefulStr<'a> for P where P: Stateful> {} + +/// The result of parsing +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum ParseResult { + + /// The parse is finished. + Done(Output), + + /// The parse can continue. + Continue(State), + } /// A trait for stateless parsers. @@ -204,136 +246,137 @@ impl PartialEq for ParseResult where S: PartialEq, P: Stateful, P: pub trait Parser { /// Choice between parsers - fn or_else

(self, other: P) -> impls::OrElseParser - where Self: Sized + fn or_else

(self, other: P) -> impls::OrElse + where Self: Sized, + P: Parser, { - impls::OrElseParser::new(self, other) + impls::OrElse::new(self, other) } /// Sequencing with a committed parser - fn and_then

(self, other: P) -> impls::AndThenParser - where Self: Sized + fn and_then

(self, other: P) -> impls::AndThen + where Self: Sized, + P: Parser, { - impls::AndThenParser::new(self, other) + impls::AndThen::new(self, other) } /// Sequencing with a committed parser (bubble any errors from this parser). - fn try_and_then

(self, - other: P) - -> impls::MapParser, impls::TryZip> - where Self: Sized + fn try_and_then

(self, other: P) -> impls::Map, impls::TryZip> + where Self: Sized, + P: Parser, { self.and_then(other).map(impls::TryZip) } /// Sequencing with a committed parser (bubble any errors from that parser). - fn and_then_try

(self, - other: P) - -> impls::MapParser, impls::ZipTry> - where Self: Sized + fn and_then_try

(self, other: P) -> impls::Map, impls::ZipTry> + where Self: Sized, + P: Parser, { self.and_then(other).map(impls::ZipTry) } /// Sequencing with a committed parser (bubble any errors from either parser). - fn try_and_then_try

(self, - other: P) - -> impls::MapParser, impls::TryZipTry> - where Self: Sized + fn try_and_then_try

(self, other: P) -> impls::Map, impls::TryZipTry> + where Self: Sized, + P: Parser, { self.and_then(other).map(impls::TryZipTry) } /// Iterate one or more times (returns an uncommitted parser). - fn plus(self, factory: F) -> impls::PlusParser - where Self: Sized + fn plus(self, factory: F) -> impls::Plus + where Self: Sized, + F: Factory, { - impls::PlusParser::new(self, factory) + impls::Plus::new(self, factory) } /// Iterate zero or more times (returns a committed parser). - fn star(self, factory: F) -> impls::StarParser - where Self: Sized + fn star(self, factory: F) -> impls::Star + where Self: Sized, + F: Factory, { - impls::StarParser::new(self, factory) + impls::Star::new(self, factory) } /// Apply a function to the result - fn map(self, f: F) -> impls::MapParser - where Self: Sized + fn map(self, f: F) -> impls::Map + where Self: Sized, { - impls::MapParser::new(self, f) + impls::Map::new(self, f) } /// Apply a 2-arguent function to the result - fn map2(self, f: F) -> impls::MapParser> - where Self: Sized + fn map2(self, f: F) -> impls::Map> + where Self: Sized, { - impls::MapParser::new(self, impls::Function2::new(f)) + impls::Map::new(self, impls::Function2::new(f)) } /// Apply a 3-arguent function to the result - fn map3(self, f: F) -> impls::MapParser> - where Self: Sized + fn map3(self, f: F) -> impls::Map> + where Self: Sized, { - impls::MapParser::new(self, impls::Function3::new(f)) + impls::Map::new(self, impls::Function3::new(f)) } /// Apply a 4-arguent function to the result - fn map4(self, f: F) -> impls::MapParser> - where Self: Sized + fn map4(self, f: F) -> impls::Map> + where Self: Sized, { - impls::MapParser::new(self, impls::Function4::new(f)) + impls::Map::new(self, impls::Function4::new(f)) } /// Apply a 5-arguent function to the result - fn map5(self, f: F) -> impls::MapParser> - where Self: Sized + fn map5(self, f: F) -> impls::Map> + where Self: Sized, { - impls::MapParser::new(self, impls::Function5::new(f)) + impls::Map::new(self, impls::Function5::new(f)) } /// Apply a function to the result (bubble any errors). - fn try_map(self, f: F) -> impls::MapParser> + fn try_map(self, f: F) -> impls::Map> where Self: Sized { self.map(impls::Try::new(f)) } /// Apply a 2-argument function to the result (bubble any errors). - fn try_map2(self, f: F) -> impls::MapParser>> + fn try_map2(self, f: F) -> impls::Map>> where Self: Sized { self.try_map(impls::Function2::new(f)) } /// Apply a 3-argument function to the result (bubble any errors). - fn try_map3(self, f: F) -> impls::MapParser>> + fn try_map3(self, f: F) -> impls::Map>> where Self: Sized { self.try_map(impls::Function3::new(f)) } /// Apply a 4-argument function to the result (bubble any errors). - fn try_map4(self, f: F) -> impls::MapParser>> + fn try_map4(self, f: F) -> impls::Map>> where Self: Sized { self.try_map(impls::Function4::new(f)) } /// Apply a 5-argument function to the result (bubble any errors). - fn try_map5(self, f: F) -> impls::MapParser>> + fn try_map5(self, f: F) -> impls::Map>> where Self: Sized { self.try_map(impls::Function5::new(f)) } - /// Take the results of iterating this parser, and feed it into another parser. - fn pipe

(self, other: P) -> impls::PipeParser - where Self: Sized - { - impls::PipeParser::new(self, other) - } + // /// Take the results of iterating this parser, and feed it into another parser. + // fn pipe

(self, other: P) -> impls::PipeParser + // where Self: Sized + // { + // impls::PipeParser::new(self, other) + // } /// A parser which produces its input. /// @@ -344,34 +387,33 @@ pub trait Parser { /// /// ``` /// # use parsell::{character,Parser,Uncommitted,Stateful}; - /// # use parsell::MaybeParseResult::{Commit}; /// # use parsell::ParseResult::{Done,Continue}; /// # use std::borrow::Cow::{Borrowed,Owned}; /// fn ignore() {} /// let parser = character(char::is_alphabetic).plus(ignore).buffer(); - /// match parser.parse("abc!") { - /// Commit(Done("!",result)) => assert_eq!(result,Borrowed("abc")), + /// match parser.init(&mut "abc!".chars()).unwrap() { + /// Done(Borrowed(result)) => assert_eq!(result,"abc"), /// _ => panic!("can't happen"), /// } - /// match parser.parse("abc") { - /// Commit(Continue("",parsing)) => match parsing.parse("def!") { - /// Done("!",result) => assert_eq!(result,Owned::<'static,str>(String::from("abcdef"))), + /// match parser.init(&mut "abc".chars()).unwrap() { + /// Continue(parsing) => match parsing.more(&mut "def!".chars()) { + /// Done(Owned(result)) => assert_eq!(result,"abcdef"), /// _ => panic!("can't happen"), /// }, /// _ => panic!("can't happen"), /// } /// ``` - fn buffer(self) -> impls::BufferedParser + fn buffer(self) -> impls::Buffered where Self: Sized { - impls::BufferedParser::new(self) + impls::Buffered::new(self) } } /// A trait for committed parsers. /// -/// A parser is committed if it is guaranteed not to backtrack. +/// A parser is committed if it is guaranteed only to backtrack on empty input. /// Committed parsers are typically constructed by calling the methods of the library, /// for example: /// @@ -380,7 +422,7 @@ pub trait Parser { /// let parser = character(char::is_alphanumeric).star(String::new); /// ``` /// -/// Here, `parser` is a `Committed<&str,Output=String>`. +/// Here, `parser` is a `Committed, Output=String>`. /// /// The reason for distinguishing between committed and uncommitted parsers /// is that the library is designed for LL(1) grammars, that only use one token @@ -392,38 +434,13 @@ pub trait Parser { /// whose domain is prefix-closed (that is, if *s·t* is in the domain, then *s* is in the domain) /// and non-empty. -pub trait Committed: Parser { - - /// The type of the data being produced by the parser. - type Output; - - /// The type of the parser state. - type State: Stateful; - - /// Create a stateful parser by initializing a stateless parser. - fn init(&self) -> Self::State; - - /// Build an iterator from a parser and some data. - fn iter(self, data: S) -> impls::IterParser - where Self: Sized + Copy - { - impls::IterParser::new(self, data) - } - - /// Short hand for calling init then parse. - fn init_parse(&self, data: S) -> ParseResult - where Self: Sized - { - self.init().parse(data) - } - - /// Short hand for calling init then done. - fn init_done(&self) -> Self::Output - where Self: Sized - { - self.init().done() - } +pub trait Committed: Uncommitted + where Str: Iterator, +{ + /// Parse an EOF. + fn empty(&self) -> Self::Output; + } /// A trait for uncommitted parsers. @@ -436,23 +453,23 @@ pub trait Committed: Parser { /// will then try `q`. For example: /// /// ``` -/// # use parsell::{character,CHARACTER,Parser,Uncommitted,Committed,Stateful}; +/// # use parsell::{character,CHARACTER,Parser,Uncommitted,UncommittedStr,Committed,Stateful}; /// # use parsell::ParseResult::Done; /// fn default(_: Option) -> String { String::from("?") } /// let parser = /// character(char::is_numeric).plus(String::new) /// .or_else(character(char::is_alphabetic).plus(String::new)) /// .or_else(CHARACTER.map(default)); -/// match parser.init().parse("123abc") { -/// Done("abc",result) => assert_eq!(result,"123"), +/// match parser.init_str("123abc").unwrap() { +/// Done(result) => assert_eq!(result, "123"), /// _ => panic!("Can't happen"), /// } -/// match parser.init().parse("abc123") { -/// Done("123",result) => assert_eq!(result,"abc"), +/// match parser.init_str("abc123").unwrap() { +/// Done(result) => assert_eq!(result, "abc"), /// _ => panic!("Can't happen"), /// } -/// match parser.init().parse("!@#") { -/// Done("@#",result) => assert_eq!(result,"?"), +/// match parser.init_str("!@#").unwrap() { +/// Done(result) => assert_eq!(result, "?"), /// _ => panic!("Can't happen"), /// } /// ``` @@ -460,330 +477,255 @@ pub trait Committed: Parser { /// Semantically, a parser with input *S* and output *T* is a partial function *S\+ → T* /// whose domain is prefix-closed (that is, if *s·t* is in the domain, then *s* is in the domain). -pub trait Uncommitted: Parser { +pub trait Uncommitted + where Str: Iterator, +{ - /// The type of the data being produced by the parser. type Output; + type State: 'static + Stateful; - /// The type of the parser state. - type State: Stateful; + /// Parse a string of data. + fn init(&self, string: &mut Str) -> Option>; - /// Provides data to the parser. - /// - /// If `parser: Uncommitted`, then `parser.parse(data)` either: +} + +/// A trait for uncommitted string parsers. + +pub trait UncommittedStr<'a>: Uncommitted> { + + /// Provides string data to the parser. /// - /// * returns `Empty(data)` because `data` was empty, - /// * returns `Abort(data)` because the parser should backtrack, or - /// * returns `Commit(result)` because the parser has committed. + /// If `parser: Uncommitted>` and `data: &'a str`, then `parser.init_str(data)` + /// is short-hand for `parser.init(&mut data.chars())`. /// /// For example: /// /// ``` - /// # use parsell::{character,Parser,Uncommitted,Stateful}; - /// # use parsell::MaybeParseResult::{Empty,Commit,Abort}; - /// # use parsell::ParseResult::{Done,Continue}; - /// let parser = character(char::is_alphabetic).plus(String::new); - /// match parser.parse("") { - /// Empty("") => (), - /// _ => panic!("can't happen"), - /// } - /// match parser.parse("!abc") { - /// Abort("!abc") => (), - /// _ => panic!("can't happen"), - /// } - /// match parser.parse("abc!") { - /// Commit(Done("!",result)) => assert_eq!(result,"abc"), - /// _ => panic!("can't happen"), - /// } - /// match parser.parse("abc") { - /// Commit(Continue("",parsing)) => match parsing.parse("def!") { - /// Done("!",result) => assert_eq!(result,"abcdef"), + /// # use parsell::{character,Parser,Uncommitted,UncommittedStr,Committed,Stateful,StatefulStr}; + /// # use parsell::ParseResult::{Continue,Done}; + /// let parser = character(char::is_alphabetic).star(String::new); + /// match parser.init_str("ab").unwrap() { + /// Continue(stateful) => match stateful.more_str("cd") { + /// Continue(stateful) => match stateful.more_str("ef!") { + /// Done(result) => assert_eq!(result, "abcdef"), + /// _ => panic!("can't happen"), + /// }, /// _ => panic!("can't happen"), /// }, /// _ => panic!("can't happen"), /// } /// ``` - /// - /// Note that the decision to commit or abort must be made on the first - /// token of data (since the parser only retries on empty input) - /// so this is appropriate for LL(1) grammars that only perform one token - /// of lookahead. - fn parse(&self, value: S) -> MaybeParseResult where Self: Sized; - -} - -/// The result of a parse. -pub enum MaybeParseResult - where P: Stateful -{ - /// The input was empty. - Empty(S), - /// The parser must backtrack. - Abort(S), - /// The parser has committed to parsing the input. - Commit(ParseResult), -} -impl MaybeParseResult where P: Stateful -{ - /// Apply a function the the Commit branch of a parse result - pub fn map(self, f: F) -> MaybeParseResult - where Q: Stateful, - F: Function + fn init_str(&self, string: &'a str) -> Option> + where Self: Sized, { - match self { - Empty(rest) => Empty(rest), - Abort(s) => Abort(s), - Commit(c) => Commit(c.map(f)), - } + self.init(&mut string.chars()) } -} - -// Implement Debug for MaybeParseResult without requiring P: Debug -impl Debug for MaybeParseResult - where P: Stateful, - S: Debug, - P::Output: Debug, -{ - fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result { - match self { - &Empty(ref rest) => write!(fmt, "Empty({:?})", rest), - &Abort(ref rest) => write!(fmt, "Abort({:?})", rest), - &Commit(ref result) => write!(fmt, "Commit({:?})", result), - } - } } -impl PartialEq for MaybeParseResult where S: PartialEq, P: Stateful, P::Output: PartialEq { - fn eq(&self, other: &MaybeParseResult) -> bool { - match (self, other) { - (&Empty(ref rest1), &Empty(ref rest2)) => (rest1 == rest2), - (&Abort(ref rest1), &Abort(ref rest2)) => (rest1 == rest2), - (&Commit(ref result1), &Commit(ref result2)) => (result1 == result2), - _ => false, - } - } -} +impl<'a, P> UncommittedStr<'a> for P where P: Uncommitted> {} /// A trait for boxable parsers. -/// -/// Regular languages can be parsed in constant memory, so do not require any heap allocation (other than -/// the heap allocation peformed by user code such as creating buffers). Context-free languages require -/// allocating unbounded memory. In order to support streaming input, the state of the parser must be -/// saved on the heap, and restored when more input arrives. -/// -/// In Rust, heap-allocated data is often kept in a `Box`, where `T` is a trait. In the case -/// of parsers, the library needs to save and restore a stateful parser, for which the obvious -/// type is `Box`. There are two issues with this... -/// -/// Firstly, the lifetimes mentioned in the type of the parser may change over time. -/// For example, the program: -/// -/// ```text -/// fn check_results (self, rest: &'b str, result: String) { -/// assert_eq!(rest,"!"); assert_eq!(result,"abc123"); -/// } -/// let parser = character(char::is_alphanumeric).star(String::new); -/// let stateful = parser.init(); -/// let boxed: Box> = Box::new(stateful); -/// let stuff: &'b str = "abc123!"; -/// match boxed.parse(stuff) { -/// Done(rest,result) => self.check_results(rest,result), -/// _ => println!("can't happen"), -/// } -/// ``` -/// -/// does not typecheck, because the type of `boxed` is fixed as containing parsers for input `&'a str`, -/// but it was fed input of type `&'b str`. To fix this, we change the type of the box to be -/// polymorphic in the lifetime of the parser: -/// -/// ```text -/// fn check_results (self, rest: &'b str, result: String) { -/// assert_eq!(rest,"!"); assert_eq!(result,"abc123"); -/// } -/// let parser = character(char::is_alphanumeric).star(String::new); -/// let stateful = parser.init(); -/// let boxed: Box Stateful<&'a str,Output=String>> = Box::new(stateful); -/// let stuff: &'b str = "abc123!"; -/// match boxed.parse(stuff) { -/// Done(rest,result) => self.check_results(rest,result), -/// _ => println!("can't happen"), -/// } -/// ``` -/// -/// Secondly, the `Stateful` trait is not -/// [object-safe](https://doc.rust-lang.org/book/trait-objects.html#object-safety), -/// so cannot be boxed and unboxed safely. In order to address this, there is a trait -/// `Boxable`, which represents stateful parsers, but is object-safe -/// and so can be boxed and unboxed safely: -/// -/// ``` -/// # struct Foo<'a>(&'a str); -/// # impl<'b> Foo<'b> { -/// fn check_results (self, rest: &'b str, result: String) { -/// assert_eq!(rest,"!"); assert_eq!(result,"abc123"); -/// } -/// # fn foo(self) { -/// # use parsell::{character,Parser,Uncommitted,Committed,Boxable,Stateful}; -/// # use parsell::ParseResult::{Done,Continue}; -/// let parser = character(char::is_alphanumeric).star(String::new); -/// let stateful = parser.init(); -/// let boxed: Box Boxable<&'a str,Output=String>> = Box::new(stateful.boxable()); -/// let stuff: &'b str = "abc123!"; -/// match boxed.parse(stuff) { -/// Done(rest,result) => self.check_results(rest,result), -/// _ => println!("can't happen"), -/// } -/// # } } -/// ``` -/// -/// The type `Box>` implements the trait -/// `Stateful`, so boxes can be used as parsers, -/// which allows stateful parsers to heap-allocate their state. -/// -/// Boxable parsers are usually used in recursive-descent parsing, -/// for context-free grammars that cannot be parsed as a regular language. -/// For example, consider a simple type for trees: -/// -/// ``` -/// # use parsell::{Owned}; -/// struct Tree(Vec); -/// impl Owned for Tree {} -/// ``` -/// -/// which can be parsed from a well-nested sequence of parentheses, for example -/// `(()())` can be parsed as `Tree(vec![Tree(vec![]),Tree(vec![])])`. -/// The desired implementation is: -/// -/// ```text -/// fn is_lparen(ch: char) -> bool { ch == '(' } -/// fn is_rparen(ch: char) -> bool { ch == ')' } -/// fn mk_vec() -> Result,String> { Ok(Vec::new()) } -/// fn mk_ok(ok: T) -> Result { Ok(ok) } -/// fn mk_err(_: Option) -> Result { Err(String::from("Expected a ( or ).")) } -/// fn mk_tree(_: char, children: Vec, _: char) -> Tree { -/// Tree(children) -/// } -/// let LPAREN = character(is_lparen); -/// let RPAREN = character(is_rparen).map(mk_ok).or_else(CHARACTER.map(mk_err)); -/// let TREE = LPAREN -/// .and_then_try(TREE.star(mk_vec)) -/// .try_and_then_try(RPAREN) -/// .try_map3(mk_tree); -/// ``` -/// -/// but this doesn't work because it gives the definition of `TREE` in terms of itself, -/// and Rust doesn't allow this kind of cycle. -/// -/// Instead, the solution is to define a struct `TreeParser`, and then implement `Uncommitted<&str>` -/// for it. The type of the state of a `TreeParser` is a box containing an appropriate -/// `BoxableParserState` trait: -/// -/// ``` -/// # use parsell::{Boxable, Owned}; -/// # struct Tree(Vec); -/// # impl Owned for Tree {} -/// type TreeParserState = Box Boxable<&'b str, Output=Tree>>; -/// ``` -/// -/// The implementation of `Uncommitted<&str>` for `TreeParser` is mostly straightfoward: -/// -/// ``` -/// # use parsell::{character,CHARACTER,Parser,Uncommitted,Committed,Boxable,Stateful,MaybeParseResult,Owned}; -/// # use parsell::ParseResult::{Done,Continue}; -/// # use parsell::MaybeParseResult::{Commit}; -/// # #[derive(Eq,PartialEq,Clone,Debug)] -/// struct Tree(Vec); -/// impl Owned for Tree {} -/// # #[derive(Copy,Clone,Debug)] -/// struct TreeParser; -/// type TreeParserState = Box Boxable<&'b str, Output=Result>>; -/// impl Parser for TreeParser {} -/// impl<'a> Uncommitted<&'a str> for TreeParser { -/// type Output = Result; -/// type State = TreeParserState; -/// fn parse(&self, data: &'a str) -> MaybeParseResult { -/// // ... parser goes here...` -/// # fn is_lparen(ch: char) -> bool { ch == '(' } -/// # fn is_rparen(ch: char) -> bool { ch == ')' } -/// # fn mk_vec() -> Result,String> { Ok(Vec::new()) } -/// # fn mk_ok(ok: T) -> Result { Ok(ok) } -/// # fn mk_err(_: Option) -> Result { Err(String::from("Expected a ( or ).")) } -/// # fn mk_tree(_: char, children: Vec, _: char) -> Tree { -/// # Tree(children) -/// # } -/// # fn mk_box

(parser: P) -> TreeParserState -/// # where P: 'static+for<'a> Stateful<&'a str, Output=Result> { -/// # Box::new(parser.boxable()) -/// # } -/// # let LPAREN = character(is_lparen); -/// # let RPAREN = character(is_rparen).map(mk_ok).or_else(CHARACTER.map(mk_err)); -/// # let parser = LPAREN -/// # .and_then_try(TreeParser.star(mk_vec)) -/// # .try_and_then_try(RPAREN) -/// # .try_map3(mk_tree); -/// # parser.parse(data).map(mk_box) -/// } -/// } -/// ``` -/// -/// The important thing is that the definiton of `parse` can make use of `TREE`, so the parser can call itself -/// recursively, then box up the result state: -/// -/// ``` -/// # use parsell::{character,CHARACTER,Parser,Uncommitted,Committed,Boxable,Stateful,MaybeParseResult,Owned}; -/// # use parsell::ParseResult::{Done,Continue}; -/// # use parsell::MaybeParseResult::{Commit}; -/// # #[derive(Eq,PartialEq,Clone,Debug)] -/// struct Tree(Vec); -/// impl Owned for Tree {} -/// # #[derive(Copy,Clone,Debug)] -/// struct TreeParser; -/// type TreeParserState = Box Boxable<&'b str, Output=Result>>; -/// impl Parser for TreeParser {} -/// impl<'a> Uncommitted<&'a str> for TreeParser { -/// type Output = Result; -/// type State = TreeParserState; -/// fn parse(&self, data: &'a str) -> MaybeParseResult { -/// fn is_lparen(ch: char) -> bool { ch == '(' } -/// fn is_rparen(ch: char) -> bool { ch == ')' } -/// fn mk_vec() -> Result,String> { Ok(Vec::new()) } -/// fn mk_ok(ok: T) -> Result { Ok(ok) } -/// fn mk_err(_: Option) -> Result { Err(String::from("Expected a ( or ).")) } -/// fn mk_tree(_: char, children: Vec, _: char) -> Tree { -/// Tree(children) -/// } -/// fn mk_box

(parser: P) -> TreeParserState -/// where P: 'static+for<'a> Stateful<&'a str, Output=Result> { -/// Box::new(parser.boxable()) -/// } -/// let LPAREN = character(is_lparen); -/// let RPAREN = character(is_rparen).map(mk_ok).or_else(CHARACTER.map(mk_err)); -/// let parser = LPAREN -/// .and_then_try(TreeParser.star(mk_vec)) -/// .try_and_then_try(RPAREN) -/// .try_map3(mk_tree); -/// parser.parse(data).map(mk_box) -/// } -/// } -/// let TREE = TreeParser; -/// match TREE.parse("((") { -/// Commit(Continue("",parsing)) => match parsing.parse(")()))") { -/// Done(")",result) => assert_eq!(result,Ok(Tree(vec![Tree(vec![]),Tree(vec![])]))), -/// _ => panic!("can't happen"), -/// }, -/// _ => panic!("can't happen"), -/// } -/// ``` -/// -/// The reason for making `Boxable` a different trait from `Stateful` -/// is that it provides weaker safety guarantees. `Stateful` enforces that -/// clients cannot call `parse` after `done`, but `Boxable` does not. - -pub trait Boxable { +// +// TODO: finish this documentation! +// +// /// +// /// Regular languages can be parsed in constant memory, so do not require any heap allocation (other than +// /// the heap allocation peformed by user code such as creating buffers). Context-free languages require +// /// allocating unbounded memory. In order to support streaming input, the state of the parser must be +// /// saved on the heap, and restored when more input arrives. +// /// +// /// In Rust, heap-allocated data is often kept in a `Box`, where `T` is a trait. In the case +// /// of parsers, the library needs to save and restore a stateful parser, for which the obvious +// /// type is `Box`. There are two issues with this... +// /// +// /// Firstly, the lifetimes mentioned in the type of the parser may change over time. +// /// For example, the program: +// /// +// /// ```text +// /// let this: &'a str = ...; +// /// let that: &'b str = ...; +// /// let parser = character(char::is_alphanumeric).star(ignore).buffer(); +// /// match parser.init_str(this).unwrap() { +// /// Continue(stateful) => { +// /// let boxed: Box, Output=Cow<'a, str>>> = Box::new(stateful); +// /// match boxed.more_str(that) { +// /// Done(result: Cow<'b,str>) => ... +// /// ``` +// /// +// /// does not typecheck, because the type of `boxed` is fixed as containing parsers for input `&'a str`, +// /// but it was fed input of type `&'b str`. To fix this, we change the type of the box to be +// /// polymorphic in the lifetime of the parser: +// /// +// /// ```text +// /// let this: &'a str = ...; +// /// let that: &'b str = ...; +// /// let parser = character(char::is_alphanumeric).star(ignore).buffer(); +// /// match parser.init_str(this).unwrap() { +// /// Continue(stateful) => { +// /// let boxed: Box Stateful, Output=Cow<'c, str>>> = Box::new(stateful); +// /// match boxed.more_str(that) { +// /// Done(result: Cow<'b,str>) => ... +// /// ``` +// /// +// /// Secondly, the `Stateful` trait is not +// /// [object-safe](https://doc.rust-lang.org/book/trait-objects.html#object-safety), +// /// so cannot be boxed and unboxed safely. In order to address this, there is a trait +// /// `Boxable`, which represents stateful parsers, but is object-safe +// /// and so can be boxed and unboxed safely: +// /// +// /// ``` +// /// # use parsell::{character,Parser,Uncommitted,Committed,Boxable,Stateful}; +// /// # use parsell::ParseResult::{Done,Continue}; +// /// # fn ignore() {} +// /// let parser = character(char::is_alphanumeric).star(ignore).buffer(); +// /// match parser.init_str(this).unwrap() { +// /// Continue(stateful) => { +// /// let boxed: Box Stateful, Output=Cow<'c, str>>> = Box::new(stateful.boxable()); +// /// }, +// /// _ => panic!("Can't happen."), +// /// } +// /// ``` +// /// +// /// The type `Box>` implements the trait +// /// `Stateful`, so boxes can be used as parsers, +// /// which allows stateful parsers to heap-allocate their state. +// /// +// /// Boxable parsers are usually used in recursive-descent parsing, +// /// for context-free grammars that cannot be parsed as a regular language. +// /// For example, consider a simple type for trees: +// /// +// /// ``` +// /// struct Tree(Vec); +// /// ``` +// /// +// /// which can be parsed from a well-nested sequence of parentheses, for example +// /// `(()())` can be parsed as `Tree(vec![Tree(vec![]),Tree(vec![])])`. +// /// The desired implementation is: +// /// +// /// ```text +// /// fn is_lparen(ch: char) -> bool { ch == '(' } +// /// fn is_rparen(ch: char) -> bool { ch == ')' } +// /// fn mk_vec() -> Vec { Ok(Vec::new()) } +// /// fn mk_ok(ok: T) -> Result { Ok(ok) } +// /// fn mk_err(_: Option) -> Result { Err(String::from("Expected a ( or ).")) } +// /// fn mk_tree(_: char, children: Vec, _: char) -> Tree { +// /// Tree(children) +// /// } +// /// let LPAREN = character(is_lparen); +// /// let RPAREN = character(is_rparen).map(mk_ok).or_else(CHARACTER.map(mk_err)); +// /// let TREE = LPAREN +// /// .and_then_try(TREE.star(mk_vec)) +// /// .try_and_then_try(RPAREN) +// /// .try_map3(mk_tree); +// /// ``` +// /// +// /// but this doesn't work because it gives the definition of `TREE` in terms of itself, +// /// and Rust doesn't allow this kind of cycle. +// /// +// /// Instead, the solution is to define a struct `TreeParser`, and then implement `Uncommitted<&str>` +// /// for it. The type of the state of a `TreeParser` is a box containing an appropriate +// /// `BoxableParserState` trait: +// /// +// /// ``` +// /// # use parsell::{Boxable}, +// /// # struct Tree(Vec); +// /// type TreeParserState = Box Boxable, Output=Tree>>; +// /// ``` +// /// +// /// The implementation of `Uncommitted>` for `TreeParser` is mostly straightfoward: +// /// +// /// ``` +// /// # use parsell::{character,CHARACTER,Parser,Uncommitted,Committed,Boxable,Stateful,MaybeParseResult,Static}; +// /// # use parsell::ParseResult::{Done,Continue}; +// /// # use parsell::MaybeParseResult::{Commit}; +// /// # #[derive(Eq,PartialEq,Clone,Debug)] +// /// struct Tree(Vec); +// /// impl Static for Tree {} +// /// # #[derive(Copy,Clone,Debug)] +// /// struct TreeParser; +// /// type TreeParserState = Box Boxable<&'b str, Output=Result>>; +// /// impl Parser for TreeParser { +// /// type StaticOutput = Result; +// /// type State = TreeParserState; +// /// } +// /// impl<'a> Uncommitted<&'a str> for TreeParser { +// /// fn parse(&self, data: &'a str) -> MaybeParseResult { +// /// // ... parser goes here...` +// /// # fn is_lparen(ch: char) -> bool { ch == '(' } +// /// # fn is_rparen(ch: char) -> bool { ch == ')' } +// /// # fn mk_vec() -> Result,String> { Ok(Vec::new()) } +// /// # fn mk_ok(ok: T) -> Result { Ok(ok) } +// /// # fn mk_err(_: Option) -> Result { Err(String::from("Expected a ( or ).")) } +// /// # fn mk_tree(_: char, children: Vec, _: char) -> Tree { +// /// # Tree(children) +// /// # } +// /// # fn mk_box

(parser: P) -> TreeParserState +// /// # where P: 'static+for<'a> Stateful<&'a str, Output=Result> { +// /// # Box::new(parser.boxable()) +// /// # } +// /// # let LPAREN = character(is_lparen); +// /// # let RPAREN = character(is_rparen).map(mk_ok).or_else(CHARACTER.map(mk_err)); +// /// # let parser = LPAREN +// /// # .and_then_try(TreeParser.star(mk_vec)) +// /// # .try_and_then_try(RPAREN) +// /// # .try_map3(mk_tree); +// /// # parser.parse(data).map(mk_box) +// /// } +// /// } +// /// ``` +// /// +// /// The important thing is that the definiton of `parse` can make use of `TREE`, so the parser can call itself +// /// recursively, then box up the result state: +// /// +// /// ``` +// /// # use parsell::{character,CHARACTER,Parser,Uncommitted,Committed,Boxable,Stateful,MaybeParseResult,Static}; +// /// # use parsell::ParseResult::{Done,Continue}; +// /// # use parsell::MaybeParseResult::{Commit}; +// /// # #[derive(Eq,PartialEq,Clone,Debug)] +// /// struct Tree(Vec); +// /// # impl StaticMarker for Tree {} +// /// # #[derive(Copy,Clone,Debug)] +// /// struct TreeParser; +// /// type TreeParserState = Box Boxable, Output=Result>>; +// /// impl Parser for TreeParser {} +// /// impl<'a> Uncommitted<&'a str> for TreeParser { +// /// fn init(&self, data: Chars<'a>) -> Option> { +// /// fn is_lparen(ch: char) -> bool { ch == '(' } +// /// fn is_rparen(ch: char) -> bool { ch == ')' } +// /// fn mk_vec() -> Vec { Vec::new() } +// /// fn mk_ok(ok: T) -> Result { Ok(ok) } +// /// fn mk_err(_: Option) -> Result { Err(String::from("Expected a ( or ).")) } +// /// fn mk_tree(_: char, children: Vec, _: char) -> Tree { Tree(children) } +// /// let LPAREN = character(is_lparen); +// /// let RPAREN = character(is_rparen).map(mk_ok).or_else(CHARACTER.map(mk_err)); +// /// let parser = LPAREN +// /// .and_then_try(TreeParser.star(mk_vec)) +// /// .try_and_then_try(RPAREN) +// /// .try_map3(mk_tree); +// /// parser.init(data) +// /// } +// /// } +// /// let TREE = TreeParser; +// /// match TREE.init_str("((").unwrap() { +// /// Continue(parsing) => match parsing.more_str(")()))") { +// /// Done(result) => assert_eq!(result, Ok(Tree(vec![Tree(vec![]),Tree(vec![])]))), +// /// _ => panic!("Can't happen"), +// /// }, +// /// _ => panic!("Can't happen"), +// /// } +// /// ``` +// /// +// /// The reason for making `Boxable` a different trait from `Stateful` +// /// is that it provides weaker safety guarantees. `Stateful` enforces that +// /// clients cannot call `parse` after `done`, but `Boxable` does not. + +pub trait Boxable + where Str: Iterator, +{ type Output; - fn parse_boxable(&mut self, value: S) -> (S, Option); + fn more_boxable(&mut self, string: &mut Str) -> ParseResult<(), Self::Output>; fn done_boxable(&mut self) -> Self::Output; } @@ -794,25 +736,25 @@ pub trait Boxable { /// /// ``` /// # use parsell::{Function,character}; -/// # use parsell::impls::{CharacterParser}; +/// # use parsell::impls::{Character}; /// struct AlphaNumeric; /// impl Function for AlphaNumeric { /// type Output = bool; /// fn apply(&self, arg: char) -> bool { arg.is_alphanumeric() } /// } -/// let parser: CharacterParser = +/// let parser: Character = /// character(AlphaNumeric); /// ``` /// -/// Here, we can name the type of the parser `CharacterParser`, +/// Here, we can name the type of the parser `Character`, /// which would not be possible if `character` took its argument as a `Fn(T) -> U`, /// since `typeof` is not implemented in Rust. /// At some point, Rust will probably get abstract return types, /// at which point the main need for this type will go away. -pub trait Function { +pub trait Function { type Output; - fn apply(&self, arg: T) -> Self::Output; + fn apply(&self, arg: S) -> Self::Output; } // NOTE(eddyb): a generic over U where F: Fn(T) -> U doesn't allow HRTB in both T and U. @@ -930,82 +872,190 @@ impl Consumer> for Result where C: Consumer } } +/// A trait for subtyping + +pub trait Upcast { + fn upcast(self) -> T where Self: Sized; +} + +impl<'a, T: ?Sized> Upcast> for Cow<'static, T> + where T: ToOwned, +{ + fn upcast(self) -> Cow<'a, T> { self } +} + +impl Upcast<(T1, T2)> for (S1,S2) + where S1: Upcast, + S2: Upcast, +{ + fn upcast(self) -> (T1, T2) { (self.0.upcast(), self.1.upcast()) } +} + +impl Upcast> for Option + where S: Upcast, +{ + fn upcast(self) -> Option { self.map(Upcast::upcast) } +} + +impl Upcast> for Result + where S: Upcast, + D: Upcast, +{ + fn upcast(self) -> Result { self.map(Upcast::upcast).map_err(Upcast::upcast) } +} + /// A trait for data which can be saved to and restored from long-lived state. /// /// The canonical example of this trait is `Cow<'a,T>` which can be saved to -/// and restored from `T::Owned`. -/// -/// This trait is lot like `ToOwned`, the difference is that ` as ToOwned>::Owned` -/// is `Cow<'a,T>`, not `T::Owned`. +/// and restored from `Cow<'static,T>` when `T` is static. -pub trait ToFromOwned { - type Owned; - fn to_owned(self) -> Self::Owned; - fn from_owned(p: Self::Owned) -> Self; +pub trait ToStatic { + type Static: 'static; + fn to_static(self) -> Self::Static where Self: Sized; } -impl<'a, T: ?Sized> ToFromOwned for Cow<'a, T> where T: ToOwned { - type Owned = T::Owned; - fn to_owned(self) -> T::Owned { self.into_owned() } - fn from_owned(p: T::Owned) -> Cow<'a,T> { Cow::Owned(p) } +impl<'a, T: ?Sized> ToStatic for Cow<'a, T> + where T: 'static + ToOwned +{ + type Static = Cow<'static, T>; + fn to_static(self) -> Self::Static { Cow::Owned(self.into_owned()) } } -impl ToFromOwned for (T, U) where T: ToFromOwned, U: ToFromOwned { - type Owned = (T::Owned, U::Owned); - fn to_owned(self) -> Self::Owned { (self.0.to_owned(), self.1.to_owned()) } - fn from_owned(p: Self::Owned) -> Self { (ToFromOwned::from_owned(p.0), ToFromOwned::from_owned(p.1)) } +impl ToStatic for (T, U) + where T: ToStatic, + U: ToStatic +{ + type Static = (T::Static, U::Static); + fn to_static(self) -> Self::Static { (self.0.to_static(), self.1.to_static()) } } -impl ToFromOwned for Option where T: ToFromOwned { - type Owned = Option; - fn to_owned(self) -> Self::Owned { self.map(ToFromOwned::to_owned) } - fn from_owned(p: Self::Owned) -> Self { p.map(ToFromOwned::from_owned) } +impl ToStatic for Option + where T: ToStatic +{ + type Static = Option; + fn to_static(self) -> Self::Static { self.map(ToStatic::to_static) } } -impl ToFromOwned for Result where T: ToFromOwned, E: ToFromOwned { - type Owned = Result; - fn to_owned(self) -> Self::Owned { self.map(ToFromOwned::to_owned).map_err(ToFromOwned::to_owned) } - fn from_owned(p: Self::Owned) -> Self { p.map(ToFromOwned::from_owned).map_err(ToFromOwned::from_owned) } +impl ToStatic for Result where T: ToStatic, E: ToStatic { + type Static = Result; + fn to_static(self) -> Self::Static { self.map(ToStatic::to_static).map_err(ToStatic::to_static) } } -/// A marker trait for owned data. +/// A marker trait for static data. /// -/// This trait is a quick way to implment `Persist` as a no-op. +/// This trait is a quick way to implment `ToStatic` as a no-op. -pub trait Owned {} +pub trait StaticMarker {} -impl ToFromOwned for T where T: Owned { - type Owned = T; - fn to_owned(self) -> T { self } - fn from_owned(p: T) -> T { p } +impl Upcast for T where T: StaticMarker { + fn upcast(self) -> T { self } } -impl Owned for usize {} -impl Owned for u8 {} -impl Owned for u16 {} -impl Owned for u32 {} -impl Owned for u64 {} -impl Owned for isize {} -impl Owned for i8 {} -impl Owned for i16 {} -impl Owned for i32 {} -impl Owned for i64 {} -impl Owned for () {} -impl Owned for bool {} -impl Owned for char {} -impl Owned for String {} -impl Owned for Vec where T: Owned {} +impl ToStatic for T where T: 'static + StaticMarker { + type Static = T; + fn to_static(self) -> T { self } +} + +impl StaticMarker for usize {} +impl StaticMarker for u8 {} +impl StaticMarker for u16 {} +impl StaticMarker for u32 {} +impl StaticMarker for u64 {} +impl StaticMarker for isize {} +impl StaticMarker for i8 {} +impl StaticMarker for i16 {} +impl StaticMarker for i32 {} +impl StaticMarker for i64 {} +impl StaticMarker for () {} +impl StaticMarker for bool {} +impl StaticMarker for char {} +impl StaticMarker for String {} +impl StaticMarker for Vec where T: 'static {} + +/// A trait for peekable iterators + +struct ByRef(F); + +impl<'a, T, F> Function<&'a T> for ByRef where + F: Function, + T: Copy, +{ + type Output = F::Output; + fn apply(&self, arg: &'a T) -> F::Output { self.0.apply(*arg) } +} + +pub trait PeekableIterator: Iterator { + + fn is_empty(&mut self) -> bool; + + fn next_if_ref(&mut self, f: F) -> Option + where F: for<'a> Function<&'a Self::Item, Output = bool>; + + fn next_if(&mut self, f: F) -> Option + where F: Function, + Self::Item: Copy, + { + self.next_if_ref(ByRef(f)) + } + +} + +impl PeekableIterator for Peekable + where I: Iterator +{ + fn is_empty(&mut self) -> bool { + self.peek().is_none() + } + + fn next_if_ref(&mut self, f: F) -> Option + where F: for<'a> Function<&'a Self::Item, Output = bool> + { + match self.peek() { + Some(ref item) if f.apply(item) => (), + _ => return None, + }; + self.next() + } +} + +impl<'a> PeekableIterator for Chars<'a> +{ + fn is_empty(&mut self) -> bool { + self.as_str().is_empty() + } + + fn next_if_ref(&mut self, f: F) -> Option + where F: for<'b> Function<&'b char, Output = bool> + { + match self.as_str().chars().next() { + Some(ref ch) if f.apply(ch) => self.next(), + _ => None + } + } +} /// An uncommitted parser that reads one character. /// /// The parser `character(f)` reads one character `ch` from the input, /// if `f(ch)` is `true` then it commits and the result is `ch`, /// otherwise it backtracks. +/// +/// This requires characters to be copyable. -pub fn character(f: F) -> impls::CharacterParser - where F: Function -{ - impls::CharacterParser::new(f) +pub fn character(f: F) -> impls::Character { + impls::Character::new(f) +} + +/// An uncommitted parser that reads one character by reference. +/// +/// The parser `character(f)` reads one character `ch` from the input, +/// if `f(&ch)` is `true` then it commits and the result is `ch`, +/// otherwise it backtracks. +/// +/// This does not require characters to be copyable. + +pub fn character_ref(f: F) -> impls::CharacterRef { + impls::CharacterRef::new(f) } /// A committed parser that reads one character. @@ -1013,488 +1063,443 @@ pub fn character(f: F) -> impls::CharacterParser /// The parser `CHARACTER` reads one character `ch` from the input, /// and produces `Some(ch)`. It produces `None` at the end of input. -pub const CHARACTER: impls::AnyCharacterParser = impls::AnyCharacterParser; +pub const CHARACTER: impls::AnyCharacter = impls::AnyCharacter; -/// An uncommitted parser that reads one token. -/// -/// The parser `token(f)` reads one token `tok` from the input, -/// if `f(tok)` is `true` then it commits and the result is `tok`, -/// otherwise it backtracks. +/// A committed parser that reads zero characters. -pub fn token(f: F) -> impls::TokenParser { - impls::TokenParser::::new(f) +pub fn emit(t: T) -> impls::Emit { + impls::Emit::new(t) } -/// A committed parser that reads one token. -/// -/// The parser `TOKEN` reads one token `tok` from the input, -/// and produces `Some(tok)`. It produces `None` at the end of input. - -pub const TOKEN: impls::AnyTokenParser = impls::AnyTokenParser; - // ----------- Tests ------------- -#[allow(non_snake_case,dead_code)] -impl MaybeParseResult where P: Stateful +#[allow(non_snake_case)] +impl ParseResult { - fn unEmpty(self) -> S { + pub fn unDone(self) -> Output { match self { - Empty(rest) => rest, - _ => panic!("MaybeParseResult is not empty"), + Done(result) => result, + _ => panic!("Not done"), } } - fn unAbort(self) -> S { + pub fn unContinue(self) -> State { match self { - Abort(s) => s, - _ => panic!("MaybeParseResult is not failure"), + Continue(state) => state, + _ => panic!("Not continue"), } } - fn unCommit(self) -> ParseResult { - match self { - Commit(s) => s, - _ => panic!("MaybeParseResult is not success"), - } - } -} - -#[allow(non_snake_case,dead_code)] -impl ParseResult where P: Stateful -{ - fn unDone(self) -> (S, P::Output) { - match self { - Done(s, t) => (s, t), - _ => panic!("ParseResult is not done"), - } - } - - fn unContinue(self) -> P { - match self { - Continue(_, p) => p, - _ => panic!("ParseResult is not continue"), - } - } } #[test] fn test_character() { let parser = character(char::is_alphabetic); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("989").unAbort(), "989"); - assert_eq!(parser.parse("abc").unCommit().unDone(), ("bc", 'a')); -} - -#[test] -#[allow(non_snake_case)] -fn test_CHARACTER() { - let parser = CHARACTER; - assert_eq!(parser.init().parse("abc").unDone(), ("bc", Some('a'))); - assert_eq!(parser.init().parse("").unContinue().parse("abc").unDone(), - ("bc", Some('a'))); - assert_eq!(parser.init().done(), None); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "989".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), "989"); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), 'a'); + assert_eq!(data.as_str(), "bcd"); } #[test] -fn test_token() { - fn is_zero(num: &usize) -> bool { - *num == 0 - } - let parser = token(is_zero); - let mut iter = parser.parse((1..3).peekable()).unAbort(); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), None); - let (mut iter, result) = parser.parse((0..3).peekable()).unCommit().unDone(); - assert_eq!(iter.next(), Some(1)); - assert_eq!(iter.next(), Some(2)); - assert_eq!(iter.next(), None); - assert_eq!(result, 0); +fn test_character_ref() { + fn is_alphabetic<'a>(ch: &'a char) -> bool { ch.is_alphabetic() } + let parser = character_ref(is_alphabetic); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "989".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), "989"); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), 'a'); + assert_eq!(data.as_str(), "bcd"); } #[test] #[allow(non_snake_case)] -fn test_TOKEN() { - let parser = TOKEN; - let (mut iter, result) = parser.init_parse("abc".chars()).unDone(); - assert_eq!(result, Some('a')); - assert_eq!(iter.next(), Some('b')); - assert_eq!(iter.next(), Some('c')); - assert_eq!(iter.next(), None); +fn test_CHARACTER() { + let parser = CHARACTER; + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some('a')); + assert_eq!(data.as_str(), "bcd"); } #[test] fn test_map() { + // uncommitted map let parser = character(char::is_alphabetic).map(Some); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("989").unAbort(), "989"); - assert_eq!(parser.parse("abc").unCommit().unDone(), ("bc", Some('a'))); -} - -#[test] -#[allow(non_snake_case)] -fn test_map2() { - fn f(ch1: char, ch2: Option) -> Option<(char, char)> { - ch2.and_then(|ch2| Some((ch1, ch2))) - } - fn mk_none(_: Option) -> Option { - None - } - let ALPHANUMERIC = character(char::is_alphanumeric).map(Some).or_else(CHARACTER.map(mk_none)); - let parser = character(char::is_alphabetic).and_then(ALPHANUMERIC).map2(f); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("!b!").unAbort(), "!b!"); - assert_eq!(parser.parse("a!!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("ab!").unCommit().unDone(), - ("!", Some(('a', 'b')))); -} - -#[test] -#[allow(non_snake_case)] -fn test_map3() { - fn f(ch1: char, ch2: Option, ch3: Option) -> Option<(char, char, char)> { - ch3.and_then(|ch3| ch2.and_then(|ch2| Some((ch1, ch2, ch3)))) - } - fn mk_none(_: Option) -> Option { - None - } - let ALPHANUMERIC = character(char::is_alphanumeric).map(Some).or_else(CHARACTER.map(mk_none)); - let parser = character(char::is_alphabetic) - .and_then(ALPHANUMERIC) - .and_then(ALPHANUMERIC) - .map3(f); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("!bc!").unAbort(), "!bc!"); - assert_eq!(parser.parse("a!c!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("ab!!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("abc!").unCommit().unDone(), - ("!", Some(('a', 'b', 'c')))); -} - -#[test] -#[allow(non_snake_case)] -fn test_map4() { - fn f(ch1: char, - ch2: Option, - ch3: Option, - ch4: Option) - -> Option<(char, char, char, char)> { - ch4.and_then(|ch4| ch3.and_then(|ch3| ch2.and_then(|ch2| Some((ch1, ch2, ch3, ch4))))) - } - fn mk_none(_: Option) -> Option { - None - } - let ALPHANUMERIC = character(char::is_alphanumeric).map(Some).or_else(CHARACTER.map(mk_none)); - let parser = character(char::is_alphabetic) - .and_then(ALPHANUMERIC) - .and_then(ALPHANUMERIC) - .and_then(ALPHANUMERIC) - .map4(f); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("!bcd!").unAbort(), "!bcd!"); - assert_eq!(parser.parse("a!cd!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("ab!d!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("abc!!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("abcd!").unCommit().unDone(), - ("!", Some(('a', 'b', 'c', 'd')))); -} - -#[test] -#[allow(non_snake_case)] -fn test_map5() { - fn f(ch1: char, - ch2: Option, - ch3: Option, - ch4: Option, - ch5: Option) - -> Option<(char, char, char, char, char)> { - ch5.and_then(|ch5| { - ch4.and_then(|ch4| { - ch3.and_then(|ch3| ch2.and_then(|ch2| Some((ch1, ch2, ch3, ch4, ch5)))) - }) - }) - } - fn mk_none(_: Option) -> Option { - None - } - let ALPHANUMERIC = character(char::is_alphanumeric).map(Some).or_else(CHARACTER.map(mk_none)); - let parser = character(char::is_alphabetic) - .and_then(ALPHANUMERIC) - .and_then(ALPHANUMERIC) - .and_then(ALPHANUMERIC) - .and_then(ALPHANUMERIC) - .map5(f); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("!bcde!").unAbort(), "!bcde!"); - assert_eq!(parser.parse("a!cde!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("ab!de!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("abc!e!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("abcd!!").unCommit().unDone(), ("!", None)); - assert_eq!(parser.parse("abcde!").unCommit().unDone(), - ("!", Some(('a', 'b', 'c', 'd', 'e')))); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "989".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), "989"); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some('a')); + assert_eq!(data.as_str(), "bcd"); + // committed map + let parser = CHARACTER.map(Some); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some(Some('a'))); + assert_eq!(data.as_str(), "bcd"); } #[test] #[allow(non_snake_case)] fn test_and_then() { - fn mk_none(_: Option) -> Option { - None - } - let ALPHANUMERIC = character(char::is_alphanumeric).map(Some).or_else(CHARACTER.map(mk_none)); - let ALPHABETIC = character(char::is_alphabetic).map(Some).or_else(CHARACTER.map(mk_none)); - let parser = ALPHABETIC.and_then(ALPHANUMERIC); - parser.init().parse("").unContinue(); - assert_eq!(parser.init().parse("989").unDone(), - ("9", (None, Some('8')))); - assert_eq!(parser.init().parse("a!!").unDone(), - ("!", (Some('a'), None))); - assert_eq!(parser.init().parse("abc").unDone(), - ("c", (Some('a'), Some('b')))); + // uncommitted + let parser = character(char::is_alphabetic).and_then(CHARACTER); + let mut data = "989".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), "989"); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), ('a', Some('b'))); + assert_eq!(data.as_str(), "cd"); + let mut data1 = "a".chars(); + let mut data2 = "bcd".chars(); + assert_eq!(parser.init(&mut data1).unwrap().unContinue().more(&mut data2).unDone(), ('a', Some('b'))); + assert_eq!(data1.as_str(), ""); + assert_eq!(data2.as_str(), "cd"); + // committed + let parser = CHARACTER.and_then(CHARACTER); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), (Some('a'), Some('b'))); + assert_eq!(data.as_str(), "cd"); + let mut data1 = "a".chars(); + let mut data2 = "bcd".chars(); + assert_eq!(parser.init(&mut data1).unwrap().unContinue().more(&mut data2).unDone(), (Some('a'), Some('b'))); + assert_eq!(data1.as_str(), ""); + assert_eq!(data2.as_str(), "cd"); } #[test] #[allow(non_snake_case)] fn test_try_and_then() { - fn mk_err(_: Option) -> Result { - Err(String::from("oh")) - } - fn mk_ok(ok: T) -> Result { - Ok(ok) - } + fn mk_err(_: Option) -> Result { Err(String::from("oh")) } + fn mk_ok(ok: T) -> Result { Ok(ok) } let ALPHANUMERIC = character(char::is_alphanumeric).map(mk_ok).or_else(CHARACTER.map(mk_err)); - let parser = character(char::is_alphabetic).map(mk_ok).try_and_then(ALPHANUMERIC); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("989").unAbort(), "989"); - assert_eq!(parser.parse("a!!").unCommit().unDone(), - ("!", Ok(('a', Err(String::from("oh")))))); - assert_eq!(parser.parse("abc").unCommit().unDone(), - ("c", Ok(('a', Ok('b'))))); + let parser = ALPHANUMERIC.try_and_then(ALPHANUMERIC); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "abc".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Ok(('a', Ok('b')))); + assert_eq!(data.as_str(), "c"); + let mut data = "a!!".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Ok(('a', Err(String::from("oh"))))); + assert_eq!(data.as_str(), "!"); + let mut data = "!ab".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Err(String::from("oh"))); + assert_eq!(data.as_str(), "b"); } #[test] #[allow(non_snake_case)] fn test_and_then_try() { - fn mk_err(_: Option) -> Result { - Err(String::from("oh")) - } - fn mk_ok(ok: T) -> Result { - Ok(ok) - } + fn mk_err(_: Option) -> Result { Err(String::from("oh")) } + fn mk_ok(ok: T) -> Result { Ok(ok) } let ALPHANUMERIC = character(char::is_alphanumeric).map(mk_ok).or_else(CHARACTER.map(mk_err)); - let parser = character(char::is_alphabetic).map(mk_ok).and_then_try(ALPHANUMERIC); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("989").unAbort(), "989"); - assert_eq!(parser.parse("a!!").unCommit().unDone(), - ("!", Err(String::from("oh")))); - assert_eq!(parser.parse("abc").unCommit().unDone(), - ("c", Ok((Ok('a'), 'b')))); + let parser = ALPHANUMERIC.and_then_try(ALPHANUMERIC); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "abc".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Ok((Ok('a'), 'b'))); + assert_eq!(data.as_str(), "c"); + let mut data = "a!!".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Err(String::from("oh"))); + assert_eq!(data.as_str(), "!"); + let mut data = "!ab".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Ok((Err(String::from("oh")), 'a'))); + assert_eq!(data.as_str(), "b"); } #[test] #[allow(non_snake_case)] fn test_try_and_then_try() { - fn mk_err(_: Option) -> Result { - Err(String::from("oh")) - } - fn mk_ok(ok: T) -> Result { - Ok(ok) - } + fn mk_err(_: Option) -> Result { Err(String::from("oh")) } + fn mk_ok(ok: T) -> Result { Ok(ok) } let ALPHANUMERIC = character(char::is_alphanumeric).map(mk_ok).or_else(CHARACTER.map(mk_err)); - let parser = character(char::is_alphabetic).map(mk_ok).try_and_then_try(ALPHANUMERIC); - parser.parse("").unEmpty(); - assert_eq!(parser.parse("989").unAbort(), "989"); - assert_eq!(parser.parse("a!!").unCommit().unDone(), - ("!", Err(String::from("oh")))); - assert_eq!(parser.parse("abc").unCommit().unDone(), - ("c", Ok(('a', 'b')))); + let parser = ALPHANUMERIC.try_and_then_try(ALPHANUMERIC); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "abc".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Ok(('a', 'b'))); + assert_eq!(data.as_str(), "c"); + let mut data = "a!!".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Err(String::from("oh"))); + assert_eq!(data.as_str(), "!"); + let mut data = "!ab".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Err(String::from("oh"))); + assert_eq!(data.as_str(), "b"); } #[test] #[allow(non_snake_case)] fn test_or_else() { - fn mk_none(_: Option) -> Option { - None - } + fn mk_none(_: Option) -> Option { None } let NUMERIC = character(char::is_numeric).map(Some).or_else(CHARACTER.map(mk_none)); let ALPHABETIC = character(char::is_alphabetic).map(Some).or_else(CHARACTER.map(mk_none)); - let parser = character(char::is_alphabetic) - .and_then(ALPHABETIC) - .map(Some) + let parser = character(char::is_alphabetic).and_then(ALPHABETIC).map(Some) .or_else(character(char::is_numeric).and_then(NUMERIC).map(Some)) .or_else(CHARACTER.map(mk_none)); - parser.init().parse("").unContinue(); - parser.init().parse("a").unContinue(); - parser.init().parse("9").unContinue(); - assert_eq!(parser.init().parse("!!").unDone(), ("!", None)); - assert_eq!(parser.init().parse("a99").unDone(), - ("9", Some(('a', None)))); - assert_eq!(parser.init().parse("9aa").unDone(), - ("a", Some(('9', None)))); - assert_eq!(parser.init().parse("abc").unDone(), - ("c", Some(('a', Some('b'))))); - assert_eq!(parser.init().parse("123").unDone(), - ("3", Some(('1', Some('2'))))); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "abcd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some(('a', Some('b')))); + assert_eq!(data.as_str(), "cd"); + let mut data = "a89".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some(('a', None))); + assert_eq!(data.as_str(), "9"); + let mut data = "789".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some(('7', Some('8')))); + assert_eq!(data.as_str(), "9"); + let mut data = "7cd".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), Some(('7', None))); + assert_eq!(data.as_str(), "d"); + let mut data = "!?".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), None); + assert_eq!(data.as_str(), "?"); } #[test] #[allow(non_snake_case)] fn test_plus() { let parser = character(char::is_alphanumeric).plus(String::new); - parser.parse("").unEmpty(); - parser.parse("!!!").unAbort(); - assert_eq!(parser.parse("a!").unCommit().unDone(), - ("!", String::from("a"))); - assert_eq!(parser.parse("abc98def!").unCommit().unDone(), - ("!", String::from("abc98def"))); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "!?".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), "!?"); + let mut data = "abc!".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), "abc"); + assert_eq!(data.as_str(), "!"); + let mut data1 = "ab".chars(); + let mut data2 = "c!".chars(); + assert_eq!(parser.init(&mut data1).unwrap().unContinue().more(&mut data2).unDone(), "abc"); + assert_eq!(data.as_str(), "!"); } #[test] #[allow(non_snake_case)] fn test_star() { let parser = character(char::is_alphanumeric).star(String::new); - parser.init().parse("").unContinue(); - assert_eq!(parser.init().parse("!!!").unDone(), - ("!!!", String::from(""))); - assert_eq!(parser.init().parse("a!").unDone(), ("!", String::from("a"))); - assert_eq!(parser.init().parse("abc98def!").unDone(), - ("!", String::from("abc98def"))); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "!?".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), ""); + assert_eq!(data.as_str(), "!?"); + let mut data = "abc!".chars(); + assert_eq!(parser.init(&mut data).unwrap().unDone(), "abc"); + assert_eq!(data.as_str(), "!"); + let mut data1 = "ab".chars(); + let mut data2 = "c!".chars(); + assert_eq!(parser.init(&mut data1).unwrap().unContinue().more(&mut data2).unDone(), "abc"); + assert_eq!(data.as_str(), "!"); } #[test] #[allow(non_snake_case)] fn test_buffer() { - use std::borrow::Cow::{Borrowed, Owned}; + use std::borrow::Cow::{Borrowed,Owned}; fn ignore() {} let ALPHABETIC = character(char::is_alphabetic); let ALPHANUMERIC = character(char::is_alphanumeric); let parser = ALPHABETIC.and_then(ALPHANUMERIC.star(ignore)).buffer(); - assert_eq!(parser.parse("989").unAbort(), "989"); - assert_eq!(parser.parse("a!").unCommit().unDone(), ("!", Borrowed("a"))); - assert_eq!(parser.parse("abc!").unCommit().unDone(), - ("!", Borrowed("abc"))); - let parsing = parser.parse("a").unCommit().unContinue(); - assert_eq!(parsing.parse("bc!").unDone(), - ("!", Owned(String::from("abc")))); - let parser = ALPHANUMERIC.star(ignore).buffer(); - assert_eq!(parser.init().parse("!").unDone(), ("!", Borrowed(""))); - assert_eq!(parser.init().parse("a!").unDone(), ("!", Borrowed("a"))); - assert_eq!(parser.init().parse("abc!").unDone(), ("!", Borrowed("abc"))); - let parsing = parser.init().parse("a").unContinue(); - assert_eq!(parsing.parse("bc!").unDone(), - ("!", Owned(String::from("abc")))); + let mut data = "".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), ""); + let mut data = "!?".chars(); + assert!(parser.init(&mut data).is_none()); + assert_eq!(data.as_str(), "!?"); + let mut data = "abc!".chars(); + if let Borrowed(result) = parser.init(&mut data).unwrap().unDone() { + assert_eq!(result, "abc"); + } else { panic!("cow") } + assert_eq!(data.as_str(), "!"); + let mut data1 = "abc".chars(); + let mut data2 = "def!".chars(); + if let Owned(result) = parser.init(&mut data1).unwrap().unContinue().more(&mut data2).unDone() { + assert_eq!(result, "abcdef"); + } else { panic!("cow") } + assert_eq!(data.as_str(), "!"); } #[test] #[allow(non_snake_case)] -fn test_iter() { - fn mk_X(_: Option) -> char { - 'X' - } - let ALPHABETIC = character(char::is_alphabetic); - let parser = ALPHABETIC.or_else(CHARACTER.map(mk_X)); - let mut iter = parser.iter("abc"); - assert_eq!(iter.next(), Some('a')); - assert_eq!(iter.next(), Some('b')); - assert_eq!(iter.next(), Some('c')); - assert_eq!(iter.next(), None); +fn test_cow() { + fn is_foo<'a>(string: &Cow<'a,str>) -> bool { string == "foo" } + fn mk_other<'a>(_: Option>) -> Cow<'a,str> { Cow::Borrowed("other") } + fn is_owned<'a,T:?Sized+ToOwned>(cow: Cow<'a,T>) -> bool { match cow { Cow::Owned(_) => true, _ => false } } + let ONE = character_ref(is_foo); + let OTHER = CHARACTER.map(mk_other); + let parser = ONE.and_then(ONE.or_else(OTHER)).and_then(ONE.or_else(OTHER)); + let mut data = vec![Cow::Borrowed("foo"), Cow::Borrowed("bar"), Cow::Borrowed("foo")]; + let ((fst, snd), thd) = parser.init(&mut data.drain(..).peekable()).unwrap().unDone(); + assert_eq!(fst, "foo"); + assert_eq!(snd, "other"); + assert_eq!(thd, "foo"); + assert!(!is_owned(fst)); + assert!(!is_owned(snd)); + assert!(!is_owned(thd)); + let mut data1 = vec![Cow::Borrowed("foo")]; + let mut data2 = vec![Cow::Borrowed("bar"), Cow::Borrowed("foo")]; + let ((fst, snd), thd) = parser.init(&mut data1.drain(..).peekable()).unwrap().unContinue() + .more(&mut data2.drain(..).peekable()).unDone(); + assert_eq!(fst, "foo"); + assert_eq!(snd, "other"); + assert_eq!(thd, "foo"); + assert!(is_owned(fst)); + assert!(!is_owned(snd)); + assert!(!is_owned(thd)); + let mut data1 = vec![Cow::Borrowed("foo"), Cow::Borrowed("bar")]; + let mut data2 = vec![Cow::Borrowed("foo")]; + let ((fst, snd), thd) = parser.init(&mut data1.drain(..).peekable()).unwrap().unContinue() + .more(&mut data2.drain(..).peekable()).unDone(); + assert_eq!(fst, "foo"); + assert_eq!(snd, "other"); + assert_eq!(thd, "foo"); + assert!(is_owned(fst)); + assert!(is_owned(snd)); + assert!(!is_owned(thd)); } #[test] #[allow(non_snake_case)] -fn test_pipe() { - use std::borrow::{Borrow, Cow}; - #[derive(Clone,Debug,PartialEq,Eq)] - enum Token { - Identifier(String), - Number(usize), - Other, - } - fn mk_id<'a>(string: Cow<'a, str>) -> Token { - Token::Identifier(string.into_owned()) - } - fn mk_num<'a>(string: Cow<'a, str>) -> Token { - Token::Number(usize::from_str_radix(string.borrow(), 10).unwrap()) - } - fn mk_other(_: Option) -> Token { - Token::Other - } - fn ignore() {} - fn is_decimal(ch: char) -> bool { - ch.is_digit(10) - } - fn is_identifier(tok: &Token) -> bool { - match *tok { - Token::Identifier(_) => true, - _ => false, - } - } - fn is_number(tok: &Token) -> bool { - match *tok { - Token::Number(_) => true, - _ => false, +fn test_boxable() { + use std::vec::Drain; + #[derive(Copy, Clone, Debug)] + struct Test; + type TestCh<'a> = Cow<'a,str>; + type TestStr<'a> = Peekable>>; + type TestOutput<'a> = ((TestCh<'a>, TestCh<'a>), TestCh<'a>); + type TestState = Box Boxable, TestStr<'a>, Output=TestOutput<'a>>>; + impl Parser for Test {} + impl<'a> Uncommitted, TestStr<'a>> for Test { + type Output = TestOutput<'a>; + type State = TestState; + fn init(&self, string: &mut TestStr<'a>) -> Option>> { + fn is_foo<'a>(string: &Cow<'a,str>) -> bool { string == "foo" } + fn mk_other<'a>(_: Option>) -> TestCh<'a> { Cow::Borrowed("other") } + let ONE = character_ref(is_foo); + let OTHER = CHARACTER.map(mk_other); + let parser = ONE.and_then(ONE.or_else(OTHER)).and_then(ONE.or_else(OTHER)); + // This bit should be in the API + match parser.init(string) { + None => None, + Some(Done(result)) => Some(Done(result)), + Some(Continue(state)) => Some(Continue(Box::new(impls::BoxableState::new(state)))), + } } } - let ALPHABETIC = character(char::is_alphabetic); - let DIGIT = character(is_decimal); - let lexer = ALPHABETIC.plus(ignore) - .buffer() - .map(mk_id) - .or_else(DIGIT.plus(ignore).buffer().map(mk_num)) - .or_else(CHARACTER.map(mk_other)); - let parser = token(is_identifier).or_else(token(is_number)).star(Vec::::new); - assert_eq!(lexer.pipe(parser).init().parse("abc37!!").unDone(), - ("!", - vec![Token::Identifier(String::from("abc")), Token::Number(37)])); -} - -#[test] -#[allow(non_snake_case)] -fn test_different_lifetimes1() { - fn go<'a, 'b, P>(ab: &'a str, cd: &'b str, parser: P) - where P: Copy + for<'c> Committed<&'c str, Output = (Option, Option)> - { - let _: &'a str = parser.init().parse(ab).unDone().0; - let _: &'b str = parser.init().parse(cd).unDone().0; - assert_eq!(parser.init().parse(ab).unDone(), - ("", (Some('a'), Some('b')))); - assert_eq!(parser.init().parse(cd).unDone(), - ("", (Some('c'), Some('d')))); - } - let parser = CHARACTER.and_then(CHARACTER); - go("ab", "cd", parser); + fn is_owned<'a,T:?Sized+ToOwned>(cow: Cow<'a,T>) -> bool { match cow { Cow::Owned(_) => true, _ => false } } + let parser = Test; + let mut data = vec![Cow::Borrowed("foo"), Cow::Borrowed("bar"), Cow::Borrowed("foo")]; + let ((fst, snd), thd) = parser.init(&mut data.drain(..).peekable()).unwrap().unDone(); + assert_eq!(fst, "foo"); + assert_eq!(snd, "other"); + assert_eq!(thd, "foo"); + assert!(!is_owned(fst)); + assert!(!is_owned(snd)); + assert!(!is_owned(thd)); + let mut data1 = vec![Cow::Borrowed("foo")]; + let mut data2 = vec![Cow::Borrowed("bar"), Cow::Borrowed("foo")]; + let ((fst, snd), thd) = parser.init(&mut data1.drain(..).peekable()).unwrap().unContinue() + .more(&mut data2.drain(..).peekable()).unDone(); + assert_eq!(fst, "foo"); + assert_eq!(snd, "other"); + assert_eq!(thd, "foo"); + assert!(is_owned(fst)); + assert!(!is_owned(snd)); + assert!(!is_owned(thd)); + let mut data1 = vec![Cow::Borrowed("foo"), Cow::Borrowed("bar")]; + let mut data2 = vec![Cow::Borrowed("foo")]; + let ((fst, snd), thd) = parser.init(&mut data1.drain(..).peekable()).unwrap().unContinue() + .more(&mut data2.drain(..).peekable()).unDone(); + assert_eq!(fst, "foo"); + assert_eq!(snd, "other"); + assert_eq!(thd, "foo"); + assert!(is_owned(fst)); + assert!(is_owned(snd)); + assert!(!is_owned(thd)); } -#[test] -#[allow(non_snake_case)] -fn test_different_lifetimes2() { - use std::borrow::Cow; - use std::borrow::Cow::Owned; - fn ignore() {} - fn is_owned<'a,T:?Sized+ToOwned>(cow: &Cow<'a,T>) -> bool { match cow { &Owned(_) => true, _ => false } } - fn go<'a, 'b, P>(fst: &'a str, snd: &'b str, parser: P) - where P: Copy + for<'c> Committed<&'c str, Output = (Cow<'c,str>, Cow<'c,str>)> - { - match parser.init().parse(fst) { - Continue("", parsing) => match parsing.parse(snd) { - Done("!", (ref fst, ref snd)) => { - assert!(is_owned(fst)); - assert!(is_owned(snd)); - assert_eq!(fst, "abc"); - assert_eq!(snd, "123"); - }, - oops => panic!("Shouldn't happen 2 {:?}", oops), - }, - Done("!", (ref fst, ref snd)) => { - assert!(!is_owned(fst)); - assert!(!is_owned(snd)); - assert_eq!(fst, "abc"); - assert_eq!(snd, "123"); - }, - oops => panic!("Shouldn't happen 1 {:?}", oops), - } - } - let parser = character(char::is_alphabetic).star(ignore).buffer() - .and_then(character(char::is_numeric).star(ignore).buffer()); - go("abc123!", "!", parser); - go("abc1", "23!", parser); -} +// #[test] +// #[allow(non_snake_case)] +// fn test_iter() { +// fn mk_X(_: Option) -> char { +// 'X' +// } +// let ALPHABETIC = character(char::is_alphabetic); +// let parser = ALPHABETIC.or_else(CHARACTER.map(mk_X)); +// let mut iter = parser.iter("abc"); +// assert_eq!(iter.next(), Some('a')); +// assert_eq!(iter.next(), Some('b')); +// assert_eq!(iter.next(), Some('c')); +// assert_eq!(iter.next(), None); +// } + +// #[test] +// #[allow(non_snake_case)] +// fn test_pipe() { +// use std::borrow::{Borrow, Cow}; +// #[derive(Clone,Debug,PartialEq,Eq)] +// enum Token { +// Identifier(String), +// Number(usize), +// Other, +// } +// fn mk_id<'a>(string: Cow<'a, str>) -> Token { +// Token::Identifier(string.into_owned()) +// } +// fn mk_num<'a>(string: Cow<'a, str>) -> Token { +// Token::Number(usize::from_str_radix(string.borrow(), 10).unwrap()) +// } +// fn mk_other(_: Option) -> Token { +// Token::Other +// } +// fn ignore() {} +// fn is_decimal(ch: char) -> bool { +// ch.is_digit(10) +// } +// fn is_identifier(tok: &Token) -> bool { +// match *tok { +// Token::Identifier(_) => true, +// _ => false, +// } +// } +// fn is_number(tok: &Token) -> bool { +// match *tok { +// Token::Number(_) => true, +// _ => false, +// } +// } +// let ALPHABETIC = character(char::is_alphabetic); +// let DIGIT = character(is_decimal); +// let lexer = ALPHABETIC.plus(ignore) +// .buffer() +// .map(mk_id) +// .or_else(DIGIT.plus(ignore).buffer().map(mk_num)) +// .or_else(CHARACTER.map(mk_other)); +// let parser = token(is_identifier).or_else(token(is_number)).star(Vec::::new); +// assert_eq!(lexer.pipe(parser).init().parse("abc37!!").unDone(), +// ("!", +// vec![Token::Identifier(String::from("abc")), Token::Number(37)])); +// }