Skip to content

Commit

Permalink
Add at least basic docs to all TODO doc items, fix up ctx and add doc…
Browse files Browse the repository at this point in the history
…tests
  • Loading branch information
CraftSpider committed Feb 16, 2023
1 parent 1c9a3f7 commit d48f139
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 57 deletions.
39 changes: 4 additions & 35 deletions src/zero_copy/combinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,37 +717,6 @@ where
go_extra!(O);
}

/// See [`Parser::map_ctx`].
pub struct MapCtx<A, F> {
pub(crate) parser: A,
pub(crate) mapper: F,
}

impl<A: Copy, F: Copy> Copy for MapCtx<A, F> {}
impl<A: Clone, F: Clone> Clone for MapCtx<A, F> {
fn clone(&self) -> Self {
MapCtx {
parser: self.parser.clone(),
mapper: self.mapper.clone(),
}
}
}

impl<'a, I, O, E, A, F, Ctx> Parser<'a, I, O, E> for MapCtx<A, F>
where
I: Input + ?Sized,
E: ParserExtra<'a, I>,
A: Parser<'a, I, O, extra::Full<E::Error, E::State, Ctx>>,
F: Fn(&E::Context) -> Ctx,
Ctx: 'a,
{
fn go<M: Mode>(&self, inp: &mut InputRef<'a, '_, I, E>) -> PResult<M, O, E::Error> {
inp.with_ctx((self.mapper)(inp.ctx()), |inp| self.parser.go::<M>(inp))
}

go_extra!(O);
}

/// See [`Parser::delimited_by`].
pub struct DelimitedBy<A, B, C, OB, OC> {
pub(crate) parser: A,
Expand Down Expand Up @@ -853,27 +822,27 @@ where
go_extra!(O);
}

/// TODO
/// Configuration for [`Parser::repeated`], used in [`ConfigParser::configure`].
#[derive(Default)]
pub struct RepeatedCfg {
at_least: Option<usize>,
at_most: Option<usize>,
}

impl RepeatedCfg {
/// TODO
/// Set the minimum number of repetitions accepted
pub fn at_least(mut self, n: usize) -> Self {
self.at_least = Some(n);
self
}

/// TODO
/// Set the maximum number of repetitions accepted
pub fn at_most(mut self, n: usize) -> Self {
self.at_most = Some(n);
self
}

/// TODO
/// Set an exact number of repetitions to accept
pub fn exactly(mut self, n: usize) -> Self {
self.at_least = Some(n);
self.at_most = Some(n);
Expand Down
3 changes: 2 additions & 1 deletion src/zero_copy/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ impl<T: Clone> SliceInput for [T] {
}
}

///
/// An input wrapper contains a user-defined context in its span, in addition to the span of the
/// wrapped input.
pub struct WithContext<'a, Ctx, I: ?Sized>(pub Ctx, pub &'a I);

