glue 0.8.7

Glue is a parser combinator framework for parsing text based formats, it is easy to use and relatively fast too.
Documentation
//! Parser combinators for matching structures.

use crate::types::*;

#[inline]
/// Match a structure with left and right hand delimiters.
///
/// ```
/// # use glue::combinators::structures::*;
/// # use glue::prelude::*;
/// assert_eq!(
///     delimited(is('['), take(1..3, is(any)), is(']')).parse("[123]"),
///     Ok((
///         ParserContext {
///             input: "[123]",
///             bounds: 4..5,
///         },
///         "123"
///     ))
/// );
/// ```
pub fn delimited<'a, Lhs, LhsRes, Par, ParRes, Rhs, RhsRes>(
    mut prefix: Lhs,
    mut parser: Par,
    mut suffix: Rhs,
) -> impl Parser<'a, ParRes>
where
    Lhs: Parser<'a, LhsRes>,
    Par: Parser<'a, ParRes>,
    Rhs: Parser<'a, RhsRes>,
{
    move |ctx| {
        prefix
            .parse(ctx)
            .and_then(|(ctx, _)| parser.parse(ctx))
            .and_then(|(ctx, res)| match suffix.parse(ctx) {
                Ok((ctx, _)) => Ok(ctx.with_data(res)),
                Err(error) => Err(error),
            })
            .map_error(|error| SourceError::Ranges(vec![error]))
    }
}

#[inline]
/// Match a structure with left hand delimiter.
///
/// ```
/// # use glue::combinators::structures::*;
/// # use glue::prelude::*;
/// let ctx = ParserContext::from("$123");
///
/// assert_eq!(
///     left_delimited(is('$'), take(.., is(digit))).parse(ctx.clone()),
///     Ok((ctx.select(1..4), "123"))
/// );
/// ```
pub fn left_delimited<'a, Lhs, LhsRes, Par, ParRes>(
    mut left: Lhs,
    mut parser: Par,
) -> impl Parser<'a, ParRes>
where
    Lhs: Parser<'a, LhsRes>,
    Par: Parser<'a, ParRes>,
{
    move |ctx| {
        left.parse(ctx)
            .and_then(|ctx| parser.parse(ctx))
            .map_error(|error| SourceError::Ranges(vec![error]))
    }
}

#[inline]
/// Match a structure with right hand delimiter.
///
/// ```
/// # use glue::combinators::structures::*;
/// # use glue::prelude::*;
/// let ctx = ParserContext::from("123%");
///
/// assert_eq!(
///     right_delimited(take(.., is(digit)), is('%')).parse(ctx.clone()),
///     Ok((ctx.select(3..4), "123"))
/// );
/// ```
pub fn right_delimited<'a, Par, ParRes, Rhs, RhsRes>(
    mut parser: Par,
    mut right: Rhs,
) -> impl Parser<'a, ParRes>
where
    Par: Parser<'a, ParRes>,
    Rhs: Parser<'a, RhsRes>,
{
    move |ctx| {
        parser
            .parse(ctx)
            .and_then(|(ctx, res)| match right.parse(ctx) {
                Ok((ctx, _)) => Ok(ctx.with_data(res)),
                Err(error) => Err(error),
            })
            .map_error(|error| SourceError::Ranges(vec![error]))
    }
}

#[inline]
/// Match a structure that consists of two parsers separated by another.
///
/// ```
/// # use glue::combinators::structures::*;
/// # use glue::prelude::*;
/// assert_eq!(
///     separated(is(digit), is(one_of("+-")), is(digit)).parse("1+2"),
///     Ok((
///         ParserContext {
///             input: "1+2",
///             bounds: 2..3,
///         },
///         ("1", "2"),
///     ))
/// );
/// ```
pub fn separated<'a, Lhs, LhsRes, Sep, SepRes, Rhs, RhsRes>(
    mut left: Lhs,
    mut separator: Sep,
    mut right: Rhs,
) -> impl Parser<'a, (LhsRes, RhsRes)>
where
    Lhs: Parser<'a, LhsRes>,
    Sep: Parser<'a, SepRes>,
    Rhs: Parser<'a, RhsRes>,
{
    move |ctx| {
        left.parse(ctx)
            .and_then(|(ctx, bef_res)| {
                separator.parse(ctx).and_then(|ctx| {
                    right
                        .parse(ctx)
                        .and_then(|(ctx, aft_res)| Ok(ctx.with_data((bef_res, aft_res))))
                })
            })
            .map_error(|error| SourceError::Ranges(vec![error]))
    }
}