1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
//! Gobble is a simple parser combinator system for parsing strings.
//!
//! For example parsing a function call
//!
//! ```rust
//! use gobble::*;
//! let ident = || {
//!     read_fs(is_alpha, 1)
//!         .then(read_fs(is_alpha_num, 0))
//!         .map(|(mut a, b)| {
//!             a.push_str(&b);
//!             a
//!     })
//! };
//!
//! let fsig = ident()
//!     .then_ig(tag("("))
//!     .then(sep(ident(), tag(","), true))
//!     .then_ig(tag(")"));
//!  
//!  let (nm, args) = fsig.parse_s("loadFile1(fname,ref)").unwrap();
//!  assert_eq!(nm, "loadFile1");
//!  assert_eq!(args, vec!["fname", "ref"]);
//!
//!  assert!(fsig.parse_s("23file(fname,ref)").is_err());
//!  
//!  ```
//!
//!  While from the example it is not so clear. A parser is a trait.
//!   
//!  ```ignore
//!
//!  pub type ParseRes<'a, V> = Result<(LCChars<'a>, V), ParseError>;
//!
//!  pub trait Parser<V> {
//!     fn parse<'a>(&self, LCChars<'a>)->ParseRes<'a,V>;
//!
//!     fn parse(&self,&str)->Result<V,ParseError>{
//!         // a helper method, parse_s which parses strings, by
//!         // converting them to a LLCChars, which is just a wrapper around
//!         // the chars iterator to keep track of line and column number
//!     }
//!
//!     //There are combinator methods and a helper methods that produce
//!     // other parsers wrapped around this one.  "or","map","then","then_ig","ig_then"
//!  }
//!  ```
//!
//!  Parser is also automatically implemented for any function that follows
//!  the same signature (without the self)
//!  ```rust
//!  use gobble::*;
//!  fn my_parser<'a>(i:&LCChars<'a>)->ParseRes<'a,String>{
//!     // i is an non mut pointer, so you have to clone it to mutate it,
//!     // this means parent iterators can try something else if this one fails
//!     // The combinators will do that for you
//!     let (it_clone,val) = tag("(").or(tag("[")).ig_then(read_fs(is_num,1)).parse(i)?;
//!     Ok((it_clone,val))
//!     //or you can just loop on the iterator clone yourself
//!  }
//!  //my_parser now can be combined with other parsers
//!  let (n,s) = my_parser.then(read_fs(is_alpha,1)).parse_s("(45red").unwrap();
//!  assert_eq!(n,"45");
//!  assert_eq!(s,"red");
//!  ```

pub mod combi;
pub mod err;
pub mod iter;
pub mod ptrait;
pub mod reader;
pub mod repeater;

pub use combi::*;
pub use err::*;
pub use iter::*;
pub use ptrait::*;
pub use reader::*;
pub use repeater::*;

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    pub fn demo_test() {
        let ident = || {
            read_fs(is_alpha, 1)
                .then(read_fs(is_alpha_num, 0))
                .map(|(mut a, b)| {
                    a.push_str(&b);
                    a
                })
        };
        let fsig = ident()
            .then_ig(tag("("))
            .then(sep(ident(), tag(","), true))
            .then_ig(tag(")"));

        let (nm, args) = fsig.parse_s("loadFile1(fname,ref)").unwrap();
        assert_eq!(nm, "loadFile1");
        assert_eq!(args, vec!["fname", "ref"]);
    }
}