parcelona 0.1.3

minimalistic elegance parser combinator library
Documentation
//!  Parcelona minimalistic elegance parser combinator library.
//!

pub type ParseResult<'a,I,O> = std::result::Result<(&'a [I],O),&'a [I]>;
 
/// Main parser definition
pub trait Parser<'a,I,O>:  {
    fn parse(&self, input:&'a [I]) -> ParseResult<'a,I,O>;
    fn option(self) -> impl Parser<'a,I,Option<O>> + Clone;
    fn more(self,no_zero:bool) -> impl Parser<'a,I,Vec<O>> + Clone;    
}

impl<'a,I:'a,F,O> Parser<'a,I,O> for F
where
    F: Fn(&'a[I]) -> ParseResult<'a,I,O> + Clone,
{
    fn parse(&self, input:&'a [I]) -> ParseResult<'a,I,O> {  self(input)  }
    fn option(self) -> impl Parser<'a,I,Option<O>>+Clone { option(self) }
    fn more(self,no_zero:bool) -> impl Parser<'a,I,Vec<O>>+Clone { more(self,no_zero) }
}


/// parser 'take', this is a single parser, but it can be parameterized by functions.
pub fn take<'a,T,P>(predicat: P) -> impl Parser<'a,T,&'a[T]>+Clone
where
     T: 'a,
     P: Fn(&'a[T]) -> usize + Clone,
{     
    move |input: &'a[T]| {
        let i = predicat(input);
        if i>0 { return Ok(split_at_revers(input, i)); }
        Err(input)
    }    
}

/// function 'any' for parametrize parser
pub fn any<'a,T:'a+Eq+Clone>(pattern: &'a[T]) -> impl Fn(&'a[T]) -> usize+'a+Clone {
    |input| { if input.len()>0 && pattern.contains(&input[0]) { 1 } else { 0 } }
}

/// function 'starts_with' for parametrize parser
pub fn starts_with<'a,T:'a+Eq+Clone>(pattern: &'a[T]) -> impl Fn(&'a[T]) -> usize+'a+Clone {
    |input| { if input.starts_with(pattern) { pattern.len() } else { 0 } }
}

