use std::{
collections::BTreeSet,
fmt::{Debug, Display},
marker::PhantomData,
ops::Range,
};
use thiserror::Error;
mod combinator;
mod delimited;
mod pratt;
pub use combinator::Combinator;
pub use delimited::Delimited;
pub use derive_parser_macro::{Parse, Spanned, Token};
pub use pratt::{Pratt, Precedence};
pub trait Token: Clone + Spanned {
type Kind: Display + PartialEq;
fn kind(&self) -> Self::Kind;
}
pub trait Spanned {
type Span: Span;
fn span(&self) -> Self::Span;
}
macro_rules! impl_spanned {
(($n0:tt, $t1:ident)$(, $(($n:tt, $tn:ident)),*)?) => {
impl<$t1$(, $($tn),*)?> Spanned for ($t1, $($($tn),*)?)
where
$t1: Spanned,
$($($tn: Spanned<Span = <$t1>::Span>),*)?
{
type Span = <$t1>::Span;
fn span(&self) -> Self::Span {
self.0.span()
$($(.enclose(&self.$n.span()))*)?
}
}
};
}
variadics_please::all_tuples_enumerated!(impl_spanned, 1, 16, T);
pub trait Span {
fn enclose(&self, other: &Self) -> Self;
}
impl Span for () {
fn enclose(&self, _other: &Self) -> Self {
()
}
}
impl<N: Ord + Default + Clone> Span for Range<N> {
fn enclose(&self, other: &Self) -> Self {
if self == &Self::default() {
return other.clone();
} else if other == &Self::default() {
return self.clone();
}
Range {
start: (&self.start)
.min(&self.end)
.min(&other.start)
.min(&other.end)
.clone(),
end: (&self.start)
.max(&self.end)
.max(&other.start)
.max(&other.end)
.clone(),
}
}
}
pub trait Input: Debug {
type Token: Token + Debug;
type Checkpoint: Copy + Ord + Debug;
fn next(&mut self) -> Option<Self::Token>;
fn save(&self) -> Self::Checkpoint;
fn reset(&mut self, checkpoint: Self::Checkpoint);
}
pub trait Parse {
type Token: Debug;
type Output;
fn parse<I>(input: &mut I) -> Result<Success<Self::Output, I>, Error<I>>
where
I: Input<Token = Self::Token>;
}
impl<T: Debug> Parse for PhantomData<T> {
type Token = T;
type Output = Self;
fn parse<I>(_input: &mut I) -> Result<Success<Self::Output, I>, Error<I>>
where
I: Input<Token = Self::Token>,
{
Ok(Success(PhantomData, None))
}
}
#[derive(Clone)]
pub struct Success<O, I: Input>(#[doc(hidden)] pub O, #[doc(hidden)] pub Option<Error<I>>);
impl<O, I, T> Debug for Success<O, I>
where
O: Debug,
I: Input<Token = T> + Debug,
T: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Success")
.field(&self.0)
.field(&self.1)
.finish()
}
}
impl<O, I: Input> Success<O, I> {
pub fn merge<P>(&mut self, other: Success<P, I>) -> P {
let Some(_) = self.1 else {
self.1 = other.1;
return other.0;
};
let Some(e2) = other.1 else {
return other.0;
};
self.1 = Some(self.1.take().unwrap().merge(e2));
return other.0;
}
pub fn map<P, F>(self, fun: F) -> Success<P, I>
where
F: FnOnce(O) -> P,
{
Success(fun(self.0), self.1)
}
pub fn result(self) -> O {
self.0
}
}
impl<O, I: Input> From<O> for Success<O, I> {
fn from(value: O) -> Self {
Success(value, None)
}
}
#[derive(Debug, Error)]
pub struct Error<I>
where
I: Input,
{
pub position: I::Checkpoint,
pub expected: BTreeSet<String>,
pub found: Option<I::Token>,
pub committed: bool,
}
impl<I> Error<I>
where
I: Input,
{
pub fn merge(mut self, other: Error<I>) -> Self {
let committed = self.committed || other.committed;
if self.position == other.position {
self.expected.extend(other.expected.into_iter());
self.committed = committed;
self
} else {
let mut err = std::cmp::max_by_key(self, other, |e| e.position);
err.committed = committed;
err
}
}
pub fn label(mut self, label: String, pos: I::Checkpoint) -> Self {
if self.position <= pos {
self.expected.clear();
self.expected.insert(label);
}
self
}
}
impl<I> Display for Error<I>
where
I: Input,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Expected ")?;
if self.expected.len() > 1 {
let mut all_but_last = self.expected.iter().take(self.expected.len() - 1);
write!(f, "one of {}", all_but_last.next().unwrap())?;
for exp in all_but_last {
write!(f, ", {}", exp)?;
}
write!(f, " or {}", self.expected.iter().last().unwrap())?;
} else if let Some(first) = self.expected.first() {
write!(f, "{first}")?;
} else {
write!(f, "end of input")?;
};
if let Some(found) = &self.found {
write!(f, " but found {}", found.kind())
} else {
write!(f, " but found end of input")
}
}
}
impl<I> Clone for Error<I>
where
I: Input,
{
fn clone(&self) -> Self {
Error {
position: self.position.clone(),
expected: self.expected.clone(),
found: self.found.clone(),
committed: self.committed.clone(),
}
}
}