impl<'a, Ctx: Clone, I: Input + ?Sized> Input for WithContext<'a, Ctx, I> {
Expand Down
40 changes: 21 additions & 19 deletions src/zero_copy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub mod prelude {
pub use super::{
error::{EmptyErr, Error as _, Rich, Simple},
extra,
primitive::{any, choice, empty, end, group, just, none_of, one_of, take_until, todo},
primitive::{any, choice, empty, end, group, just, none_of, one_of, take_until, todo, map_ctx},
recovery::{nested_delimiters, skip_until},
recursive::{recursive, Recursive},
// select,
Expand Down Expand Up @@ -936,14 +936,14 @@ pub trait Parser<'a, I: Input + ?Sized, O, E: ParserExtra<'a, I> = extra::Defaul
/// assert_eq!(successive_letters.parse(b"ab").into_result(), Ok(b'b')); // 'b' follows 'a'
/// assert!(successive_letters.parse(b"ac").has_errors()); // 'c' does not follow 'a'
/// ```
fn then_with_ctx<U, CtxN, P>(
fn then_with_ctx<U, P>(
self,
then: P,
) -> ThenWithCtx<Self, P, O, I, extra::Full<E::Error, E::State, CtxN>>
) -> ThenWithCtx<Self, P, O, I, extra::Full<E::Error, E::State, O>>
where
Self: Sized,
CtxN: 'a,
P: Parser<'a, I, U, extra::Full<E::Error, E::State, CtxN>>,
O: 'a,
P: Parser<'a, I, U, extra::Full<E::Error, E::State, O>>,
{
ThenWithCtx {
parser: self,
Expand All @@ -952,20 +952,22 @@ pub trait Parser<'a, I: Input + ?Sized, O, E: ParserExtra<'a, I> = extra::Defaul
}
}

/// TODO
fn map_ctx<Ctx, F>(self, mapper: F) -> MapCtx<Self, F>
where
Self: Sized,
F: Fn(O, &E::Context) -> Ctx,
Ctx: 'a,
{
MapCtx {
parser: self,
mapper,
}
}

/// TODO
/// Run the previous contextual parser with the provided context
///
/// ```
/// # use chumsky::zero_copy::prelude::*;
/// # use chumsky::zero_copy::primitive::JustCfg;
///
/// let generic = just(b'0').configure(|cfg, ctx: &u8| cfg.seq(*ctx));
///
/// let parse_a = just::<_, _, extra::Default>(b'b').ignore_then(generic.with_ctx::<u8>(b'a'));
/// let parse_b = just::<_, _, extra::Default>(b'a').ignore_then(generic.with_ctx(b'b'));
///
/// assert_eq!(parse_a.parse(b"ba" as &[_]).into_result(), Ok::<_, Vec<EmptyErr>>(b'a'));
/// assert!(parse_a.parse(b"bb").has_errors());
/// assert_eq!(parse_b.parse(b"ab" as &[_]).into_result(), Ok(b'b'));
/// assert!(parse_b.parse(b"aa").has_errors());
/// ```
fn with_ctx<Ctx>(self, ctx: Ctx) -> WithCtx<Self, Ctx>
where
Self: Sized,
Expand Down
75 changes: 73 additions & 2 deletions src/zero_copy/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,13 @@ where
// fn iter(&self) -> Self::Iter<'_> { (*self).iter() }
// }

/// TODO
/// Configuration for [`just`], used in [`ConfigParser::configure`]
pub struct JustCfg<T> {
seq: Option<T>,
}

impl<T> JustCfg<T> {
/// TODO
/// Set the sequence to be used while parsing
pub fn seq(mut self, new_seq: T) -> Self {
self.seq = Some(new_seq);
self
Expand Down Expand Up @@ -552,6 +552,77 @@ where
go_extra!((C, OP));
}

/// See [`map_ctx`].
pub struct MapCtx<A, F> {
pub(crate) parser: A,
pub(crate) mapper: F,
}

impl<A: Copy, F: Copy> Copy for MapCtx<A, F> {}
impl<A: Clone, F: Clone> Clone for MapCtx<A, F> {
fn clone(&self) -> Self {
MapCtx {
parser: self.parser.clone(),
mapper: self.mapper.clone(),
}
}
}

impl<'a, I, O, E, A, F, Ctx> Parser<'a, I, O, E> for MapCtx<A, F>
where
I: Input + ?Sized,
E: ParserExtra<'a, I>,
A: Parser<'a, I, O, extra::Full<E::Error, E::State, Ctx>>,
F: Fn(&E::Context) -> Ctx,
Ctx: 'a,
{
fn go<M: Mode>(&self, inp: &mut InputRef<'a, '_, I, E>) -> PResult<M, O, E::Error> {
inp.with_ctx((self.mapper)(inp.ctx()), |inp| self.parser.go::<M>(inp))
}

go_extra!(O);
}

/// Apply a mapping function to the context of this parser. Note that this combinator will
/// behave differently from all other maps, in terms of which parsers it effects - while
/// other maps apply to the output of the parser, and thus read left-to-right, this one
/// applies to the _input_ of the parser, and as such applies right-to-left.
///
/// More technically, if all combinators form a 'tree' of parsers, where each node executes
/// its children in turn, normal maps apply up the tree. This means a parent mapper gets the
/// result of its children, applies the map, then passes the new result to its parent. This map,
/// however, applies down the tree. Context is provided from the parent, such as [`Parser::then_with_ctx`],
/// and gets altered before being provided to the children.
///
/// ```
/// # use chumsky::zero_copy::{prelude::*, error::Simple};
///
/// let upper = just(b'0').configure(|cfg, ctx: &u8| cfg.seq(*ctx));
///
/// let inc = one_of::<_, _, extra::Default>(b'a'..=b'z')
/// .then_with_ctx(map_ctx(|c: &u8| c.to_ascii_uppercase(), upper))
/// .slice()
/// .repeated()
/// .at_least(1)
/// .collect::<Vec<_>>();
///
/// assert_eq!(inc.parse(b"aAbB" as &[_]).into_result(), Ok(vec![b"aA" as &[_], b"bB"]));
/// assert!(inc.parse(b"aB").has_errors());
/// ```
pub fn map_ctx<'a, P, OP, I, E, F, Ctx>(mapper: F, parser: P) -> MapCtx<P, F>
where
F: Fn(&E::Context) -> Ctx,
Ctx: 'a,
I: Input + ?Sized,
P: Parser<'a, I, OP, E>,
E: ParserExtra<'a, I>,
{
MapCtx {
parser,
mapper,
}
}

/// See [`fn@todo`].
pub struct Todo<I: ?Sized, O, E>(PhantomData<(O, E, I)>);

Expand Down

0 comments on commit d48f139

Please sign in to comment.