use {
crate::{
error::{FullParsingError, ParsingError, ParsingResult},
input::Input,
pattern::{IntoPattern, Pattern},
tuple::{Tuple, first, map_second, tuple},
utils::PathLike,
},
std::{
convert::Infallible,
fmt::{Debug, Display},
iter::FusedIterator,
marker::PhantomData,
mem::replace,
},
};
pub trait MappingParser<In, Out, NewOut, Reason = Infallible>:
Sized + FnMut(In, Out) -> ParsingResult<In, NewOut, Reason>
{
}
impl<In, Out, NewOut, Reason, F> MappingParser<In, Out, NewOut, Reason> for F where
F: Sized + FnMut(In, Out) -> ParsingResult<In, NewOut, Reason>
{
}
pub trait Parser<In: Input, Out, Reason = Infallible>:
Sized + FnMut(In) -> ParsingResult<In, Out, Reason>
{
#[expect(clippy::missing_errors_doc)]
fn parse(&mut self, input: In) -> ParsingResult<In, Out, Reason> {
self(input)
}
fn filter(mut self, mut f: impl FnMut(&Out) -> bool) -> impl Parser<In, Out, Reason> {
move |src| match self(src.clone()) {
Ok((rest, res)) if f(&res) => Ok((rest, res)),
Ok(_) => Err(ParsingError::new_recoverable(src)),
Err(err) => Err(err),
}
}
fn filter_fatal(
mut self,
reason: Reason,
mut f: impl FnMut(&Out) -> bool,
) -> impl Parser<In, Out, Reason>
where
Reason: Clone,
{
move |src| match self(src.clone()) {
Ok((rest, res)) if f(&res) => Ok((rest, res)),
Ok(_) => Err(ParsingError::new(src, reason.clone())),
Err(err) => Err(err),
}
}
fn map_reason<NewReason>(
mut self,
mut f: impl FnMut(Reason) -> NewReason,
) -> impl Parser<In, Out, NewReason> {
move |src| self(src).map_err(|e| e.map_reason(&mut f))
}
fn adapt_reason<NewReason>(mut self) -> impl Parser<In, Out, NewReason>
where
Infallible: From<Reason>,
{
move |i| self(i).map_err(ParsingError::adapt_reason)
}
fn map<NewOut>(
mut self,
mut parser: impl MappingParser<In, Out, NewOut, Reason>,
) -> impl Parser<In, NewOut, Reason> {
move |src| self(src).and_then(|(i, o)| parser(i, o))
}
fn map_out<NewOut>(
mut self,
mut f: impl FnMut(Out) -> NewOut,
) -> impl Parser<In, NewOut, Reason> {
move |src| self(src).map(map_second(&mut f))
}
fn map_until<NewOut>(
mut self,
mut f: impl FnMut(Out) -> Option<NewOut>,
) -> impl Parser<In, NewOut, Reason> {
move |mut src| {
let end = src.clone().end();
loop {
let (rest, value) = self(replace(&mut src, end.clone())).map(map_second(&mut f))?;
src = rest;
let Some(value) = value else {
continue;
};
return Ok((src, value));
}
}
}
#[cfg(feature = "nightly")]
fn call<F>(mut self, mut f: F) -> impl Parser<In, F::Output, Reason>
where
F: FnMut<Out>,
Out: core::marker::Tuple,
{
move |src| self(src).map(map_second(|x| f.call_mut(x)))
}
fn or(mut self, mut parser: impl Parser<In, Out, Reason>) -> impl Parser<In, Out, Reason> {
move |src| {
let fallback = src.clone();
match self(src) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() => parser(fallback),
Err(err) => Err(err),
}
}
}
fn or_nonempty(
mut self,
mut parser: impl Parser<In, Out, Reason>,
) -> impl Parser<In, Out, Reason> {
move |src| {
let fallback = src.clone();
match self(src) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() && !err.rest.is_empty() => parser(fallback),
Err(err) => Err(err),
}
}
}
fn or_map_rest(mut self, mut f: impl FnMut(In) -> Out) -> impl Parser<In, Out, Reason> {
move |src| {
let fallback = src.clone();
match self(src) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() && !err.rest.is_empty() => {
Ok((fallback.clone().end(), f(fallback)))
}
Err(err) => Err(err),
}
}
}
fn or_value(mut self, value: Out) -> impl Parser<In, Out, Reason>
where
Out: Clone,
{
move |src| {
let fallback = src.clone();
match self(src) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() => Ok((fallback, value.clone())),
Err(err) => Err(err),
}
}
}
fn and<Other>(
mut self,
mut parser: impl Parser<In, Other, Reason>,
) -> impl Parser<In, (Out, Other), Reason> {
move |src| {
let (rest, out) = self(src.clone())?;
match parser(rest) {
Ok((rest, new_out)) => Ok((rest, (out, new_out))),
Err(mut err) => {
if err.is_recoverable() {
err.rest = src;
}
Err(err)
}
}
}
}
fn and_value<Other: Clone>(mut self, value: Other) -> impl Parser<In, (Out, Other), Reason> {
move |src| {
let (rest, out) = self(src)?;
Ok((rest, (out, value.clone())))
}
}
fn add<New>(
mut self,
mut parser: impl Parser<In, New, Reason>,
) -> impl Parser<In, Out::Appended<New>, Reason>
where
Out: Tuple,
{
move |src| {
let (rest, out) = self(src.clone())?;
match parser(rest) {
Ok((rest, new_out)) => Ok((rest, out.append(new_out))),
Err(mut err) => {
if err.is_recoverable() {
err.rest = src;
}
Err(err)
}
}
}
}
fn add_value<Other: Clone>(
mut self,
value: Other,
) -> impl Parser<In, Out::Appended<Other>, Reason>
where
Out: Tuple,
{
move |src| {
let (rest, out) = self(src)?;
Ok((rest, out.append(value.clone())))
}
}
fn then<NewOut>(
mut self,
mut parser: impl Parser<In, NewOut, Reason>,
) -> impl Parser<In, NewOut, Reason> {
move |src| {
let rest = self(src.clone())?.0;
parser(rest).map_err(|mut err| {
if err.is_recoverable() {
err.rest = src;
}
err
})
}
}
fn skip<Skipped>(
mut self,
mut parser: impl Parser<In, Skipped, Reason>,
) -> impl Parser<In, Out, Reason> {
move |src| {
let (rest, out) = self(src.clone())?;
match parser(rest) {
Ok((rest, _)) => Ok((rest, out)),
Err(mut err) => {
if err.is_recoverable() {
err.rest = src;
}
Err(err)
}
}
}
}
fn expect<NewReason: Clone>(mut self, expected: NewReason) -> impl Parser<In, Out, NewReason> {
move |src| self(src).map_err(|e| e.reason(expected.clone()))
}
fn or_reason(mut self, reason: Reason) -> impl Parser<In, Out, Reason>
where
Reason: Clone,
{
move |src| self(src).map_err(|e| e.or_reason(reason.clone()))
}
fn or_reason_if_nonempty(mut self, reason: Reason) -> impl Parser<In, Out, Reason>
where
Reason: Clone,
{
move |src| self(src).map_err(|e| e.or_reason_if_nonempty(reason.clone()))
}
fn and_span(self) -> impl Parser<In, (Out, In), Reason> {
self.map_out(tuple).add_span()
}
fn add_span(mut self) -> impl Parser<In, Out::Appended<In>, Reason>
where
Out: Tuple,
{
move |src| {
let (rest, out) = self(src.clone())?;
let end = src.len().saturating_sub(rest.len());
let consumed = src.before(end);
Ok((rest, out.append(consumed)))
}
}
fn and_rest(self) -> impl Parser<In, (Out, In), Reason> {
self.map_out(tuple).add_rest()
}
fn add_rest(mut self) -> impl Parser<In, Out::Appended<In>, Reason>
where
Out: Tuple,
{
move |src| self(src).map(|(rest, out)| (rest.clone(), out.append(rest)))
}
fn maybe(mut self) -> impl Parser<In, Option<Out>, Reason> {
move |src| match self(src) {
Ok((rest, out)) => Ok((rest, Some(out))),
Err(err) if err.is_recoverable() => Ok((err.rest, None)),
Err(err) => Err(err),
}
}
fn ok(mut self) -> impl Parser<In, bool, Reason> {
move |src| match self(src) {
Ok((rest, _)) => Ok((rest, true)),
Err(err) if err.is_recoverable() => Ok((err.rest, false)),
Err(err) => Err(err),
}
}
fn repeat(mut self) -> impl Parser<In, (), Reason> {
move |mut src| loop {
match self(src) {
Ok((rest, _)) => src = rest,
Err(err) if err.is_recoverable() => return Ok((err.rest, ())),
Err(err) => return Err(err),
}
}
}
fn collect<C: Default + Extend<Out>>(mut self) -> impl Parser<In, C, Reason> {
move |mut src| {
let mut res = C::default();
loop {
match self(src) {
Ok((rest, new)) => {
res.extend([new]);
src = rest;
}
Err(err) if err.is_recoverable() => return Ok((err.rest, res)),
Err(err) => return Err(err),
}
}
}
}
fn dbg(mut self, label: impl Display) -> impl Parser<In, Out, Reason>
where
In: Input,
Out: Debug,
Reason: Debug,
{
move |src| match self(src) {
Ok((rest, out)) => {
let until = rest.char_indices().nth(16).map_or(rest.len(), |x| x.0);
let r = &rest[..until].escape_debug();
eprintln!("{label}: Ok({out:?}) : {r}...");
Ok((rest, out))
}
Err(err) => {
let until = err
.rest
.char_indices()
.nth(16)
.map_or(err.rest.len(), |x| x.0);
let r = &err.rest[..until].escape_debug();
eprintln!("{label}: Err({:?}) : {r}...", err.reason);
Err(err)
}
}
}
fn iter(self, input: In) -> Iter<In, Out, Reason, Self> {
Iter {
input: Some(input),
parser: self,
_params: PhantomData,
}
}
fn with_full_error<'a>(
mut self,
path: impl PathLike<'a>,
full_src: &'a str,
) -> impl FnOnce(In) -> Result<(In, Out), FullParsingError<'a, Reason>>
where
In: Input,
{
move |src| self(src).map_err(|e| e.with_src_loc(path, full_src))
}
}
impl<In, Out, Reason, F> Parser<In, Out, Reason> for F
where
In: Input,
F: FnMut(In) -> ParsingResult<In, Out, Reason>,
{
}
pub struct Iter<In, Out, Reason, P> {
input: Option<In>,
parser: P,
_params: PhantomData<(Out, Reason)>,
}
impl<In, Out, Reason, P> Iterator for Iter<In, Out, Reason, P>
where
In: Input,
P: Parser<In, Out, Reason>,
{
type Item = Result<Out, ParsingError<In, Reason>>;
fn next(&mut self) -> Option<Self::Item> {
let input = self.input.take()?;
match (self.parser)(input) {
Ok((rest, res)) => {
self.input = Some(rest);
Some(Ok(res))
}
Err(err) if err.is_recoverable() => None,
Err(err) => Some(Err(err)),
}
}
}
impl<In, Out, Reason, P> FusedIterator for Iter<In, Out, Reason, P>
where
In: Input,
P: Parser<In, Out, Reason>,
{
}
impl<In, Out, Reason, P> Iter<In, Out, Reason, P>
where
In: Input,
P: Parser<In, Out, Reason>,
{
pub const fn remainder(&self) -> Option<&In> {
self.input.as_ref()
}
}
pub fn ready<In: Input, T: Clone, Reason>(value: T) -> impl Parser<In, T, Reason> {
move |i| Ok((i, value.clone()))
}
pub fn one<In: Input, Reason>(pat: impl IntoPattern) -> impl Parser<In, In, Reason> {
let pat = pat.into_pattern();
move |input| {
pat.immediate_match(input)
.map_err(ParsingError::new_recoverable)
}
}
pub fn many<In: Input, Reason>(pat: impl IntoPattern) -> impl Parser<In, In, Reason> {
let pat = pat.into_pattern();
move |input| Ok(pat.immediate_matches(input))
}
pub fn until<In: Input, Reason>(pat: impl IntoPattern) -> impl Parser<In, In, Reason> {
let pat = pat.into_pattern();
move |input| {
let input_len = input.len();
Ok({
pat.first_match(input)
.map_or_else(|input| input.split_at(input_len).rev(), map_second(first))
})
}
}
pub fn until_ex<In: Input, Reason>(pat: impl IntoPattern) -> impl Parser<In, In, Reason> {
let pat = pat.into_pattern();
move |input| {
pat.first_match_ex(input)
.map(map_second(first))
.map_err(ParsingError::new_recoverable)
}
}
pub fn group<In: Input>(open: impl IntoPattern, close: impl Pattern) -> impl Parser<In, In, ()> {
let open = open.into_pattern();
let close = close.into_pattern();
move |input| {
let Ok((mut rest, _)) = open.immediate_match(&*input) else {
return Err(ParsingError::new_recoverable(input));
};
let mut nesting = 1;
while nesting > 0 {
let (after_open, (before_open, open)) =
open.first_match_ex(rest).unwrap_or(("", (rest, "")));
let (after_close, (before_close, close)) =
close.first_match_ex(rest).unwrap_or(("", (rest, "")));
if [open, close] == ["", ""] {
let rest_start = input.len() - rest.len();
return Err(ParsingError::new(input.after(rest_start), ()));
}
if before_open.len() < before_close.len() {
rest = after_open;
nesting += 1;
} else {
rest = after_close;
nesting -= 1;
}
}
let res_len = input.len() - rest.len();
Ok(input.split_at(res_len).rev())
}
}
pub fn group_ex<In: Input>(
open: impl IntoPattern,
close: impl IntoPattern,
) -> impl Parser<In, In, ()> {
let open = open.into_pattern();
let close = close.into_pattern();
move |input| {
let input = match open.immediate_match(input) {
Ok((rest, _)) => rest,
Err(input) => return Err(ParsingError::new_recoverable(input)),
};
let mut rest = &*input;
let mut nesting = 1;
let mut close_len = 0;
while nesting > 0 {
let (after_open, (before_open, open)) =
open.first_match_ex(rest).unwrap_or(("", (rest, "")));
let (after_close, (before_close, close)) =
close.first_match_ex(rest).unwrap_or(("", (rest, "")));
if [open, close] == ["", ""] {
let rest_start = input.len() - rest.len();
return Err(ParsingError::new(input.after(rest_start), ()));
}
if before_open.len() < before_close.len() {
rest = after_open;
nesting += 1;
} else {
rest = after_close;
close_len = close.len();
nesting -= 1;
}
}
let res_len = input.len() - rest.len() - close_len;
Ok(input
.split_at(res_len)
.map_second(|rest| rest.after(close_len))
.rev())
}
}