/// function 'starts_with_any' for parametrize parser
pub fn starts_with_any<'a,T:'a+Eq+Clone>(pattern: &'a[&'a[T]]) -> impl Fn(&'a[T]) -> usize+'a+Clone {
    move |input| {
        for i in pattern {  if input.starts_with(i) { return pattern.len() }; };
        0
    }
}

/// enum for 'seq' function
#[derive(Clone)]
 pub enum SeqCount {
    Max(usize),
    Exact(usize),
    Range((usize,usize)),
    None,    
}

/// function 'seq'-sequence for parametrize parser
pub fn seq<'a,P,T:'a+Eq+Clone>(p: P, count:SeqCount) -> impl Fn(&'a[T]) -> usize+'a+Clone
where
    P: Fn(& T) -> bool+Clone+'a,
{ move |input| {
    let mut c:usize = 0;
    match count {
        SeqCount::None   =>        for i in input { if p(i)      {c+=1;} else {break;} },
        SeqCount::Max(x) =>        for i in input { if c<x&&p(i) {c+=1;} else {break;} },
        SeqCount::Exact(x) =>    { for i in input { if c<x&&p(i) {c+=1;} else {break;} } if c!=x {c=0;}; },
        SeqCount::Range((x,y))=> { for i in input { if c<y&&p(i) {c+=1;} else {break;} } if c<x  {c=0;}; },
    }
    c
}}


// combinators

/// combinator map
pub fn map<'a,T:'a,F,P,R1,R2>(parser: P, map_fn: F) -> impl Parser<'a,T,R2>+Clone
where
    P: Parser<'a,T,R1>+Clone,
    F: Fn(R1) -> R2+Clone,
{
    move |input| {
        parser
            .parse(input)
            .map(|(next_input, result)| (next_input, map_fn(result)))
    }
}

/// combinator option - allways return Ok, no Err
pub fn option<'a,T:'a,P,R>(parser: P) -> impl Parser<'a,T,Option<R>>+Clone
where
    P: Parser<'a,T,R>+Clone,
{
    move |input| {  
        match parser.parse(input) {
            Ok((input,r)) => Ok((input,Some(r))),
            _             => Ok((input,None))   
    }}
}

/// combinator pair
pub fn pair<'a,T:'a,P1,P2,R1,R2>(p1:P1,p2:P2) -> impl Parser<'a,T,(R1,R2)>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
{
    move |input| {
        p1.parse(input).and_then(|(next_input,r1)| { 
        p2.parse(next_input).map(|(next_input,r2)| (next_input,(r1,r2))) })
    }
}

/// combinator left
pub fn left<'a,T:'a,P1,P2,R1,R2>(p1:P1,p2:P2) -> impl Parser<'a,T,R1>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
{
    map(pair(p1,p2),|(l,_)|l)
}

/// combinator right
pub fn right<'a,T:'a,P1,P2,R1,R2>(p1:P1,p2:P2) -> impl Parser<'a,T,R2>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
{
   map(pair(p1,p2),|(_,r)|r)
}

/// combinator right 'left'-is options, if left returns Error it is ignored
pub fn right_opt<'a,T:'a,P1,P2,R1,R2>(p1:P1,p2:P2) -> impl Parser<'a,T,R2>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
{
    move |input| {
        if let Ok((input,_)) = p1.parse(input) { p2.parse(input) } 
        else { p2.parse(input) }
    }
}
 
/// combinator left 'right'-is options, if right returns Error it is ignored
pub fn left_opt<'a,T:'a,P1,P2,R1,R2>(p1:P1,p2:P2) -> impl Parser<'a,T,R1>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
{
    move |input| {
        p1.parse(input).map(|(next_input, r1)| {
           match p2.parse(next_input) {
               Ok((next_input,_)) => (next_input,r1),
               _                  => (next_input,r1),
           }    
        })
    }
}

/// combinator find, be careful when choosing a parser 'step', in most cases it
/// should be a one step parser.
pub fn find<'a,T:'a,P1,P2,R1,R2>(step:P1,p:P2) -> impl Parser<'a,T,R2>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
{
    move |input: &'a[T]| {
        let mut next_input1 = input;
        while let Ok((next_input2,_)) = step.parse(next_input1) {
            let r = p.parse(next_input1);
            if r.is_ok() { return r; }
            next_input1 = next_input2;
        }     
        Err(input)
    }
}

/// const for write more readable parsers
pub const NO_ZERO:bool = true;
pub const ZERO:bool    = false;

/// combinator more
pub fn more<'a,T:'a,P,R>(p:P,no_zero:bool) -> impl Parser<'a,T,Vec<R>>+Clone
where
    P: Parser<'a,T,R>+Clone,
{
    move |mut input: &'a[T]| {
        let mut result = Vec::new();
        while let Ok((next_input,item)) = p.parse(input) {
            input = next_input;
            result.push(item);
        }
        if no_zero && result.is_empty() { Err(input) }
        else { Ok((input,result)) }
    }
}

/// combinator alt
pub fn alt<'a,T:'a,P,R>(p:&'a[P]) -> impl Parser<'a,T,R>+Clone
where
    P: Parser<'a,T,R>+Clone,
{
    move |input: &'a[T]| {
       for x in p {
         let result = x.parse(input);
         match result {
             Ok(_) => { return result; },
             _     => { continue; },
         }
       }
       Err(input)
    }
}

/// combinator separated pair
pub fn sep_pair<'a,T:'a,P1,P_,P2,R1,R2,R_>(p1:P1,sep:P_,p2:P2) -> impl Parser<'a,T,(R1,R2)>+Clone
where
    P1: Parser<'a,T,R1>+Clone,
    P2: Parser<'a,T,R2>+Clone,
    P_: Parser<'a,T,R_>+Clone,
{
       pair(left(p1,sep),p2)   
}

/// just usefull function
#[inline]
pub fn split_at_revers<'a, T>(input: &'a [T], count: usize) -> (&'a [T], &'a [T]) {
    (&input[count..], &input[..count])
}

// just drop all parser result
fn drop<I>(_: I) -> () {
    ()
}