bogobble/
common.rs

1#![allow(deprecated)]
2//! Generally useful base parsers
3//! Str,Int,Uint,Esc,Float
4//!
5//! ```rust
6//! use bogobble::*;
7//! use common::*;
8//!
9//! assert_eq!(Bool.parse_s("true").unwrap(),true);
10//! assert_eq!(Bool.parse_s("false").unwrap(),false);
11//!
12//! assert_eq!(Quoted.parse_s(r#""hello\t\"world\"""#),Ok("hello\t\"world\"".to_string()));
13//!
14//! assert_eq!(Ident.parse_s("me34A_ dothing").unwrap(),"me34A_");
15//! assert_eq!(Int.parse_s("32").unwrap(),32);
16//!
17//! //floats
18//! assert_eq!(Float.parse_s("32.").unwrap(),32.);
19//! assert_eq!(Float.parse_s("-23.4").unwrap(),-23.4);
20//! assert_eq!(Float.parse_s("-23.4e2").unwrap(),-2340.);
21//! assert_eq!(Float.parse_s("123.4e-2").unwrap(),1.234);
22//! ```
23use crate::charbool::*;
24use crate::combi::*;
25use crate::err::*;
26use crate::iter::*;
27use crate::parser::*;
28use crate::reader::*;
29use crate::strung::*;
30//use crate::strings::*;
31//use crate::tuple::*;
32use crate::select::*;
33use std::convert::TryFrom;
34
35parser! { "Escapes a '\' and converts '\\n' '\\t' '\\r'"
36    (Esc->char)
37    last('\\',or!('t'.map(|_|'\t'), 'r'.map(|_|'\r'), 'n'.map(|_|'\n'), Any.one()))
38}
39
40parser! { "A string surrounded in Quotes"
41    (Quoted->String),
42    ('"',chars_until(or(Esc, Any.one()), '"')).map(|(_,( b,_))| b),
43}
44
45parser! { "A letter followed by numbers and letters or '_'"
46    (Ident->String)
47    string((Alpha.iplus(), (Alpha, NumDigit, '_').istar()))
48}
49
50#[deprecated(since = "0.5.0", note = "use Ident instead")]
51pub fn common_ident<'a>(it: &PIter<'a>) -> ParseRes<'a, String> {
52    Ident.parse(it)
53}
54
55parser! { "a usize"
56    (UInt->usize)
57    common_uint
58}
59
60#[deprecated(since = "0.5.1", note = " will go private as UInt does the job")]
61pub fn common_uint<'a>(it: &PIter<'a>) -> ParseRes<'a, usize> {
62    let mut added = false;
63    let mut res: usize = 0;
64    let mut it = it.clone();
65    loop {
66        let it2 = it.clone();
67        match it.next() {
68            Some(v) if is_num(v) => {
69                added = true;
70                res = res
71                    .checked_mul(10)
72                    .ok_or(it.err_s("A Smaller number"))?
73                    .checked_add(v as usize - '0' as usize)
74                    .ok_or(it.err_s("A Smaller number"))?;
75            }
76            Some('_') => {}
77            _ => {
78                if added {
79                    return Ok((it2, res, None));
80                }
81                return it2.err_rs("[0-9]*");
82            }
83        }
84    }
85}
86
87parser! { "Returns a parsed isize"
88    (Int->isize)
89    (maybe('-'),UInt).try_map(|(m,n)|{
90        let n = isize::try_from(n).map_err(|_|Expected::Str("Int too big"))?;
91        match m {
92            Some(_)=>Ok(-n),
93            None=>Ok(n),
94        }
95    })
96}
97
98parser! { "the words 'true' or 'false'"
99    (Bool->bool)
100    or(keyword("true").map(|_|true),keyword("false").map(|_|false))
101}
102
103fn dot_part<'a>(i: &PIter<'a>) -> ParseRes<'a, f64> {
104    let mut res = 0.;
105    let mut exp = 0.1;
106    let mut it = i.clone();
107    if it.next() != Some('.') {
108        return i.err_rs("A Dot");
109    }
110    loop {
111        let it2 = it.clone();
112        match it.next() {
113            Some('_') => {}
114            Some(v) if is_num(v) => {
115                res += (((v as i64) as f64) - 48.0) * exp;
116                exp *= 0.1;
117            }
118            _ => return Ok((it2, res, None)),
119        }
120    }
121}
122
123parser! {"'e' followed by a uint, allowed on floats"
124    (Exponent->isize)
125    last('e',Int)
126}
127
128parser! { "floating point numbers eg '134.4e6'"
129    (Float->f64)
130    (Int,dot_part,maybe(Exponent)).map(|(n,d,e)|{
131        let mut res =n as f64;
132        res += res.signum() * d;
133        if let Some(exp) = e{
134            match exp >= 0{
135                true =>{
136                    for _ in 0..exp {
137                        res *= 10.
138                    }
139                }
140                false =>{
141                    for _ in 0..-exp {
142                        res /= 10.
143                    }
144                }
145            }
146        };
147        res
148    })
149
150}
151
152#[cfg(test)]
153pub mod test {
154    use super::*;
155    #[test]
156    pub fn test_parse_numbers() {
157        let r = Int.parse_s("32").unwrap();
158        assert_eq!(r, 32);
159        let r = Int.parse_s("-45023").unwrap();
160        assert_eq!(r, -45023);
161        let r = Int.parse_s("34_234").unwrap();
162        assert_eq!(r, 34234);
163        assert!(Int.parse_s("45654323456765432345676543212345654").is_err());
164        assert!(Int.parse_s("   45").is_err());
165    }
166
167    #[test]
168    pub fn parse_floats() {
169        let r = Float.parse_s("32.").unwrap();
170        assert_eq!(r, 32.);
171        let r = Float.parse_s("-23.4").unwrap();
172        assert_eq!(r, -23.4);
173        let r = Float.parse_s("-23.4e2").unwrap();
174        assert_eq!(r, -2340.);
175        let r = Float.parse_s("123.4e-2").unwrap();
176        assert_eq!(r, 1.234);
177        assert!(Float.parse_s("123").is_err());
178    }
179}