use crate::pos::{Position};
#[derive(Debug, Clone, Copy)]
pub struct View<'a>{
pub(crate) view : &'a str,
pub(crate) pos : Position,
}
impl<'a> From<&'a str> for View<'a> {
fn from(s : &'a str) -> Self {
Self::new(s)
}
}
impl<'a> View<'a> {
#[must_use]
pub const fn new(view : &'a str) -> Self {
Self{
view,
pos : Position::new_zero(),
}
}
#[must_use]
pub const fn get_view(&self) -> &'a str{
self.view
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.view.is_empty()
}
#[must_use]
pub const fn top_position(&self) -> &Position {
&self.pos
}
#[must_use]
pub const fn into_pos(self) -> Position {
self.pos
}
#[must_use]
pub fn progress(self, inc : usize) -> (&'a str, Self) {
if inc == 0 {
("", self)
}
else{
let (pfx, sfx) = self.view.split_at(inc);
let mut fit = pfx.split('\n');
let mut elem = fit.next().unwrap(); let mut nls = 0;
for el in fit {
elem = el;
nls += 1;
}
let (mut r, mut c) = self.pos.unpack();
if nls > 0 {
c = 0;
r += nls;
}
c += u32::try_from(elem.len()).unwrap();
(pfx, Self{
pos : Position::new(r, c),
view : sfx,
})
}
}
#[allow(clippy::missing_errors_doc)]
pub fn match_tool<T : Tool<'a>>(self, t : &T) -> Result<Self, T::Error> {
t.parse(self).map(|i| i.2)
}
#[allow(clippy::missing_errors_doc)]
#[must_use]
pub fn match_always<T : AlwaysTool<'a>>(self, t : &T) -> Self {
t.parse_always(self).2
}
#[allow(clippy::missing_errors_doc)]
pub fn match_tool_string<T : Tool<'a>>(self, t : &T) -> Result<(&'a str, Self), T::Error> {
let vw = self.get_view();
t.parse(self).map(|i| (&vw[0..i.1], i.2))
}
#[allow(clippy::missing_errors_doc)]
pub fn match_tool_data<T : Tool<'a>>(self, t : &T) -> Result<(T::Data, Self), T::Error> {
t.parse(self).map(|i| (i.0, i.2))
}
#[allow(clippy::missing_errors_doc)]
pub fn match_always_data<T : AlwaysTool<'a>>(self, t : &T) -> (T::Data, Self) {
let i = t.parse_always(self);
(i.0, i.2)
}
#[allow(clippy::missing_errors_doc)]
pub fn match_tool_data_len<T : Tool<'a>>(self, t : &T) -> Result<(T::Data, usize, Self), T::Error> {
t.parse(self)
}
#[allow(clippy::missing_errors_doc)]
pub fn match_map<D, T, F>(self, t : &T, f : F) -> Result<(D, Self), T::Error> where
T : Tool<'a>,
F : FnOnce(T::Data, Position) -> D
{
self.match_tool_data(t)
.map(|(d, s)| (f(d, s.pos), s))
}
#[allow(clippy::missing_errors_doc)]
pub fn match_map_err<D, E, T, F, G>(self, t : &T, f : F, g : G) -> Result<(D, Self), E> where
T : Tool<'a>,
F : FnOnce(T::Data, Position) -> D,
G : FnOnce(T::Error) -> E
{
self.match_tool_data(t)
.map(|(d, s)| (f(d, s.pos), s))
.map_err(g)
}
#[allow(clippy::missing_errors_doc)]
pub fn match_if_matches<PRE : Tool<'a>, R : Tool<'a>>(self, pre : &PRE, t : &R) -> Result<Self, R::Error> {
self.match_tool(pre).map_or(
Ok(self),
|next| next.match_tool(t))
}
#[allow(clippy::missing_errors_doc)]
pub fn match_if_else_data<PRE : Tool<'a>, R : Tool<'a>, ELS>(self, pre : &PRE, t : &R, els : ELS) -> Result<(R::Data, Self), R::Error> where
ELS : FnOnce(Self) -> Result<(R::Data, Self), R::Error>
{
self.match_tool(pre)
.map_or_else(
|_| els(self),
|next|next.match_tool_data(t))
}
#[allow(clippy::missing_errors_doc)]
pub fn match_if_else_data_len<PRE : Tool<'a>, R : Tool<'a>, ELS>(self, pre : &PRE, t : &R, els : ELS) -> Result<(R::Data, usize, Self), R::Error> where
ELS : FnOnce(Self) -> Result<(R::Data, usize, Self), R::Error>
{
self.match_tool(pre)
.map_or_else(
|_| els(self),
|next| next.match_tool_data_len(t))
}
}
pub trait Tool<'a> {
type Error;
type Data;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>;
}
pub trait AlwaysTool<'a> : Tool<'a> {
fn parse_always(&self, st : View<'a>) -> (Self::Data, usize, View<'a>);
fn parse_always_nodata(&self, st : View<'a>) -> ((), usize, View<'a>) {
let (_, l, s) = self.parse_always(st);
((), l, s)
}
}
#[derive(Debug)]
pub struct SetError<T, E>(pub T, pub ::core::marker::PhantomData<fn() -> E>);
impl<T, E> SetError<T, E> {
pub fn new(d : T) -> Self {
Self(d, ::core::marker::PhantomData)
}
}
impl<T : Clone, E> Clone for SetError<T, E> {
fn clone(&self) -> Self {
Self::new(self.0.clone())
}
}
impl<T : Copy, E> Copy for SetError<T, E> {}
impl<T : Default, E> Default for SetError<T, E> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T, E, B> AsRef<B> for SetError<T, E> where T : AsRef<B>, B : ?Sized {
fn as_ref(&self) -> &B {
self.0.as_ref()
}
}
impl<'a, T, E> AlwaysTool<'a> for SetError<T, E> where T : AlwaysTool<'a> {
fn parse_always(&self, st : View<'a>) -> (Self::Data, usize, View<'a>) {
self.0.parse_always(st)
}
}
impl<'a, T, E> Tool<'a> for SetError<T, E> where T : AlwaysTool<'a> {
type Error = E;
type Data = T::Data;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error> {
Ok(self.0.parse_always(st))
}
}
#[derive(Debug, Copy, Clone)]
pub struct MapTool<T, FD, FE>(pub T, pub FD, pub FE);
impl<'a, T, D, E, FD, FE> Tool<'a> for MapTool<T, FD, FE> where
T : Tool<'a>,
FD : Fn(T::Data) -> D,
FE : Fn(T::Error) -> E
{
type Data = D;
type Error = E;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error> {
self.0.parse(st)
.map(|(d, l, st)| ((self.1)(d), l, st) )
.map_err(&self.2)
}
}
impl<'a, T, D, E, FD, FE> AlwaysTool<'a> for MapTool<T, FD, FE> where
T : AlwaysTool<'a>,
FD : Fn(T::Data) -> D,
FE : Fn(T::Error) -> E
{
fn parse_always(&self, st : View<'a>) -> (Self::Data, usize, View<'a>) {
let (d, l, st) = self.0.parse_always(st);
((self.1)(d), l, st)
}
}
#[macro_export]
macro_rules! always_impl {
($i:ident) => {
always_impl!($i, ());
};
($i:ident, $t:ty) => {
impl<'a> Tool<'a> for $i {
type Error = core::convert::Infallible;
type Data = $t;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error> {
Ok(self.parse_always(st))
}
}
}
}
impl<'a, T> Tool<'a> for &T where T : Tool<'a> + ?Sized {
type Error = T::Error;
type Data = T::Data;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
T::parse(*self, st)
}
}
impl<'a, T> AlwaysTool<'a> for &T where T : AlwaysTool<'a> + ?Sized {
fn parse_always(&self, st : View<'a>) -> (Self::Data, usize, View<'a>) {
T::parse_always(*self, st)
}
}
impl<'a> Tool<'a> for char {
type Error = View<'a>;
type Data = Self;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
st.get_view().chars().next()
.and_then(|c| if c == *self {
Some((c, c.len_utf8(), st.progress(c.len_utf8()).1))
}
else {
None
})
.ok_or(st)
}
}
impl<'a> Tool<'a> for str {
type Error = View<'a>;
#[allow(clippy::needless_borrows_for_generic_args, clippy::use_self)]
type Data = &'a str;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
if st.get_view().starts_with(self) {
Ok((&st.get_view()[0..self.len()], self.len(), st.progress(self.len()).1))
}
else {
Err(st)
}
}
}
impl<'a, T> Tool<'a> for [T] where T : Tool<'a> {
type Data = (usize, T::Data);
type Error = Option<T::Error>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
let mut err = None;
for (i, t) in self.iter().enumerate() {
match t.parse(st) {
Ok(r) => return Ok(((i, r.0), r.1, r.2)),
Err(e) => err = Some(e),
}
}
Err(err)
}
}
impl<'a, T, const N : usize> Tool<'a> for [T; N] where T : Tool<'a> {
type Data = (usize, T::Data);
type Error = Option<T::Error>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
let mut err = None;
for (i, t) in self.iter().enumerate() {
match t.parse(st) {
Ok(r) => return Ok(((i, r.0), r.1, r.2)),
Err(e) => err = Some(e),
}
}
Err(err)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct TrueTool;
impl<'a> AlwaysTool<'a> for TrueTool {
fn parse_always(&self, st : View<'a>) -> (Self::Data, usize, View<'a>) {
((), 0, st)
}
}
always_impl!(TrueTool);
#[derive(Debug, Clone, Copy)]
pub struct Predicate<P>{
pub(crate) predicate : P,
}
impl<P> Predicate<P> {
pub const fn new(predicate : P) -> Self {
Self{
predicate,
}
}
}
impl<'a, P : Fn(char) -> bool> Tool<'a> for Predicate<P>{
type Data = char;
type Error = View<'a>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
st.get_view().chars().next().and_then(
|c| if (self.predicate)(c) {
Some((c, c.len_utf8(), st.progress(c.len_utf8()).1))
}
else {
None
})
.ok_or(st)
}
}
#[derive(Debug, Clone, Copy)]
pub struct PredicateData<P>{
pub(crate) predicate : P,
}
impl<P> PredicateData<P> {
pub const fn new(predicate : P) -> Self {
Self{
predicate,
}
}
}
impl<D, P : Fn(char) -> Option<D> > PredicateData<P> {
pub fn parse_char(&self, st : &str) -> Option<(D, usize)> {
st.chars().next().and_then(|c| {
(self.predicate)(c).map(|d| (d, c.len_utf8()))
})
}
}
impl<'a, D, P : Fn(char) -> Option<D>> Tool<'a> for PredicateData<P>{
type Data = D;
type Error = View<'a>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
st.get_view().chars().next().and_then(
|c| (self.predicate)(c).map(|d| (d, c.len_utf8())))
.map(|(d, l)| (d, l, st.progress(l).1))
.ok_or(st)
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct AnyChar;
impl<'a> Tool<'a> for AnyChar {
type Data = char;
type Error = View<'a>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
st.get_view().chars().next()
.map(|c| (c, c.len_utf8(), st.progress(c.len_utf8()).1))
.ok_or(st)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct EOFTool;
impl<'a> Tool<'a> for EOFTool{
type Data = ();
type Error = View<'a>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
if st.is_empty() {
Ok(((), 0, st))
}
else{
Err(st)
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NonEmpty<P>(pub P);
impl<'a, P> Tool<'a> for NonEmpty<P> where P : Tool<'a> {
type Data = P::Data;
type Error = Option<P::Error>;
fn parse(&self, st : View<'a>) -> Result<(Self::Data, usize, View<'a>), Self::Error>{
self.0.parse(st)
.map_err(Some)
.and_then(|d| if d.1 > 0 {Ok(d)} else {Err(None)})
}
}