#parser-combinator #parser #combinator #error #composition #macro #approach

abortable_parser

A parser combinator library with an emphasis on error handling

8 releases

0.2.6 Nov 2, 2021
0.2.5 Nov 2, 2021
0.2.4 Apr 29, 2021
0.2.3 Feb 2, 2019
0.1.0 Oct 10, 2018

#135 in Parser tooling

24 downloads per month
Used in ucg

Apache-2.0

70KB
1.5K SLoC

Abortable Parser

Build Status

A parser combinator library in rust with an emphasis on error handling. Heavily inspired by nom in it's approach to macro composition.


lib.rs:

An opinionated parser combinator library with a focus on fully abortable parsing and easy error handling.

The approach to macro composition is heavily inspired by nom. It focuses on a simple API for combinators, and easy error handling.

We have a number of macros that assist in the gneration or handling of each type of error.

Simple parsing of a url.

#[macro_use]
extern crate abortable_parser;
use abortable_parser::iter::StrIter;
use abortable_parser::{Result, eoi, ascii_ws};

make_fn!(proto<StrIter, &str>,
    do_each!(
        proto => until!(text_token!("://")),
        _ => must!(text_token!("://")),
        (proto)
    )
);

make_fn!(domain<StrIter, &str>,
    do_each!(
        // domains do not start with a slash
        _ => peek!(not!(text_token!("/"))),
        domain => until!(either!(
            discard!(text_token!("/")),
            discard!(ascii_ws),
            eoi)),
        (domain)
    )
);

make_fn!(path<StrIter, &str>,
     until!(either!(discard!(ascii_ws), eoi))
);

make_fn!(full_url<StrIter, (Option<&str>, Option<&str>, Option<&str>)>,
    do_each!(
        protocol => proto,
        // If we match the protocol then we must have a domain.
        // This is an example of an unrecoverable parsing error so we
        // abort with the must! macro if it doesn't match.
        domain => must!(domain),
        path => optional!(path),
        (Some(protocol), Some(domain), path)
    )
);

make_fn!(relative_url<StrIter, (Option<&str>, Option<&str>, Option<&str>)>,
    do_each!(
        _ => not!(either!(text_token!("//"), proto)),
        // we require a valid path for relative urls.
        path => path,
        (None, None, Some(path))
    )
);

make_fn!(url<StrIter, (Option<&str>, Option<&str>, Option<&str>)>,
    either!(
        full_url,
        relative_url,
    )
);

let iter = StrIter::new("http://example.com/some/path ");
let result = url(iter);
assert!(result.is_complete());
if let Result::Complete(_, (proto, domain, path)) = result {
    assert!(proto.is_some());
    assert!(domain.is_some());
    if let Some(domain) = domain {
        assert_eq!(domain, "example.com");
    }
    assert!(path.is_some());
    if let Some(path) = path {
        assert_eq!(path, "/some/path");
    }
}

let bad_input = StrIter::new("http:///some/path");
let bad_result = url(bad_input);
assert!(bad_result.is_abort());

No runtime deps