#![doc(html_root_url = "https://docs.rs/kparse")]
#![warn(absolute_paths_not_starting_with_crate)]
#![allow(box_pointers)]
#![warn(elided_lifetimes_in_paths)]
#![warn(explicit_outlives_requirements)]
#![warn(keyword_idents)]
#![warn(macro_use_extern_crate)]
#![warn(meta_variable_misuse)]
#![warn(missing_abi)]
#![warn(non_ascii_idents)]
#![warn(noop_method_call)]
#![warn(pointer_structural_match)]
#![warn(semicolon_in_expressions_from_macros)]
#![allow(single_use_lifetimes)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unreachable_pub)]
#![allow(unsafe_code)]
#![allow(unsafe_op_in_unsafe_fn)]
#![warn(unstable_features)]
#![allow(unused_crate_dependencies)]
#![allow(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_lifetimes)]
#![warn(unused_qualifications)]
#![allow(unused_results)]
#![warn(variant_size_differences)]
#![allow(clippy::uninlined_format_args)]
#![allow(clippy::type_complexity)]
pub mod combinators;
mod debug;
pub mod examples;
pub mod parser_error;
mod parser_ext;
pub mod provider;
pub mod source;
pub mod spans;
pub mod test;
pub mod token_error;
pub use crate::parser_error::ParserError;
pub use crate::token_error::TokenizerError;
use std::borrow::Borrow;
use crate::parser_ext::{
AllConsuming, Complete, Consumed, Cut, DelimitedBy, FromStrParser, IntoErr, MapRes,
OptPrecedes, Optional, OrElse, PNot, Peek, Precedes, Recognize, Terminated, Value, Verify,
WithCode, WithContext,
};
use crate::provider::{StdTracker, TrackData, TrackProvider};
use crate::source::{SourceBytes, SourceStr};
use nom::{AsBytes, InputIter, InputLength, InputTake, Offset, Parser, Slice};
use nom_locate::LocatedSpan;
use std::fmt::{Debug, Display};
use std::ops::RangeTo;
use std::str::FromStr;
pub mod prelude {
pub use crate::parser_error::AppendParserError;
pub use crate::provider::TrackProvider;
pub use crate::source::Source;
pub use crate::spans::{SpanFragment, SpanUnion};
pub use crate::test::Report;
pub use crate::{
define_span, Code, ErrInto, ErrOrNomErr, KParseError, KParser, ParseSpan, Track,
TrackResult, TrackedSpan,
};
}
pub type DynTrackProvider<'s, C, T> = &'s (dyn TrackProvider<C, T>);
pub type ParseSpan<'s, C, T> = LocatedSpan<T, DynTrackProvider<'s, C, T>>;
#[macro_export]
macro_rules! define_span {
($v:vis $name:ident = $code:ty, $typ:ty) => {
#[cfg(debug_assertions)]
$v type $name<'a> = ParseSpan<'a, $code, &'a $typ>;
#[cfg(not(debug_assertions))]
$v type $name<'a> = &'a $typ;
};
}
pub type ParserResult<C, I, O> = Result<(I, O), nom::Err<ParserError<C, I>>>;
pub type TokenizerResult<C, I, O> = Result<(I, O), nom::Err<TokenizerError<C, I>>>;
pub trait Code: Copy + Display + Debug + Eq {
const NOM_ERROR: Self;
}
pub trait KParseError<C, I> {
type WrappedError: Debug;
fn from(code: C, span: I) -> Self;
fn with_code(self, code: C) -> Self;
fn code(&self) -> Option<C>;
fn span(&self) -> Option<I>;
fn err(&self) -> Option<&Self::WrappedError>;
fn parts(&self) -> Option<(C, I, &Self::WrappedError)>;
}
pub trait ErrInto<E2> {
type Result;
fn err_into(self) -> Self::Result;
}
impl<I, O, E1, E2> ErrInto<E2> for Result<(I, O), nom::Err<E1>>
where
E2: From<E1>,
{
type Result = Result<(I, O), nom::Err<E2>>;
fn err_into(self) -> Self::Result {
match self {
Ok(v) => Ok(v),
Err(nom::Err::Error(e)) => Err(nom::Err::Error(e.into())),
Err(nom::Err::Failure(e)) => Err(nom::Err::Failure(e.into())),
Err(nom::Err::Incomplete(e)) => Err(nom::Err::Incomplete(e)),
}
}
}
pub trait ErrOrNomErr {
type WrappedError: Debug;
fn wrap(self) -> nom::Err<Self::WrappedError>;
}
pub trait KParser<I, O, E>
where
Self: Sized,
{
fn err_into<E2>(self) -> IntoErr<Self, O, E, E2>
where
E: Into<E2>;
fn with_code<C>(self, code: C) -> WithCode<Self, C>
where
C: Code,
E: KParseError<C, I>;
fn with_context<C, Y>(self, context: Y) -> WithContext<Self, C, E, Y>
where
C: Code,
I: Clone,
E: Into<ParserError<C, I>>,
Y: Clone + 'static;
fn map_res<TR, O2>(self, map: TR) -> MapRes<Self, O, TR, O2>
where
TR: Fn(O) -> Result<O2, nom::Err<E>>;
fn parse_from_str<C, O2>(self, code: C) -> FromStrParser<Self, C, O, O2>
where
C: Code,
O: InputIter<Item = char>,
O2: FromStr,
E: KParseError<C, I>;
fn value<O2>(self, value: O2) -> Value<Self, O, O2>
where
O2: Clone;
fn all_consuming<C>(self, code: C) -> AllConsuming<Self, C>
where
C: Code,
I: InputLength,
E: KParseError<C, I>;
fn complete<C>(self, code: C) -> Complete<Self, C>
where
C: Code,
I: Clone,
E: KParseError<C, I>;
fn cut(self) -> Cut<Self>;
fn opt(self) -> Optional<Self>;
fn recognize(self) -> Recognize<Self, O>
where
I: Clone + Slice<RangeTo<usize>> + Offset;
fn consumed(self) -> Consumed<Self>
where
I: Clone + Slice<RangeTo<usize>> + Offset;
fn terminated<PA, O2>(self, terminator: PA) -> Terminated<Self, PA, O2>
where
PA: Parser<I, O2, E>;
fn precedes<PA, O2>(self, successor: PA) -> Precedes<Self, PA, O>
where
PA: Parser<I, O2, E>;
fn opt_precedes<PA, O2>(self, successor: PA) -> OptPrecedes<Self, PA, O>
where
PA: Parser<I, O2, E>,
I: Clone;
fn delimited_by<PA, O2>(self, delimiter: PA) -> DelimitedBy<Self, PA, O2>
where
PA: Parser<I, O2, E>;
fn peek(self) -> Peek<Self>
where
I: Clone;
fn not<C>(self, code: C) -> PNot<Self, C, O>
where
C: Code,
E: KParseError<C, I>,
I: Clone;
fn or_else<PE, OE>(self, other: PE) -> OrElse<Self, PE, OE>
where
PE: Parser<I, OE, E>;
fn verify<V, C, O2>(self, verify: V, code: C) -> Verify<Self, V, C, O2>
where
C: Code,
V: Fn(&O2) -> bool,
O: Borrow<O2>,
O2: ?Sized,
E: KParseError<C, I>;
}
impl<T, I, O, E> KParser<I, O, E> for T
where
T: Parser<I, O, E>,
{
#[inline]
fn err_into<E2>(self) -> IntoErr<Self, O, E, E2>
where
E: Into<E2>,
{
IntoErr {
parser: self,
_phantom: Default::default(),
}
}
#[inline]
fn with_code<C>(self, code: C) -> WithCode<Self, C>
where
C: Code,
E: KParseError<C, I>,
{
WithCode { parser: self, code }
}
#[inline]
fn with_context<C, Y>(self, context: Y) -> WithContext<Self, C, E, Y>
where
C: Code,
I: Clone,
E: Into<ParserError<C, I>>,
Y: Clone + 'static,
{
WithContext {
parser: self,
context,
_phantom: Default::default(),
}
}
#[inline]
fn map_res<TR, O2>(self, map: TR) -> MapRes<Self, O, TR, O2>
where
TR: Fn(O) -> Result<O2, nom::Err<E>>,
{
MapRes {
parser: self,
map,
_phantom: Default::default(),
}
}
#[inline]
fn parse_from_str<C, O2>(self, code: C) -> FromStrParser<Self, C, O, O2>
where
C: Code,
O: InputIter<Item = char>,
O2: FromStr,
E: KParseError<C, I>,
{
FromStrParser {
parser: self,
code,
_phantom: Default::default(),
}
}
#[inline]
fn value<O2>(self, value: O2) -> Value<Self, O, O2>
where
O2: Clone,
{
Value {
parser: self,
value,
_phantom: Default::default(),
}
}
#[inline]
fn all_consuming<C>(self, code: C) -> AllConsuming<Self, C>
where
C: Code,
I: InputLength,
E: KParseError<C, I>,
{
AllConsuming { parser: self, code }
}
#[inline]
fn complete<C>(self, code: C) -> Complete<Self, C>
where
C: Code,
I: Clone,
E: KParseError<C, I>,
{
Complete { parser: self, code }
}
#[inline]
fn cut(self) -> Cut<Self> {
Cut { parser: self }
}
#[inline]
fn opt(self) -> Optional<Self> {
Optional { parser: self }
}
#[inline]
fn recognize(self) -> Recognize<Self, O>
where
I: Clone + Slice<RangeTo<usize>> + Offset,
{
Recognize {
parser: self,
_phantom: Default::default(),
}
}
#[inline]
fn consumed(self) -> Consumed<Self>
where
I: Clone + Slice<RangeTo<usize>> + Offset,
{
Consumed { parser: self }
}
#[inline]
fn terminated<PA, O2>(self, terminator: PA) -> Terminated<Self, PA, O2>
where
PA: Parser<I, O2, E>,
{
Terminated {
parser: self,
terminator,
_phantom: Default::default(),
}
}
#[inline]
fn precedes<PS, O2>(self, successor: PS) -> Precedes<Self, PS, O>
where
PS: Parser<I, O2, E>,
{
Precedes {
parser: self,
successor,
_phantom: Default::default(),
}
}
#[inline]
fn opt_precedes<PS, O2>(self, successor: PS) -> OptPrecedes<Self, PS, O>
where
PS: Parser<I, O2, E>,
I: Clone,
{
OptPrecedes {
parser: self,
successor,
_phantom: Default::default(),
}
}
#[inline]
fn delimited_by<PA, O2>(self, delimiter: PA) -> DelimitedBy<Self, PA, O2>
where
PA: Parser<I, O2, E>,
{
DelimitedBy {
parser: self,
delimiter,
_phantom: Default::default(),
}
}
#[inline]
fn peek(self) -> Peek<Self>
where
I: Clone,
{
Peek { parser: self }
}
#[inline]
fn not<C>(self, code: C) -> PNot<Self, C, O> {
PNot {
parser: self,
code,
_phantom: Default::default(),
}
}
#[inline]
fn or_else<PE, OE>(self, other: PE) -> OrElse<Self, PE, OE>
where
PE: Parser<I, OE, E>,
{
OrElse {
parser: self,
other,
_phantom: Default::default(),
}
}
#[inline]
fn verify<V, C, O2>(self, verify: V, code: C) -> Verify<Self, V, C, O2>
where
C: Code,
V: Fn(&O2) -> bool,
O: Borrow<O2>,
O2: ?Sized,
E: KParseError<C, I>,
{
Verify {
parser: self,
verify,
code,
_phantom: Default::default(),
}
}
}
pub struct Track;
impl Track {
pub fn new_tracker<C, I>() -> StdTracker<C, I>
where
C: Code,
I: Clone + Debug + AsBytes,
I: InputTake + InputLength + InputIter,
{
StdTracker::new()
}
#[cfg(debug_assertions)]
pub fn new_span<'s, C, I>(
provider: &'s impl TrackProvider<C, I>,
text: I,
) -> LocatedSpan<I, DynTrackProvider<'s, C, I>>
where
C: Code,
I: Clone + Debug + AsBytes,
I: InputTake + InputLength + InputIter,
I: 's,
{
provider.track_span(text)
}
#[cfg(not(debug_assertions))]
pub fn new_span<'s, C, I>(_provider: &'s impl TrackProvider<C, I>, text: I) -> I
where
C: Code,
I: Clone + Debug + AsBytes,
I: InputTake + InputLength + InputIter,
I: 's,
{
text
}
pub fn source_str(text: &str) -> SourceStr<'_> {
SourceStr::new(text)
}
pub fn source_bytes(text: &[u8]) -> SourceBytes<'_> {
SourceBytes::new(text)
}
#[inline(always)]
pub fn ok<C, I, O, E>(&self, rest: I, input: I, value: O) -> Result<(I, O), nom::Err<E>>
where
C: Code,
I: Clone + Debug,
I: TrackedSpan<C>,
I: InputTake + InputLength + InputIter,
E: KParseError<C, I> + Debug,
{
rest.track_ok(input);
rest.track_exit();
Ok((rest, value))
}
#[inline(always)]
pub fn err<C, I, O, E>(
&self,
err: E,
) -> Result<(I, O), nom::Err<<E as ErrOrNomErr>::WrappedError>>
where
C: Code,
I: Clone + Debug,
I: TrackedSpan<C>,
I: InputTake + InputLength + InputIter,
E: KParseError<C, I> + ErrOrNomErr + Debug,
{
match err.parts() {
None => Err(err.wrap()),
Some((code, span, e)) => {
span.track_err(code, e);
span.track_exit();
Err(err.wrap())
}
}
}
#[inline(always)]
pub fn ok_section<C, I>(&self, rest: I, input: I)
where
C: Code,
I: TrackedSpan<C>,
{
rest.track_ok(input);
}
#[inline(always)]
pub fn err_section<C, I, E>(&self, err: &E)
where
C: Code,
I: Clone + Debug,
I: TrackedSpan<C>,
I: InputTake + InputLength + InputIter,
E: KParseError<C, I> + Debug,
{
match err.parts() {
None => {}
Some((code, span, e)) => {
span.track_err(code, e);
}
}
}
#[inline(always)]
pub fn enter<C, I>(&self, func: C, span: I)
where
C: Code,
I: TrackedSpan<C>,
{
span.track_enter(func);
}
#[inline(always)]
pub fn debug<C, I>(&self, span: I, debug: String)
where
C: Code,
I: TrackedSpan<C>,
{
span.track_debug(debug);
}
#[inline(always)]
pub fn info<C, I>(&self, span: I, info: &'static str)
where
C: Code,
I: TrackedSpan<C>,
{
span.track_info(info);
}
#[inline(always)]
pub fn warn<C, I>(&self, span: I, warn: &'static str)
where
C: Code,
I: TrackedSpan<C>,
{
span.track_warn(warn);
}
}
pub trait TrackResult<C, I>
where
C: Code,
I: Clone + Debug,
I: TrackedSpan<C>,
I: InputTake + InputLength + InputIter + AsBytes,
{
fn track(self) -> Self;
fn track_as(self, code: C) -> Self;
}
impl<C, I, O, E> TrackResult<C, I> for Result<(I, O), nom::Err<E>>
where
C: Code,
I: Clone + Debug,
I: TrackedSpan<C>,
I: InputTake + InputLength + InputIter + AsBytes,
E: Debug,
nom::Err<E>: KParseError<C, I>,
{
#[inline(always)]
fn track(self) -> Self {
match self {
Ok((rest, token)) => Ok((rest, token)),
Err(e) => match e.parts() {
None => Err(e),
Some((code, span, err)) => {
span.track_err(code, err);
span.track_exit();
Err(e)
}
},
}
}
#[inline(always)]
fn track_as(self, code: C) -> Self {
match self {
Ok((rest, token)) => Ok((rest, token)),
Err(e) => {
let e = e.with_code(code);
match e.parts() {
None => Err(e),
Some((code, span, err)) => {
span.track_err(code, err);
span.track_exit();
Err(e)
}
}
}
}
}
}
pub trait TrackedSpan<C>
where
C: Code,
Self: Sized,
{
fn track_enter(&self, func: C);
fn track_debug(&self, debug: String);
fn track_info(&self, info: &'static str);
fn track_warn(&self, warn: &'static str);
fn track_ok(&self, parsed: Self);
fn track_err<E: Debug>(&self, code: C, err: &E);
fn track_exit(&self);
}
impl<'s, C, T> TrackedSpan<C> for LocatedSpan<T, DynTrackProvider<'s, C, T>>
where
C: Code,
T: Clone + Debug + AsBytes + InputTake + InputLength,
{
#[inline(always)]
fn track_enter(&self, func: C) {
self.extra.track(TrackData::Enter(func, clear_span(self)));
}
#[inline(always)]
fn track_debug(&self, debug: String) {
self.extra.track(TrackData::Debug(clear_span(self), debug));
}
#[inline(always)]
fn track_info(&self, info: &'static str) {
self.extra.track(TrackData::Info(clear_span(self), info));
}
#[inline(always)]
fn track_warn(&self, warn: &'static str) {
self.extra.track(TrackData::Warn(clear_span(self), warn));
}
#[inline(always)]
fn track_ok(&self, parsed: LocatedSpan<T, DynTrackProvider<'s, C, T>>) {
self.extra
.track(TrackData::Ok(clear_span(self), clear_span(&parsed)));
}
#[inline(always)]
fn track_err<E: Debug>(&self, code: C, err: &E) {
self.extra
.track(TrackData::Err(clear_span(self), code, format!("{:?}", err)));
}
#[inline(always)]
fn track_exit(&self) {
self.extra.track(TrackData::Exit());
}
}
fn clear_span<C, T>(span: &LocatedSpan<T, DynTrackProvider<'_, C, T>>) -> LocatedSpan<T, ()>
where
C: Code,
T: AsBytes + Clone,
{
unsafe {
LocatedSpan::new_from_raw_offset(
span.location_offset(),
span.location_line(),
span.fragment().clone(),
(),
)
}
}
impl<C, T> TrackedSpan<C> for LocatedSpan<T, ()>
where
T: Clone + Debug,
T: InputTake + InputLength + AsBytes,
C: Code,
{
#[inline(always)]
fn track_enter(&self, _func: C) {}
#[inline(always)]
fn track_debug(&self, _debug: String) {}
#[inline(always)]
fn track_info(&self, _info: &'static str) {}
#[inline(always)]
fn track_warn(&self, _warn: &'static str) {}
#[inline(always)]
fn track_ok(&self, _parsed: LocatedSpan<T, ()>) {}
#[inline(always)]
fn track_err<E>(&self, _func: C, _err: &E) {}
#[inline(always)]
fn track_exit(&self) {}
}
impl<'s, C> TrackedSpan<C> for &'s str
where
C: Code,
{
#[inline(always)]
fn track_enter(&self, _func: C) {}
#[inline(always)]
fn track_debug(&self, _debug: String) {}
#[inline(always)]
fn track_info(&self, _info: &'static str) {}
#[inline(always)]
fn track_warn(&self, _warn: &'static str) {}
#[inline(always)]
fn track_ok(&self, _input: Self) {}
#[inline(always)]
fn track_err<E>(&self, _func: C, _err: &E) {}
#[inline(always)]
fn track_exit(&self) {}
}
impl<'s, C> TrackedSpan<C> for &'s [u8]
where
C: Code,
{
#[inline(always)]
fn track_enter(&self, _func: C) {}
#[inline(always)]
fn track_debug(&self, _debug: String) {}
#[inline(always)]
fn track_info(&self, _info: &'static str) {}
#[inline(always)]
fn track_warn(&self, _warn: &'static str) {}
#[inline(always)]
fn track_ok(&self, _input: Self) {}
#[inline(always)]
fn track_err<E>(&self, _func: C, _err: &E) {}
#[inline(always)]
fn track_exit(&self) {}
}