pub mod tuple;
use core::{fmt::{Display, Formatter}, num::NonZeroU32};
use core::{convert::Infallible, fmt::Debug};
use std::{error::Error, path::Path};
use tuple::{first, map_second, rev, second, tuple, Tuple};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Location {
line: NonZeroU32,
col: u32,
}
impl Default for Location {
fn default() -> Self {
Self {
line: unsafe { NonZeroU32::new(1).unwrap_unchecked() },
col: 0
}
}
}
impl Display for Location {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "{}:{}", self.line, self.col)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct ParsingError<'rest, Expectation> {
rest: &'rest str,
expected: Option<Expectation>,
}
#[derive(Debug)]
pub struct FullParsingError<'path, Expectation> {
at: Location,
path: &'path Path,
expected: Option<Expectation>,
}
impl<Expectation: Display> Display for FullParsingError<'_, Expectation> {
fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
write!(f, "parsing error at {}:{}", self.path.display(), self.at)?;
if let Some(expected) = &self.expected {
write!(f, ": {expected}")?;
}
Ok(())
}
}
impl<Expectation: Error> Error for FullParsingError<'_, Expectation> {}
impl<'rest, Expectation> ParsingError<'rest, Expectation> {
pub const fn new(rest: &'rest str, expected: Expectation) -> Self {
Self { rest, expected: Some(expected) }
}
pub const fn new_recoverable(rest: &'rest str) -> Self {
Self { rest, expected: None }
}
pub const fn is_recoverable(&self) -> bool {
self.expected.is_none()
}
pub fn expectation<NewExpectation>(self, expected: NewExpectation)
-> ParsingError<'rest, NewExpectation>
{
ParsingError { expected: Some(expected), rest: self.rest }
}
pub fn narrow_expectation<NewExpectation>(self, expected: NewExpectation)
-> ParsingError<'rest, NewExpectation>
{
ParsingError { expected: self.expected.map(|_| expected), rest: self.rest }
}
pub fn with_src_loc<'path>(self, path: &'path Path, src: &str)
-> FullParsingError<'path, Expectation>
{
let Some(progress) = src.len().checked_sub(self.rest.len()) else {
return FullParsingError { at: Location::default(), expected: self.expected, path }
};
FullParsingError {
at: src.bytes().take(progress).fold(Location::default(), |loc, b| match b {
b'\n' => Location { line: loc.line.saturating_add(1), col: 0 },
_ => Location { col: loc.col.saturating_add(1), ..loc },
}),
expected: self.expected,
path,
}
}
}
pub type ParsingResult<'src, T = (), Expectation = Infallible> = core::result::Result<
(&'src str, T),
ParsingError<'src, Expectation>,
>;
pub trait Parser<'input, T = (), Expectation = Infallible>:
Sized + FnOnce(&'input str) -> ParsingResult<'input, T, Expectation>
{
fn filter(self, f: impl FnOnce(&T) -> bool)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, Expectation>
{
move |input| match self(input) {
Ok((rest, res)) if f(&res) => Ok((rest, res)),
Ok(_) => Err(ParsingError::new_recoverable(input)),
Err(err) => Err(err),
}
}
fn map<U>(self, f: impl FnOnce(T) -> U)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, U, Expectation>
{
move |input| self(input).map(map_second(f))
}
fn or(self, parser: impl FnOnce(&'input str) -> ParsingResult<'input, T, Expectation>)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, Expectation>
{
move |input| match self(input) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() => parser(input),
Err(err) => Err(err),
}
}
fn or_map_rest(self, f: impl FnOnce(&'input str) -> T)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, Expectation>
{
move |input| match self(input) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() => Ok(("", f(err.rest))),
Err(err) => Err(err),
}
}
fn or_value(self, value: T)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, Expectation>
{
move |input| match self(input) {
Ok(res) => Ok(res),
Err(err) if err.is_recoverable() => Ok((err.rest, value)),
Err(err) => Err(err),
}
}
fn and<U>(self, parser: impl FnOnce(&'input str) -> ParsingResult<'input, U, Expectation>)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, (T, U), Expectation>
{
move |input| {
let (rest, out) = self(input)?;
let (rest, new_out) = parser(rest)?;
Ok((rest, (out, new_out)))
}
}
fn add<U>(self, parser: impl FnOnce(&'input str) -> ParsingResult<'input, U, Expectation>)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T::Appended<U>, Expectation>
where
T: Tuple,
{
move |input| {
let (rest, out) = self(input)?;
let (rest, new_out) = parser(rest)?;
Ok((rest, out.append(new_out)))
}
}
fn then<U>(self, parser: impl FnOnce(&'input str) -> ParsingResult<'input, U, Expectation>)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, U, Expectation>
{
move |input| {
let rest = self(input)?.0;
let (rest, out) = parser(rest)?;
Ok((rest, out))
}
}
fn skip<U>(self, parser: impl FnOnce(&'input str) -> ParsingResult<'input, U, Expectation>)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, Expectation>
{
move |input| {
let (rest, out) = self(input)?;
let rest = parser(rest)?.0;
Ok((rest, out))
}
}
fn maybe_skip<U>(self, parser: impl FnOnce(&'input str) -> ParsingResult<'input, U, Expectation>)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, Expectation>
{
move |input| {
let (rest, out) = self(input)?;
let rest = parser(rest).map_or(rest, first);
Ok((rest, out))
}
}
fn expect<NewExpectation>(self, expected: NewExpectation)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, NewExpectation>
{
move |input| self(input).map_err(|e| e.expectation(expected))
}
fn narrow_expectation<NewExpectation>(self, expected: NewExpectation)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T, NewExpectation>
{
move |input| self(input).map_err(|e| e.narrow_expectation(expected))
}
fn get_span(self)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, (T, &'input str), Expectation>
{
self.map(tuple).add_span()
}
fn add_span(self)
-> impl FnOnce(&'input str)
-> ParsingResult<'input, T::Appended<&'input str>, Expectation>
where
T: Tuple,
{
move |input| {
let (rest, out) = self(input)?;
let consumed = unsafe {
input.get_unchecked(.. input.len().saturating_sub(rest.len()))
};
Ok((rest, out.append(consumed)))
}
}
fn repeat(self) -> impl FnOnce(&'input str) -> ParsingResult<'input, (), Expectation>
where
Self: Clone
{
move |input| loop {
match self.clone()(input) {
Ok(_) => (),
Err(err) if err.is_recoverable() => return Ok((err.rest, ())),
Err(err) => return Err(err),
}
}
}
fn parse_with_err_loc<'path>(self, path: &'path Path, input: &'input str)
-> Result<T, FullParsingError<'path, Expectation>>
{
self(input).map_err(|e| e.with_src_loc(path, input)).map(second)
}
}
impl<'input, T, Expectation, F> Parser<'input, T, Expectation> for F
where
F: FnOnce(&'input str) -> ParsingResult<'input, T, Expectation>,
{}
pub fn parse_any_char(input: &str) -> ParsingResult<char> {
let mut iter = input.chars();
iter.next().map(|ch| (iter.as_str(), ch)).ok_or(ParsingError::new_recoverable(input))
}
pub fn parse_char<'input>(ch: char) -> impl Parser<'input, char> {
parse_any_char.filter(move |x| *x == ch)
}
pub fn parse_exact(prefix: &str) -> impl Parser<&str> {
move |input| prefix.strip_prefix(prefix)
.map(|rest| (rest, prefix))
.ok_or(ParsingError::new_recoverable(input))
}
pub fn parse_until<'input>(pred: impl Fn(&char) -> bool) -> impl Parser<'input, &'input str> {
move |input| input.find(|c| pred(&c))
.map(|id| input.split_at(id).rev())
.ok_or(ParsingError::new_recoverable(input))
}
pub fn parse_until_exact(delimiter: &str) -> impl Parser<&str> {
move |input| input.split_once(delimiter)
.map(rev)
.ok_or(ParsingError::new_recoverable(input))
}
pub fn parse_while<'input>(pred: impl Fn(&char) -> bool) -> impl Parser<'input, &'input str> {
parse_until(move |c| !pred(c))
}
pub fn parse_group<'input>(open: char, close: char) -> impl Parser<'input, &'input str, ()> {
move |original_input| {
let (input, _) = parse_char(open).expect(())(original_input)?;
let mut depth = 0usize;
for (at, ch) in input.char_indices() {
if ch == close {
if depth == 0 {
let (res, src) = input.split_at(at);
return Ok((&src[1..], res));
}
depth -= 1
} else if ch == open {
depth += 1
}
}
Err(ParsingError::new(original_input, ()))
}
}