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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
//! Gobble is a simple parser combinator system for parsing strings that aims to leave your
//! parser looking as much like a declarative grammar as possible while still being rust code
//!
//! Creating Parsers in rust should be quite straight forward. For example parsing a function call
//!
//! ```rust
//! use gobble::*;
//! parser!{
//!     (Ident->String)
//!     string((Alpha.one(),(Alpha,NumDigit,'_').istar()))
//! }
//!
//! parser!{
//!     (FSig->(String,Vec<String>))
//!     (first(Ident,"("),sep_until_ig(Ident,",",")"))
//! }
//! let (nm, args) = FSig.parse_s("loadFile1(fname,ref)").unwrap();
//! assert_eq!(nm, "loadFile1");
//! assert_eq!(args, vec!["fname", "ref"]);
//! //Idents can't begin with numbers
//! assert!(FSig.parse_s("23file(fname,ref)").is_err());
//! ```
//!
//! If you'd prefer not to use macros, you don't have to:
//!
//! ```rust
//! use gobble::*;
//! let ident = || string((Alpha.one(),(Alpha,NumDigit,'_').istar()));
//!
//! let fsig = (first(ident(),"("),sep_until_ig(ident(),",",")"));
//!  
//!  let (nm, args) = fsig.parse_s("loadFile1(fname,ref)").unwrap();
//!  assert_eq!(nm, "loadFile1");
//!  assert_eq!(args, vec!["fname", "ref"]);
//!  //identifiers cant start with numbers,
//!  assert!(fsig.parse_s("23file(fname,ref)").is_err());
//!  
//!  ```
//!
//!  But the macros guarantee of Zero-Sized types which is nice when combining them
//!
//!
//!  To work this library depends the following:
//!   
//!  ```rust
//!  pub enum ParseError {
//!     //...
//!  }
//!
//!  // In the OK Case the value mean
//!  //   LCChars = copy of original, but moved forward,
//!  //   V = The resulting type
//!  //   Option<ParserError> Only "Some" if the parser could have contined with more data
//!  //   --This is useful for tracking what values would have been expected at a certain point
//!  //
//!  pub type ParseRes<'a, V> = Result<(LCChars<'a>, V,Option<ParseError>), ParseError>;
//!
//!  //implements Iterator and can be cloned relatively cheaply
//!  pub struct LCChars<'a>{
//!     it:std::str::Chars<'a>,
//!     line:usize,
//!     col:usize,
//!  }
//!
//!  pub trait Parser<V> {
//!     // Takes a non-mut pointer to the iterator, so that the caller
//!     // may try something else if this doesn't work
//!     // clone it before reading next
//!     fn parse<'a>(&self,it:&LCChars<'a>)->ParseRes<'a,V>;
//!     
//!     //...helper methods
//!  }
//!  pub trait CharBool {
//!     fn char_bool(&self,c:char)->bool;
//!     //....helper methods
//!     //
//!  }
//!  ```
//!
//!  Parser is automatically implemented for:
//!  * ```Fn<'a>(&LCChars<'a>)->ParseRes<'a,String>```
//!  * ```&'static str``` which will return itself if it matches
//!  * ```char``` which will return itself if it matched the next char
//!  * Tuples of up to 6 parsers. Returning a tuple of all the
//!     parsers matched one after the
//!  other.
//!
//!  Most of the time a parser can be built simply by combining other parsers
//!  ```rust
//!  use gobble::*;
//!
//!  // map can be used to convert one result to another
//!  // keyval is now a function that returns a parser
//!  let keyval = || (common::Ident,":",common::Quoted).map(|(a,_,c)|(a,c));
//!
//!  //this can also be written as below for better type safety
//!  fn keyval2()->impl Parser<Out=(String,String)>{
//!     (common::Ident,":",common::Quoted).map(|(a,_,c)|(a,c))
//!  }
//!
//!  // or as a macro KeyVal is now a struct like:
//!  // pub struct KeyVal;
//!  parser!{
//!     (KeyVal->(String,String))
//!     (common::Ident,":",common::Quoted).map(|(a,_,c)|(a,c))
//!  }
//!  
//!  //parse_s is a helper on Parsers
//!  let (k,v) = keyval().parse_s(r#"car:"mini""#).unwrap();
//!  assert_eq!(k,"car");
//!  assert_eq!(v,"mini");
//!
//!  //this can now be combined with other parsers.
//!  // 'ig_then' combines 2 parsers and drops the result of the first
//!  // 'then_ig' drops the result of the second
//!  // 'sep_until will repeat the first term into a Vec, separated by the second
//!  //    until the final term.
//!  let obj = || "{".ig_then(sep_until_ig(keyval(),",","}"));
//!
//!  let obs = obj().parse_s(r#"{cat:"Tiddles",dog:"Spot"}"#).unwrap();
//!  assert_eq!(obs[0],("cat".to_string(),"Tiddles".to_string()));
//!
//!  ```
//!  ## CharBool
//!
//!  CharBool is the trait for boolean char checks. It is auto implemented for:
//!  * Fn(char)->bool
//!  * char -- Returns true if the input matches the char
//!  * &'static str -- returns true if the str contains the input
//!  * several zero size types - Alpha,NumDigit,HexDigit,WS,WSL,Any
//!  * Tuples of up to 6 CharBools -- returning true if any of the members succeed
//!
//!  This means you can combine them in tuples ```(Alpha,NumDigit,"_").char_bool(c)```
//!  will be true if any of them match
//!
//!  
//!
//!  CharBool also provides several helper methods which each return a parser
//!  * ```one(self)``` matches and returns exactly 1 character
//!  * ```plus(self)``` '+' requires at least 1 matches and ruturns a string
//!  * ```min_n(self,n:usize)```  requires at least n matches and ruturns a string
//!  * ```star(self)``` '*' matches any number of chars returning a string
//!  * ```exact(self,n:usize)``` '*' matches exactly n chars returning a string
//!  * ```iplus(self)``` '+' requires at least 1 matches and ruturns a ()
//!  * ```istar(self)``` '*' matches any number of chars returning a ()
//!  * ```iexact(self,n:usize)``` matches exactly n chars returning a ()
//!  
//!  And a helper that returns a CharBool
//!  * ```except(self,cb:CharBool)``` Passes if self does, and cb doesnt
//! ```rust
//! use gobble::*;
//! let s = |c| c > 'w' || c == 'z';
//! let xv = s.one().parse_s("xhello").unwrap();
//! assert_eq!(xv,'x');
//!
//! let id = (Alpha,"_*").min_n(4).parse_s("sm*shing_game+you").unwrap();
//! assert_eq!(id,"sm*shing_game");
//!
//! // not enough matches
//! assert!((NumDigit,"abc").min_n(4).parse_s("23fflr").is_err());
//!
//! // any succeeds even with no matches equivilent to min_n(0) but "Zero Size"
//! assert_eq!((NumDigit,"abc").star().parse_s("23fflr"),Ok("23".to_string()));
//! assert_eq!((NumDigit,"abc").star().parse_s("fflr"),Ok("".to_string()));
//!
//! ```
//!
//! ## White Space
//!
//! White space is pretty straight forward to handle
//!
//! ```rust
//! use gobble::*;
//! let my_ws = || " \t".star();
//! // middle takes three parsers and returns the result of the middle
//! // this could also be done easily with 'map' or 'then_ig'
//! let my_s = |p| middle(my_ws(),p,my_ws());
//!
//! let sp_id = my_s(common::Ident);
//! let v = sp_id.parse_s("   \t  doggo  ").unwrap();
//! assert_eq!(v,"doggo");
//! ```
//! That said gobble already provides ```WS``` and ```s_(p)```
//!
//! ```rust
//! use gobble::*;
//! //eoi = end of input
//! let p = repeat_until_ig(s_("abc".plus()),eoi);
//! let r = p.parse_s("aaa \tbbb bab").unwrap();
//! assert_eq!(r,vec!["aaa","bbb","bab"]);
//! ```
//!
//! ## Recursive Structures
//!
//! Some structures like Json, or programming languages need to be able to
//! handle recursion.  Simply combining the function parsers could lead
//! to infinitely sized structures.
//!
//! The simplest way to avoid this problem is to use the parser macro.
//! Every parser created with the macro is zero sized
//!
//! But if you would really rather not use the macros, the way to handle this is
//! to make sure one member of the loop is not builtd into the structure.
//! Instead to create it using the 'Fn ->ParseRes' method.
//!
//! ```rust
//! use gobble::*;
//! #[derive(Debug,PartialEq)]
//! enum Expr {
//!     Val(isize),
//!     Add(Box<Expr>,Box<Expr>),
//!     Paren(Box<Expr>),
//! }
//!
//! fn expr_l()->impl Parser<Out=Expr>{
//!     or(
//!         middle("(",s_(expr),")").map(|e|Expr::Paren(Box::new(e))),
//!         common::Int.map(|v|Expr::Val(v))
//!     )
//! }
//!
//! // using the full fn def we avoid the recursive structure
//! fn expr<'a>(it:&LCChars<'a>)->ParseRes<'a,Expr> {
//!     //note that expr_l has brackets but expr doesnt.
//!     //expr is a reference to a static function
//!     let p = (expr_l(),maybe(s_("+").ig_then(expr)))
//!         .map(|(l,opr)|match opr{
//!             Some(r)=>Expr::Add(Box::new(l),Box::new(r)),
//!             None=>l,
//!         });
//!     
//!
//!     p.parse(it)
//! }
//!
//! let r = expr.parse_s("45 + (34+3 )").unwrap();
//!
//! //recursive structures are never fun to write manually
//! assert_eq!(r,Expr::Add(
//!                 Box::new(Expr::Val(45)),
//!                 Box::new(Expr::Paren(Box::new(Expr::Add(
//!                     Box::new(Expr::Val(34)),
//!                     Box::new(Expr::Val(3))
//!                 ))))
//!             ));
//!
//! ```

#[macro_use]
pub mod macros;

pub mod chars;
pub mod combi;
pub mod common;
pub mod err;
pub mod iter;
pub mod ptrait;
pub mod pull;
pub mod reader;
pub mod repeater;
pub mod skip;
pub mod strings;
pub mod traits;
pub mod tuple;

pub use chars::*;
pub use combi::*;
//pub use common::*;
pub use err::*;
pub use iter::*;
pub use macros::*;
pub use ptrait::*;
pub use reader::*;
pub use repeater::*;
pub use skip::*;
pub use strings::*;
pub use tuple::*;