#[cfg(test)]
mod tests;
use itertools::Itertools;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use unicode_segmentation::UnicodeSegmentation as Uni;
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Located<A> {
pub value: A,
pub from: Location,
pub to: Location,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Location {
pub row: usize,
pub col: usize,
}
impl Ord for Location {
fn cmp(&self, other: &Self) -> Ordering {
self.row
.cmp(&other.row)
.then_with(|| self.col.cmp(&other.col))
}
}
impl PartialOrd for Location {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseResult<'a, Output, State> {
Ok {
input: &'a str,
location: Location,
output: Output,
state: State,
committed: bool,
},
Err {
message: String,
from: Location,
to: Location,
state: State,
committed: bool,
},
}
pub struct ParseOk<'a, Output, State> {
input: &'a str,
output: Output,
location: Location,
state: State,
committed: bool,
}
pub struct ParseErr<State> {
message: String,
from: Location,
to: Location,
state: State,
committed: bool,
}
pub type StdParseResult<'a, A, S> = Result<ParseOk<'a, A, S>, ParseErr<S>>;
impl<'a, A, S> From<ParseResult<'a, A, S>> for StdParseResult<'a, A, S> {
fn from(val: ParseResult<'a, A, S>) -> Self {
match val {
ParseResult::Ok {
input,
location,
output,
state,
committed,
} => Ok(ParseOk {
input,
location,
output,
state,
committed,
}),
ParseResult::Err {
message,
from,
to,
state,
committed,
} => Err(ParseErr {
message,
from,
to,
state,
committed,
}),
}
}
}
impl<'a, A, S> From<StdParseResult<'a, A, S>> for ParseResult<'a, A, S> {
fn from(result: StdParseResult<'a, A, S>) -> ParseResult<'a, A, S> {
match result {
Ok(ParseOk {
input,
location,
output,
state,
committed,
}) => ParseResult::Ok {
input,
location,
output,
state,
committed,
},
Err(ParseErr {
message,
from,
to,
state,
committed,
}) => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
}
impl<'a, T, S: Clone + 'a> ParseResult<'a, T, S> {
pub fn map<U, F: FnOnce(T) -> U>(self, func: F) -> ParseResult<'a, U, S> {
match self {
ParseResult::Ok {
input,
location,
output,
state,
committed,
} => ParseResult::Ok {
input,
location,
output: func(output),
state,
committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
pub fn map_with_state<U, F: FnOnce(T, S) -> U>(self, func: F) -> ParseResult<'a, U, S> {
match self {
ParseResult::Ok {
input,
location,
output,
state,
committed,
} => ParseResult::Ok {
input,
location,
output: func(output, state.clone()),
state,
committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
pub fn map_err<F: FnOnce(String) -> String>(self, func: F) -> ParseResult<'a, T, S> {
match self {
ParseResult::Ok {
input,
location,
output,
state,
committed,
} => ParseResult::Ok {
input,
location,
output,
state,
committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message: func(message),
from,
to,
state,
committed,
},
}
}
pub fn and_then<U, F: FnOnce(&'a str, T, Location, S) -> ParseResult<'a, U, S>>(
self,
func: F,
) -> ParseResult<'a, U, S> {
match self {
ParseResult::Ok {
input,
output,
location,
state,
committed,
} => match func(input, output, location, state) {
ParseResult::Ok {
input,
output,
location,
state,
committed: cur_committed,
} => ParseResult::Ok {
input,
output,
location,
state,
committed: committed || cur_committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed: cur_committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed: committed || cur_committed,
},
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
pub fn backtrackable(self) -> ParseResult<'a, T, S> {
match self {
ParseResult::Ok {
input,
location,
output,
state,
..
} => ParseResult::Ok {
input,
location,
output,
state,
committed: false,
},
ParseResult::Err {
message,
from,
to,
state,
..
} => ParseResult::Err {
message,
from,
to,
state,
committed: false,
},
}
}
fn unwrap(self, source: &'a str) -> T {
match self {
ParseResult::Ok { output, .. } => output,
ParseResult::Err {
message, from, to, ..
} => {
println!("{}", display_error(source, message, from, to));
panic!();
}
}
}
fn unwrap_err(self) -> String
where
T: Debug + 'a,
{
match self {
ParseResult::Ok { output, .. } => panic!("{:#?}", output),
ParseResult::Err { message, .. } => message,
}
}
}
#[derive(Clone)]
pub struct Map<P, F>(P, F);
impl<'a, A: 'a, B: 'a, P: 'a, F: Clone> Parser<'a> for Map<P, F>
where
P: Parser<'a, Output = A>,
F: FnOnce(A) -> B,
{
type Output = B;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, B, Self::State> {
self.0.parse(input, location, state).map(self.1.clone())
}
}
#[derive(Clone)]
pub struct MapWithState<P, F>(P, F);
impl<'a, A, B, P, F: Clone> Parser<'a> for MapWithState<P, F>
where
P: Parser<'a, Output = A>,
F: FnOnce(A, P::State) -> B,
{
type Output = B;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, B, Self::State> {
match self.0.parse(input, location, state) {
ParseResult::Ok {
input,
output,
location,
state,
committed,
} => ParseResult::Ok {
input,
output: self.1.clone()(output, state.clone()),
location,
state,
committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
}
#[derive(Clone)]
pub struct MapErr<P, F>(P, F);
impl<'a, P: 'a, F: Clone> Parser<'a> for MapErr<P, F>
where
P: Parser<'a>,
F: FnOnce(String) -> String,
{
type Output = P::Output;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
self.0.parse(input, location, state).map_err(self.1.clone())
}
}
#[derive(Clone)]
pub struct AndThen<P1, F>(P1, F);
impl<'a, P1, P2, F: Clone, S: Clone + 'a> Parser<'a> for AndThen<P1, F>
where
P1: Parser<'a, State = S>,
P2: Parser<'a, State = S>,
F: FnOnce(P1::Output) -> P2,
{
type Output = P2::Output;
type State = S;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
self.0.parse(input, location, state).and_then(
|cur_input, cur_output, cur_location, cur_state| {
self.1.clone()(cur_output).parse(cur_input, cur_location, cur_state)
},
)
}
}
#[derive(Clone)]
pub struct Pred<'a, P: 'a, F>(P, F, &'a str);
impl<'a, P: 'a, F: 'a, Output: std::fmt::Display> Parser<'a> for Pred<'a, P, F>
where
P: Parser<'a, Output = Output>,
F: Fn(&P::Output) -> bool,
{
type Output = P::Output;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self.0.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
output: content,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
if self.1(&content) {
ParseResult::Ok {
input: cur_input,
output: content,
location: cur_location,
state: cur_state,
committed: true,
}
} else {
ParseResult::Err {
message: format!(
"I'm expecting {} but found {}.",
self.2,
display_token(content)
),
from: location,
to: cur_location,
state: cur_state,
committed: cur_committed,
}
}
}
ParseResult::Err {
message,
from,
to,
state,
..
} => ParseResult::Err {
message,
from,
to,
state,
committed: false,
},
}
}
}
#[derive(Clone)]
pub struct End<P>(P);
impl<'a, P> Parser<'a> for End<P>
where
P: Parser<'a>,
{
type Output = P::Output;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self.0.parse(input, location, state) {
ParseResult::Ok {
input,
location,
state,
output,
..
} => {
if !input.is_empty() {
ParseResult::Err {
message: "I'm expecting the end of input.".to_string(),
from: location,
to: location,
state,
committed: false,
}
} else {
ParseResult::Ok {
input,
output,
location,
state,
committed: false,
}
}
}
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
}
#[derive(Clone)]
pub struct UpdateState<P, F>(P, F);
impl<'a, P: 'a, F> Parser<'a> for UpdateState<P, F>
where
P: Parser<'a>,
F: Fn(&P::Output, P::State) -> P::State,
{
type Output = P::Output;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self.0.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
location: cur_location,
state: cur_state,
output,
committed,
} => {
let new_state = self.1(&output, cur_state);
ParseResult::Ok {
input: cur_input,
output,
location: cur_location,
state: new_state,
committed,
}
}
err @ ParseResult::Err { .. } => err,
}
}
}
#[derive(Clone)]
pub struct Update<P, F>(P, F);
impl<'a, P: 'a, A, B, F: Clone> Parser<'a> for Update<P, F>
where
P: Parser<'a, Output = A>,
F: FnOnce(&'a str, A, Location, P::State) -> ParseResult<'a, B, P::State>,
{
type Output = B;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self.0.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
location: cur_location,
state: cur_state,
output,
..
} => self.1.clone()(cur_input, output, cur_location, cur_state),
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
}
pub struct Ignore<P>(P);
impl<'a, P> Parser<'a> for Ignore<P>
where
P: Parser<'a>,
{
type Output = ();
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self.0.parse(input, location, state) {
ParseResult::Ok {
input,
location,
state,
committed,
..
} => ParseResult::Ok {
input,
location,
output: (),
state,
committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
}
}
}
pub struct Keep<P1, P2>(P1, P2);
impl<'a, P1, P2, A, B, F, S: Clone + 'a> Parser<'a> for Keep<P1, P2>
where
F: FnOnce(A) -> B,
P1: Parser<'a, Output = F, State = S>,
P2: Parser<'a, Output = A, State = S>,
{
type Output = B;
type State = P1::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
self.0
.parse(input, location, state)
.and_then(|cur_input, func, cur_location, cur_state| {
self.1.parse(cur_input, cur_location, cur_state).map(func)
})
}
}
pub struct Skip<P1, P2>(P1, P2);
impl<'a, P1, P2, S: Clone + 'a> Parser<'a> for Skip<P1, P2>
where
P1: Parser<'a, State = S>,
P2: Parser<'a, State = S>,
{
type Output = P1::Output;
type State = P1::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
self.0.parse(input, location, state).and_then(
|cur_input, left_output, cur_location, cur_state| {
self.1
.parse(cur_input, cur_location, cur_state)
.map(|_| left_output)
},
)
}
}
#[derive(Clone)]
pub struct Backtrackable<P>(P);
impl<'a, P: 'a> Parser<'a> for Backtrackable<P>
where
P: Parser<'a>,
{
type Output = P::Output;
type State = P::State;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
self.0.parse(input, location, state).backtrackable()
}
}
pub trait Parser<'a> {
type Output;
type State: Clone;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State>;
fn run(
&mut self,
input: &'a str,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
self.parse(input, Location { row: 1, col: 1 }, state)
}
fn map<F: 'a, NewOutput: 'a>(self, map_fn: F) -> Map<Self, F>
where
Self: Sized + 'a,
F: Fn(Self::Output) -> NewOutput,
{
map(self, map_fn)
}
fn map_with_state<F: 'a, NewOutput: 'a>(self, map_fn: F) -> MapWithState<Self, F>
where
Self: Sized + 'a,
F: Fn(Self::Output, Self::State) -> NewOutput,
{
map_with_state(self, map_fn)
}
fn map_err<F>(self, map_fn: F) -> MapErr<Self, F>
where
Self: Sized + 'a,
F: Fn(String) -> String,
{
map_err(self, map_fn)
}
fn and_then<F, P2, B>(self, f: F) -> AndThen<Self, F>
where
Self: Sized + 'a,
P2: Parser<'a, Output = B>,
F: Fn(Self::Output) -> P2,
{
and_then(self, f)
}
fn pred<F>(self, predicate: F, expecting: &'a str) -> Pred<Self, F>
where
Self: Sized + 'a,
F: Fn(&Self::Output) -> bool,
{
pred(self, predicate, expecting)
}
fn ignore(self) -> Ignore<Self>
where
Self: Sized + 'a,
{
Ignore(self)
}
fn update_state<F>(self, f: F) -> UpdateState<Self, F>
where
Self: Sized + 'a,
F: Fn(Self::Output, Self::State) -> Self::State,
{
update_state(self, f)
}
fn update<B, F: Clone>(self, f: F) -> Update<Self, F>
where
Self: Sized + 'a,
F: FnOnce(&'a str, Self::Output, Location, Self::State) -> ParseResult<'a, B, Self::State>,
{
update(self, f)
}
fn end(self) -> End<Self>
where
Self: Sized + 'a,
{
end(self)
}
fn keep<A, B, P2>(self, arg_parser: P2) -> Keep<Self, P2>
where
Self: Sized + 'a,
Self::Output: FnOnce(A) -> B + Clone,
P2: Parser<'a, Output = A>,
{
keep(self, arg_parser)
}
fn skip<P2>(self, ignored_parser: P2) -> Skip<Self, P2>
where
Self: Sized + 'a,
P2: Parser<'a>,
{
Skip(self, ignored_parser)
}
fn backtrackable(self) -> Backtrackable<Self>
where
Self: Sized + 'a,
{
backtrackable(self)
}
fn first_of_two<T2>(self) -> OneOfTwo<Self, T2>
where
Self: Sized + 'a,
T2: Parser<'a, Output = Self::Output, State = Self::State>,
{
OneOfTwo::First(self)
}
fn second_of_two<T1>(self) -> OneOfTwo<T1, Self>
where
Self: Sized + 'a,
T1: Parser<'a, Output = Self::Output, State = Self::State>,
{
OneOfTwo::Second(self)
}
fn first_of_three<T2, T3>(self) -> OneOfThree<Self, T2, T3>
where
Self: Sized + 'a,
T2: Parser<'a, Output = Self::Output, State = Self::State>,
T3: Parser<'a, Output = Self::Output, State = Self::State>,
{
OneOfThree::First(self)
}
fn second_of_three<T1, T3>(self) -> OneOfThree<T1, Self, T3>
where
Self: Sized + 'a,
T1: Parser<'a, Output = Self::Output, State = Self::State>,
T3: Parser<'a, Output = Self::Output, State = Self::State>,
{
OneOfThree::Second(self)
}
fn third_of_three<T1, T2>(self) -> OneOfThree<T1, T2, Self>
where
Self: Sized + 'a,
T1: Parser<'a, Output = Self::Output, State = Self::State>,
T2: Parser<'a, Output = Self::Output, State = Self::State>,
{
OneOfThree::Third(self)
}
}
fn and_then<'a, P1, P2, F>(parser: P1, f: F) -> AndThen<P1, F>
where
P1: Parser<'a>,
P2: Parser<'a>,
F: Fn(P1::Output) -> P2,
{
AndThen(parser, f)
}
pub fn token<'a, S: Clone + 'a>(expected: &'a str) -> impl Parser<Output = &'a str, State = S> {
fn_parser(move |input: &'a str, location: Location, state: S| {
let peek = input.get(0..expected.len());
if peek == Some(expected) {
ParseResult::Ok {
input: &input[expected.len()..],
output: expected,
location: increment_col(unicode_column_width(expected), location),
state,
committed: true,
}
} else {
let expected_len = expected.graphemes(true).count();
let peek_str = &input.graphemes(true).take(expected_len).join("");
ParseResult::Err {
message: format!(
"I'm expecting a `{}` but found {}.",
expected,
display_token(peek_str)
),
from: location,
to: Location {
col: location.col + unicode_column_width(peek_str),
..location
},
state,
committed: false,
}
}
})
}
fn increment_col(additional_col: usize, location: Location) -> Location {
Location {
col: location.col + additional_col,
..location
}
}
fn increment_row(additional_row: usize, location: Location) -> Location {
Location {
row: location.row + additional_row,
col: 1,
}
}
fn display_token<T: Display>(token: T) -> String {
let token_str = &token.to_string();
if unicode_column_width(token_str) == 0 {
"nothing".to_string()
} else {
format!("`{}`", token_str.replace('\n', "\\n"))
}
}
fn pair<'a, P1: 'a, P2: 'a, R1: Clone + 'a, R2: Clone + 'a, S: Clone + 'a>(
mut parser1: P1,
mut parser2: P2,
) -> impl Parser<'a, Output = (R1, R2), State = S>
where
P1: Parser<'a, Output = R1, State = S>,
P2: Parser<'a, Output = R2, State = S>,
{
fn_parser(move |input, location, state| {
parser1.parse(input, location, state).and_then(
|cur_input, first_output, cur_location, cur_state| {
parser2
.parse(cur_input, cur_location, cur_state)
.map(|second_output| (first_output.clone(), second_output))
},
)
})
}
fn map<'a, P: 'a, F: 'a, B>(parser: P, map_fn: F) -> Map<P, F>
where
P: Parser<'a>,
F: Fn(P::Output) -> B,
{
Map(parser, map_fn)
}
fn map_with_state<'a, P: 'a, F: 'a, A, B>(parser: P, map_fn: F) -> MapWithState<P, F>
where
P: Parser<'a, Output = A>,
F: Fn(P::Output, P::State) -> B,
{
MapWithState(parser, map_fn)
}
fn map_err<'a, P: 'a, F>(parser: P, map_fn: F) -> MapErr<P, F>
where
P: Parser<'a>,
F: Fn(String) -> String,
{
MapErr(parser, map_fn)
}
fn backtrackable<'a, P>(parser: P) -> Backtrackable<P>
where
P: Parser<'a>,
{
Backtrackable(parser)
}
fn left<'a, P1: 'a, P2: 'a, R1: Clone + 'a, R2: Clone + 'a, S: Clone + 'a>(
parser1: P1,
parser2: P2,
) -> impl Parser<'a, Output = R1, State = S>
where
P1: Parser<'a, Output = R1, State = S>,
P2: Parser<'a, Output = R2, State = S>,
{
map(pair(parser1, parser2), |(left, _right)| left)
}
fn keep<'a, P1, P2, F, A, B>(parser1: P1, parser2: P2) -> Keep<P1, P2>
where
F: FnOnce(A) -> B,
P1: Parser<'a, Output = F>,
P2: Parser<'a, Output = A>,
{
Keep(parser1, parser2)
}
pub type BoxedParser<'a, A, S> = Box<dyn FnMut(&'a str, Location, S) -> ParseResult<'a, A, S> + 'a>;
impl<'a, A, S: Clone + 'a> Parser<'a> for BoxedParser<'a, A, S> {
type Output = A;
type State = S;
fn parse(&mut self, input: &'a str, location: Location, state: S) -> ParseResult<'a, A, S> {
(*self)(input, location, state)
}
}
#[derive(Copy, Clone)]
pub struct FnParser<F, A, S>(F, PhantomData<A>, PhantomData<S>);
pub fn fn_parser<'a, A, S: Clone, F>(f: F) -> FnParser<F, A, S>
where
F: FnMut(&'a str, Location, S) -> ParseResult<'a, A, S>,
{
FnParser(f, PhantomData, PhantomData)
}
impl<'a, A, S: Clone, F> Parser<'a> for FnParser<F, A, S>
where
F: FnMut(&'a str, Location, S) -> ParseResult<'a, A, S>,
{
type Output = A;
type State = S;
fn parse(&mut self, input: &'a str, location: Location, state: S) -> ParseResult<'a, A, S> {
(self.0)(input, location, state)
}
}
#[doc(hidden)]
pub fn succeed_helper<'a, A: Clone + 'a, S: Clone + 'a>(
output: A,
) -> impl Parser<'a, Output = A, State = S> {
fn_parser(move |input, location, state: S| ParseResult::Ok {
input,
location,
state,
output: output.clone(),
committed: false,
})
}
#[macro_export]
macro_rules! succeed {
(|$first_arg:ident $(, $arg:ident )*| $function_body:expr) => {
succeed_helper(move |$first_arg| $(move |$arg|)* {
$function_body
})
};
(|$first_arg:ident:$first_arg_type:ty $(, $arg:ident:$arg_type:ty )*| $function_body:expr) => {
succeed_helper(move |$first_arg:$first_arg_type| $(move |$arg:$arg_type|)* {
$function_body
})
};
($value:expr) => {
succeed_helper($value)
};
() => {
succeed_helper(())
}
}
fn end<'a, P>(parser: P) -> End<P>
where
P: Parser<'a>,
{
End(parser)
}
pub fn problem<'a, F1: 'a, F2: 'a, A: 'a, S: Clone + 'a>(
message: String,
from: F1,
to: F2,
) -> impl Parser<'a, Output = A, State = S>
where
F1: Fn(Location) -> Location,
F2: Fn(Location) -> Location,
{
fn_parser(move |_input, location, state: S| ParseResult::Err {
message: message.clone(),
from: from(location),
to: to(location),
state,
committed: false,
})
}
fn right<'a, P1: 'a, P2: 'a, R1: Clone + 'a, R2: Clone + 'a, S: Clone + 'a>(
parser1: P1,
parser2: P2,
) -> impl Parser<'a, Output = R2, State = S>
where
P1: Parser<'a, Output = R1, State = S>,
P2: Parser<'a, Output = R2, State = S>,
{
map(pair(parser1, parser2), |(_left, right)| right)
}
pub fn one_or_more<'a, P: 'a, A: Clone + 'a, S: Clone + 'a>(
mut parser: P,
) -> BoxedParser<'a, Vec<A>, S>
where
P: Parser<'a, Output = A, State = S>,
{
Box::new(move |mut input, mut location, mut state| {
let mut output = Vec::new();
let mut committed = false;
match parser.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
output: first_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(first_item);
}
ParseResult::Err {
message,
from,
to,
state,
committed,
} => {
return ParseResult::Err {
message,
from,
to,
state,
committed,
};
}
}
loop {
match parser.parse(input, location, state.clone()) {
ParseResult::Ok {
input: cur_input,
output: cur_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
..
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(cur_item);
}
ParseResult::Err {
message,
from,
to,
state,
committed,
} => {
if committed {
return ParseResult::Err {
message,
from,
to,
state,
committed,
};
} else {
break;
}
}
}
}
ParseResult::Ok {
input,
output,
location,
state,
committed,
}
})
}
pub fn zero_or_more_until<'a, P: 'a, A: Clone + 'a, E: 'a, B: 'a, S: Clone + 'a>(
item_name: &'static str,
mut parser: P,
end_name: &'static str,
mut end_parser: E,
) -> BoxedParser<'a, Vec<A>, S>
where
P: Parser<'a, Output = A, State = S>,
E: Parser<'a, Output = B, State = ()>,
{
Box::new(move |mut input, mut location, mut state| {
let mut output = Vec::new();
let mut committed = false;
match end_parser.parse(input, location, ()) {
ParseResult::Ok {
committed: cur_committed,
..
} => {
committed |= cur_committed;
return ParseResult::Ok {
input,
output,
location,
state,
committed,
};
}
ParseResult::Err {
message,
from,
to,
committed,
..
} => {
if committed {
return ParseResult::Err {
message,
from,
to,
state,
committed,
};
}
} }
match parser.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
output: first_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(first_item);
}
ParseResult::Err {
message,
from,
to,
state,
committed: cur_committed,
} => {
committed |= cur_committed;
if input.is_empty() {
return ParseResult::Ok {
input,
output,
location,
state,
committed,
};
} else {
return ParseResult::Err {
message,
from,
to,
state,
committed,
};
}
}
}
loop {
match end_parser.parse(input, location, ()) {
ParseResult::Ok {
committed: cur_committed,
..
} => {
committed |= cur_committed;
return ParseResult::Ok {
input,
output,
location,
state,
committed,
};
}
ParseResult::Err {
message,
from,
to,
committed: err_committed,
..
} => {
if err_committed {
return ParseResult::Err {
message,
from,
to,
state,
committed: err_committed,
};
}
match parser.parse(input, location, state.clone()) {
ParseResult::Ok {
input: cur_input,
output: cur_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(cur_item);
}
ParseResult::Err {
from: end_from,
to: end_to,
committed: cur_committed,
..
} => {
committed |= cur_committed;
if input.is_empty() {
return ParseResult::Ok {
input,
output,
location,
state,
committed,
};
} else {
return ParseResult::Err {
message: format!("I'm expecting either {} or {}. However, neither was found.", item_name, end_name),
from: end_from,
to: end_to,
state,
committed,
};
}
}
}
}
}
}
})
}
pub fn one_or_more_until<'a, P: 'a, A: Clone + 'a, E: 'a, B: 'a, S: Clone + 'a>(
item_name: &'static str,
mut parser: P,
end_name: &'static str,
mut end_parser: E,
) -> BoxedParser<'a, Vec<A>, S>
where
P: Parser<'a, Output = A, State = S>,
E: Parser<'a, Output = B, State = ()>,
{
Box::new(move |mut input, mut location, mut state| {
let mut output = Vec::new();
let mut committed = false;
match end_parser.parse(input, location, ()) {
ParseResult::Ok {
location: end_location,
committed: cur_committed,
..
} => {
committed |= cur_committed;
return ParseResult::Err {
message: format!(
"I'm expecting at least one occurrence of {} but reached {}.",
item_name, end_name
),
from: location,
to: end_location,
state,
committed,
};
}
ParseResult::Err {
message,
from,
to,
committed: err_committed,
..
} => {
if err_committed {
return ParseResult::Err {
message,
from,
to,
state,
committed: err_committed,
};
}
match parser.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
output: first_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(first_item);
}
ParseResult::Err {
message,
from,
to,
state,
committed: cur_committed,
} => {
committed |= cur_committed;
return ParseResult::Err {
message,
from,
to,
state,
committed,
};
}
}
}
}
loop {
match end_parser.parse(input, location, ()) {
ParseResult::Ok { .. } => {
return ParseResult::Ok {
input,
output,
location,
state,
committed,
};
}
ParseResult::Err {
message,
from,
to,
committed: err_committed,
..
} => {
if err_committed {
return ParseResult::Err {
message,
from,
to,
state,
committed: err_committed,
};
}
match parser.parse(input, location, state.clone()) {
ParseResult::Ok {
input: cur_input,
output: cur_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(cur_item);
}
ParseResult::Err {
from: end_from,
to: end_to,
committed: cur_committed,
..
} => {
committed |= cur_committed;
if input.is_empty() {
return ParseResult::Ok {
input,
output,
location,
state,
committed,
};
} else {
return ParseResult::Err {
message: format!("I'm expecting either {} or {}. However, neither was found.", item_name, end_name),
from: end_from,
to: end_to,
state,
committed,
};
}
}
}
}
}
}
})
}
pub fn zero_or_more<'a, P: 'a, A: Clone + 'a, S: Clone + 'a>(
mut parser: P,
) -> BoxedParser<'a, Vec<A>, S>
where
P: Parser<'a, Output = A, State = S>,
{
Box::new(move |mut input, mut location, mut state: S| {
let mut output = Vec::new();
let mut committed = false;
loop {
match parser.parse(input, location, state.clone()) {
ParseResult::Ok {
input: cur_input,
output: cur_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => {
input = cur_input;
location = cur_location;
state = cur_state;
committed |= cur_committed;
output.push(cur_item);
}
ParseResult::Err {
message,
from,
to,
state,
committed,
} => {
if committed {
return ParseResult::Err {
message,
from,
to,
state,
committed,
};
} else {
break;
}
}
}
}
ParseResult::Ok {
input,
output,
location,
state,
committed,
}
})
}
fn any_grapheme<'a, S: Clone + 'a>(
expecting: &'a str,
) -> impl Parser<'a, Output = &'a str, State = S> {
fn_parser(move |input: &'a str, location: Location, state| {
match Uni::graphemes(input, true).next() {
Some(c) => match c {
"\n" | "\r\n" => ParseResult::Ok {
input: &input[c.len()..],
output: c,
location: increment_row(1, location),
state,
committed: false,
},
_ => ParseResult::Ok {
input: &input[c.len()..],
output: c,
location: increment_col(grapheme_column_width(c), location),
state,
committed: false,
},
},
_ => ParseResult::Err {
message: format!("I'm expecting {} but reached the end of input.", expecting),
from: location,
to: location,
state,
committed: false,
},
}
})
}
fn any_char<'a, S: Clone + 'a>(expecting: &str) -> impl Parser<'_, Output = char, State = S> {
fn_parser(
move |input: &str, location: Location, state| match input.chars().next() {
Some(c) => match c {
'\n' => ParseResult::Ok {
input: &input[c.len_utf8()..],
output: c,
location: increment_row(1, location),
state,
committed: false,
},
_ => ParseResult::Ok {
input: &input[c.len_utf8()..],
output: c,
location: increment_col(char_column_width(c), location),
state,
committed: false,
},
},
_ => ParseResult::Err {
message: format!("I'm expecting {} but reached the end of input.", expecting),
from: location,
to: location,
state,
committed: false,
},
},
)
}
pub fn chomp_if<'a, F: 'a, S: Clone + 'a>(
predicate: F,
expecting: &'a str,
) -> impl Parser<'_, Output = (), State = S>
where
F: Fn(&'a str) -> bool,
{
any_grapheme(expecting)
.pred(move |output| predicate(output), expecting)
.ignore()
}
pub fn chomp_ifc<'a, F: 'a, S: Clone + 'a>(
predicate: F,
expecting: &'a str,
) -> impl Parser<'_, Output = (), State = S>
where
F: Fn(char) -> bool,
{
any_char(expecting)
.pred(move |output| predicate(*output), expecting)
.ignore()
}
pub fn chomp_while0<'a, F: 'a, S: Clone + 'a>(
predicate: F,
expecting: &'a str,
) -> impl Parser<'_, Output = (), State = S>
where
F: Fn(&'a str) -> bool,
{
zero_or_more(chomp_if(predicate, expecting)).ignore()
}
pub fn chomp_while0c<'a, F: 'a, S: Clone + 'a>(
predicate: F,
expecting: &'a str,
) -> impl Parser<'_, Output = (), State = S>
where
F: Fn(char) -> bool,
{
zero_or_more(chomp_ifc(predicate, expecting)).ignore()
}
pub fn chomp_while1<'a, F: 'a, S: Clone + 'a>(
predicate: F,
expecting: &'a str,
) -> impl Parser<'_, Output = (), State = S>
where
F: Fn(&str) -> bool,
{
one_or_more(chomp_if(predicate, expecting)).ignore()
}
pub fn chomp_while1c<'a, F: 'a, S: Clone + 'a>(
predicate: F,
expecting: &'a str,
) -> impl Parser<'_, Output = (), State = S>
where
F: Fn(char) -> bool,
{
one_or_more(chomp_ifc(predicate, expecting)).ignore()
}
pub fn take_chomped<'a, P: 'a, S: Clone + 'a>(
mut parser: P,
) -> impl Parser<'a, Output = String, State = S>
where
P: Parser<'a, State = S>,
{
fn_parser(
move |input, location, state| match parser.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
location: cur_location,
state: cur_state,
committed: cur_committed,
..
} => ParseResult::Ok {
input: cur_input,
output: get_difference(input, cur_input).to_string(),
location: cur_location,
state: cur_state,
committed: cur_committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
},
)
}
fn get_difference<'a>(whole_str: &'a str, substr: &'a str) -> &'a str {
&whole_str[..whole_str.len() - substr.len()]
}
fn pred<'a, P: 'a, F>(parser: P, predicate: F, expecting: &'a str) -> Pred<'a, P, F>
where
P: Parser<'a>,
F: Fn(&P::Output) -> bool,
{
Pred(parser, predicate, expecting)
}
fn space_char<'a, S: Clone + 'a>() -> impl Parser<'a, Output = (), State = S> {
chomp_if(&(|c: &str| c == " "), "a whitespace")
}
fn newline_char<'a, S: Clone + 'a>() -> impl Parser<'a, Output = (), State = S> {
fn_parser(move |input, location, state: S| {
let mut cur_input: &str = input;
let mut cur_location: Location = location;
let mut cur_state: S = state.clone();
let result1 =
chomp_ifc(&(|c: char| c == '\r'), "a carriage return").parse(input, location, state);
if let ParseResult::Ok {
input,
location,
state,
..
} = result1
{
cur_input = input;
cur_location = location;
cur_state = state;
}
let result = chomp_ifc(&(|c: char| c == '\n'), "a newline").parse(
cur_input,
cur_location,
cur_state,
);
match result {
ParseResult::Ok {
input,
output,
location,
state,
committed,
} => ParseResult::Ok {
input,
output,
state,
committed,
location: increment_row(1, location),
},
err @ ParseResult::Err { .. } => err,
}
})
}
pub fn newline0<'a, P: 'a, S: Clone + 'a>(
indent_parser: P,
) -> impl Parser<'a, Output = (), State = S>
where
P: Parser<'a, Output = (), State = S>,
{
zero_or_more(pair(indent_parser, newline_char())).ignore()
}
pub fn newline1<'a, P>(indent_parser: P) -> impl Parser<'a, Output = ()>
where
P: Parser<'a, Output = ()> + 'a,
{
pair(newline_char(), newline0(indent_parser)).ignore()
}
pub fn space0<'a, S: Clone + 'a>() -> impl Parser<'a, Output = (), State = S> {
zero_or_more(space_char()).ignore()
}
pub fn space1<'a, S: Clone + 'a>() -> impl Parser<'a, Output = (), State = S> {
one_or_more(space_char()).ignore()
}
pub fn indent<'a, S: Clone + 'a>(
number_of_spaces: usize,
) -> impl Parser<'a, Output = (), State = S> {
repeat(number_of_spaces, space_char())
.ignore()
.map_err(move |_| {
format!(
"I'm expecting an indentation.\nAll indentations should be {} spaces.",
number_of_spaces
)
})
}
pub fn indents<'a, S: Clone + 'a>(
number_of_spaces: usize,
number_of_indents: usize,
) -> impl Parser<'a, Output = (), State = S> {
repeat(number_of_indents, indent(number_of_spaces))
.map_err(move |_| {
format!(
"I'm expecting {} indentation{}.\nAll indentations should be {} spaces.",
number_of_indents,
plural_suffix(number_of_indents),
number_of_spaces,
)
})
.ignore()
}
fn plural_suffix(count: usize) -> &'static str {
if count > 1 {
"s"
} else {
""
}
}
pub fn repeat<'a, A: Clone + 'a, P: 'a, S: Clone + 'a>(
times: usize,
mut parser: P,
) -> BoxedParser<'a, Vec<A>, S>
where
P: Parser<'a, Output = A, State = S>,
{
Box::new(move |mut input, mut location, mut state: S| {
let mut output = Vec::new();
let mut committed = false;
if times == 0 {
return ParseResult::Ok {
input,
location,
output,
state,
committed,
};
}
let mut counter = 0;
while let ParseResult::Ok {
input: cur_input,
output: cur_item,
location: cur_location,
state: cur_state,
committed: cur_committed,
} = parser.parse(input, location, state.clone())
{
if counter >= times {
break;
}
input = cur_input;
location = cur_location;
state = cur_state;
output.push(cur_item);
counter += 1;
committed |= cur_committed;
}
ParseResult::Ok {
input,
output,
location,
state,
committed,
}
})
}
#[macro_export]
macro_rules! one_of {
($single_parser:expr) => { $single_parser };
($first_parser:expr, $($parsers:expr),+) => {
either($first_parser, one_of!($($parsers),*))
};
}
#[doc(hidden)]
pub fn either<'a, P1, P2, A: Clone + 'a, S: Clone + 'a>(
mut parser1: P1,
mut parser2: P2,
) -> impl Parser<'a, Output = A, State = S>
where
P1: Parser<'a, Output = A, State = S> + 'a,
P2: Parser<'a, Output = A, State = S> + 'a,
{
fn_parser(move |input, location, state| {
let result = match parser1.parse(input, location, state) {
ok @ ParseResult::Ok { .. } => ok,
ParseResult::Err {
message,
from,
to,
state,
committed,
} => {
if committed {
ParseResult::Err {
message,
from,
to,
state,
committed,
}
} else {
parser2.parse(input, location, state)
}
}
};
result
})
}
pub fn optional_with_default<'a, A: Clone + 'a, P: 'a, S: Clone + 'a>(
default: A,
mut parser: P,
) -> impl Parser<'a, Output = A, State = S>
where
P: Parser<'a, Output = A, State = S>,
{
fn_parser(move |input, location, state| {
let result = match parser.parse(input, location, state) {
ok @ ParseResult::Ok { .. } => ok,
ParseResult::Err {
message,
from,
to,
state,
committed,
} => {
if committed {
ParseResult::Err {
message,
from,
to,
state,
committed,
}
} else {
ParseResult::Ok {
input,
location,
output: default.clone(),
state,
committed: false,
}
}
}
};
result
})
}
pub fn optional<'a, A: Clone + 'a, P: 'a, S: Clone + 'a>(
mut parser: P,
) -> impl Parser<'a, Output = Option<A>, State = S>
where
P: Parser<'a, Output = A, State = S>,
{
fn_parser(
move |input, location, state| match parser.parse(input, location, state) {
ok @ ParseResult::Ok { .. } => ok.map(Some),
ParseResult::Err {
message,
from,
to,
state,
committed,
} => {
if committed {
ParseResult::Err {
message,
from,
to,
state,
committed,
}
} else {
ParseResult::Ok {
input,
location,
output: None,
state,
committed: false,
}
}
}
},
)
}
pub fn newline_with_comment<'a, S: Clone + 'a>(
comment_symbol: &'a str,
) -> impl Parser<'_, Output = (), State = S> {
succeed!()
.skip(space0())
.skip(either(newline_char(), line_comment(comment_symbol)))
}
pub fn line_comment<'a, S: Clone + 'a>(
comment_symbol: &'a str,
) -> impl Parser<'_, Output = (), State = S> {
succeed!()
.skip(token(comment_symbol))
.skip(zero_or_more(chomp_ifc(
&(|c: char| c != '\n' && c != '\r'),
"any character",
)))
.skip(newline_char())
}
pub fn int<'a, S: Clone + 'a>() -> impl Parser<'a, Output = usize, State = S> {
digits("an integer", false).map(|int_str| int_str.parse().unwrap())
}
pub fn float<'a, S: Clone + 'a>() -> impl Parser<'a, Output = f64, State = S> {
let expecting = "a floating point number";
succeed!(
|whole: String, fraction: Option<String>, exponent: Option<String>| (whole
+ &fraction.unwrap_or_default()
+ &exponent.unwrap_or_default())
.parse()
.unwrap()
)
.keep(digits(expecting, false))
.keep(optional(
right(token("."), digits(expecting, true)).map(|digits| ".".to_owned() + &digits),
))
.keep(optional(
succeed!(|sign: Option<&'a str>, exponent: String| "e".to_string()
+ sign.unwrap_or_default()
+ &exponent)
.skip(either(token("e"), token("E")))
.keep(optional(either(token("+"), token("-"))))
.keep(digits(expecting, false)),
))
}
fn digits<'a, S: Clone + 'a>(
name: &'a str,
allow_leading_zeroes: bool,
) -> impl Parser<'_, Output = String, State = S> {
take_chomped(chomp_while1c(&(|c: char| c.is_ascii_digit()), name)).update(
move |input, digits: String, location: Location, state: S| {
if !allow_leading_zeroes && digits.starts_with('0') && digits.len() > 1 {
ParseResult::Err {
message: format!("You can't have leading zeroes in {}.", name),
from: Location {
col: location.col - digits.len(),
..location
},
to: location,
state,
committed: false,
}
} else {
ParseResult::Ok {
input,
output: digits,
location,
state,
committed: true,
}
}
},
)
}
pub fn variable<'a, S: Clone + 'a, F1: Clone, F2: Clone, F3: Clone>(
start: &'a F1,
inner: &'a F2,
separator: &'a F3,
reserved: &'a HashSet<String>,
expecting: &'a str,
) -> impl Parser<'a, Output = String, State = S>
where
F1: Fn(char) -> bool,
F2: Fn(char) -> bool,
F3: Fn(char) -> bool,
{
take_chomped(pair(
chomp_ifc(start, expecting),
chomp_while0c(move |c: char| inner(c) || separator(c), expecting),
))
.update(move |input, name, location, state| {
if reserved.contains(&name) {
ParseResult::Err {
message: format!(
"I'm expecting {} but found a reserved word `{}`.",
expecting, name
),
from: Location {
col: location.col - name.len(),
..location
},
to: location,
state,
committed: false,
}
} else if name
.chars()
.zip(name[1..].chars())
.any(|(c, next_c)| separator(c) && separator(next_c))
{
ParseResult::Err {
message: format!(
"I'm expecting {} but found `{}` with duplicated separators.",
expecting, name
),
from: Location {
col: location.col - name.len(),
..location
},
to: location,
state,
committed: false,
}
} else if separator(name.chars().last().unwrap()) {
ParseResult::Err {
message: format!(
"I'm expecting {} but found `{}` ended with the separator `{}`.",
expecting,
name,
&name.chars().last().unwrap()
),
from: Location {
col: location.col - name.len(),
..location
},
to: location,
state,
committed: false,
}
} else {
ParseResult::Ok {
input,
location,
output: name,
state,
committed: true,
}
}
})
}
#[derive(Copy, Clone)]
pub enum Trailing {
Forbidden,
Optional,
Mandatory,
}
#[derive(Clone)]
pub enum OneOfTwo<T1, T2> {
First(T1),
Second(T2),
}
impl<'a, P1, P2, S: Clone + 'a> Parser<'a> for OneOfTwo<P1, P2>
where
P1: Parser<'a, State = S>,
P2: Parser<'a, Output = P1::Output, State = S>,
{
type Output = P1::Output;
type State = S;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self {
OneOfTwo::First(ref mut p) => p.parse(input, location, state),
OneOfTwo::Second(ref mut p) => p.parse(input, location, state),
}
}
}
#[derive(Clone)]
pub enum OneOfThree<T1, T2, T3> {
First(T1),
Second(T2),
Third(T3),
}
impl<'a, P1, P2, P3, S: Clone + 'a> Parser<'a> for OneOfThree<P1, P2, P3>
where
P1: Parser<'a, State = S>,
P2: Parser<'a, Output = P1::Output, State = S>,
P3: Parser<'a, Output = P1::Output, State = S>,
{
type Output = P1::Output;
type State = S;
fn parse(
&mut self,
input: &'a str,
location: Location,
state: Self::State,
) -> ParseResult<'a, Self::Output, Self::State> {
match self {
OneOfThree::First(ref mut p) => p.parse(input, location, state),
OneOfThree::Second(ref mut p) => p.parse(input, location, state),
OneOfThree::Third(ref mut p) => p.parse(input, location, state),
}
}
}
pub fn sequence<
'a,
A: Clone + 'a,
StartOutput: Clone + 'a,
StartParser: 'a,
ItemParser: 'a,
SepOutput: Clone + 'a,
SepParser: 'a,
SpacesParser: 'a,
EndOutput: Clone + 'a,
EndParser: 'a,
S: Clone + 'a,
>(
start: StartParser,
item: impl Fn() -> ItemParser,
separator: impl Fn() -> SepParser,
spaces: impl Fn() -> SpacesParser,
end: EndParser,
trailing: Trailing,
) -> impl Parser<'a, Output = Vec<A>, State = S>
where
StartParser: Parser<'a, Output = StartOutput, State = S>,
ItemParser: Parser<'a, Output = A, State = S>,
SepParser: Parser<'a, Output = SepOutput, State = S>,
SpacesParser: Parser<'a, Output = (), State = S>,
EndParser: Parser<'a, Output = EndOutput, State = S>,
{
wrap(
pair(start, spaces()),
optional(
pair(
item(),
right(
spaces(),
left(
zero_or_more(wrap(
left(separator(), spaces()).backtrackable(),
item(),
spaces(),
)),
match trailing {
Trailing::Forbidden => succeed!().first_of_three(),
Trailing::Optional => {
optional_with_default((), left(separator().ignore(), spaces()))
.second_of_three()
}
Trailing::Mandatory => {
left(separator(), spaces()).ignore().third_of_three()
}
},
),
),
)
.map(move |(first_item, mut rest_items)| {
rest_items.insert(0, first_item);
rest_items
}),
)
.map(|items| items.unwrap_or(vec![])),
end,
)
}
fn wrap<'a, A: Clone + 'a, B: Clone + 'a, C: Clone + 'a, P1: 'a, P2: 'a, P3: 'a, S: Clone + 'a>(
left_delimiter: P1,
wrapped: P2,
right_delimiter: P3,
) -> impl Parser<'a, Output = B, State = S>
where
P1: Parser<'a, Output = A, State = S>,
P2: Parser<'a, Output = B, State = S>,
P3: Parser<'a, Output = C, State = S>,
{
right(left_delimiter, left(wrapped, right_delimiter))
}
pub fn located<'a, P: 'a, A, S: Clone + 'a>(
mut parser: P,
) -> impl Parser<'a, Output = Located<A>, State = S>
where
P: Parser<'a, Output = A, State = S>,
{
fn_parser(
move |input, location, state| match parser.parse(input, location, state) {
ParseResult::Ok {
input: cur_input,
output,
location: cur_location,
state: cur_state,
committed: cur_committed,
} => ParseResult::Ok {
input: cur_input,
output: Located {
value: output,
from: Location {
row: location.row,
col: location.col,
},
to: Location {
row: cur_location.row,
col: cur_location.col,
},
},
location: cur_location,
state: cur_state,
committed: cur_committed,
},
ParseResult::Err {
message,
from,
to,
state,
committed,
} => ParseResult::Err {
message,
from,
to,
state,
committed,
},
},
)
}
pub fn display_error(source: &str, error_message: String, from: Location, to: Location) -> String {
let row = from.row;
let col = from.col;
let line = source.lines().nth(row - 1).unwrap();
let error_length = if from.row < to.row {
std::cmp::max(line.len() + 1 - from.col, 1)
} else if to.col == from.col {
1
} else {
to.col - from.col
};
let row_tag = row.to_string();
let row_tag_len = if row < source.lines().count() {
(row + 1).to_string().len()
} else {
row_tag.len()
};
let prev_line = if row > 1 {
format!("{: >width$}", (row - 1).to_string(), width = row_tag_len)
+ "| "
+ source.lines().nth(row - 2).unwrap()
+ "\n"
} else {
String::new()
};
let next_line = if row < source.lines().count() {
(row + 1).to_string() + "| " + source.lines().nth(row).unwrap() + "\n"
} else {
String::new()
};
let error_line = row_tag + "| " + line;
let error_pointer = " ".repeat(col - 1 + row_tag_len + 2) + &"^".repeat(error_length);
prev_line + &error_line + "\n" + &error_pointer + "\n" + &next_line + "⚠️ " + &error_message
}
fn update_state<'a, P: 'a, F>(parser: P, f: F) -> UpdateState<P, F>
where
P: Parser<'a>,
F: Fn(P::Output, P::State) -> P::State,
{
UpdateState(parser, f)
}
fn update<'a, P: 'a, A, B, F: Clone>(parser: P, f: F) -> Update<P, F>
where
P: Parser<'a, Output = A>,
F: FnOnce(&'a str, A, Location, P::State) -> ParseResult<'a, B, P::State>,
{
Update(parser, f)
}
#[doc(hidden)]
pub fn assert_succeed<'a, P: 'a, A: PartialEq + Debug>(mut parser: P, source: &'a str, expected: A)
where
P: Parser<'a, Output = A, State = ()>,
{
assert_eq!(
parser
.parse(source, Location { row: 1, col: 1 }, ())
.unwrap(source),
expected
)
}
#[doc(hidden)]
pub fn assert_fail<'a, P: 'a, A: Debug>(mut parser: P, source: &'a str, message: &'a str)
where
P: Parser<'a, Output = A, State = ()>,
{
assert_eq!(
parser
.parse(source, Location { row: 1, col: 1 }, ())
.unwrap_err(),
message
)
}
fn unicode_column_width(s: &str) -> usize {
s.graphemes(true).map(grapheme_column_width).sum()
}
fn grapheme_column_width(s: &str) -> usize {
use xi_unicode::EmojiExt;
for c in s.chars() {
if c.is_emoji_modifier_base() || c.is_emoji_modifier() {
return 2;
}
}
UnicodeWidthStr::width(s)
}
fn char_column_width(c: char) -> usize {
UnicodeWidthChar::width(c).unwrap_or(0)
}