reda_sp/parse/
base.rs

1use nom::branch::alt;
2use nom::bytes::complete::{tag, tag_no_case};
3use nom::character::complete::{alpha1, alphanumeric1, char, digit1, line_ending, not_line_ending, one_of, space0};
4use nom::combinator::{map_res, opt, recognize};
5use nom::error::VerboseError;
6use nom::combinator::map;
7use nom::multi::{many0, many1};
8use nom::sequence::{delimited, pair, preceded, terminated, tuple};
9use nom::{Err, IResult, Parser};
10use std::str;
11use std::str::FromStr;
12
13use reda_unit::{Angle, Capacitance, Current, Frequency, Inductance, Number, Resistance, Suffix, Time, Voltage};
14
15pub type NomResult<'a, O> = IResult<&'a str, O, VerboseError<&'a str>>; 
16
17/// Convert Error to Failure
18pub trait ToFailure<T, E> {
19    fn to_failure(self) -> Result<T, nom::Err<E>>;
20}
21
22impl<T, E> ToFailure<T, E> for Result<T, nom::Err<E>> {
23    fn to_failure(self) -> Result<T, nom::Err<E>> {
24        self.map_err(|e| match e {
25            nom::Err::Error(e) => nom::Err::Failure(e),
26            other => other,
27        })
28    }
29}
30
31// /// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and
32// /// trailing whitespace, returning the output of `inner`.
33// pub fn ws<'a, F: 'a, O>(inner: F) -> impl FnMut(&'a str) -> NomResult<'a, O> 
34// where
35//     F: FnMut(&'a str) -> NomResult<'a, O> 
36// {
37//     delimited(multispace0, inner, multispace0)
38// }
39
40/// '\n' is not space, but '\n+' is a space!
41pub fn smart_space0(input: &str) -> NomResult<()> {
42    let mut i = input;
43    while !i.is_empty() {
44        let bytes = i.as_bytes();
45        match bytes[0] {
46            b' ' | b'\t' | b'\r' => {
47                i = &i[1..];
48            }
49            b'\n' => {
50                if i.len() >= 2 && i.as_bytes()[1] == b'+' {
51                    i = &i[2..];
52                    while i.starts_with(' ') || i.starts_with('\t') {
53                        i = &i[1..];
54                    }
55                } else {
56                    break;
57                }
58            }
59            _ => break,
60        }
61    }
62    Ok((i, ()))
63}
64
65pub fn hws<'a, F: 'a, O>(inner: F) -> impl FnMut(&'a str) -> NomResult<'a, O>
66where
67    F: FnMut(&'a str) -> NomResult<'a, O>,
68{
69    delimited(smart_space0, inner, smart_space0)
70}
71
72macro_rules! wrap_parser {
73    ($parser:expr, $input:expr, $ctx:expr) => {
74        match $parser {
75            Ok(v) => Ok(v),
76            Err(Err::Incomplete(n)) => Err(Err::Incomplete(n)),
77            Err(Err::Error(_)) => Err(Err::Error(nom::error::VerboseError {
78                errors: [($input, nom::error::VerboseErrorKind::Context($ctx))].into(),
79            })),
80            Err(Err::Failure(_)) => Err(Err::Failure(nom::error::VerboseError {
81                errors: [($input, nom::error::VerboseErrorKind::Context($ctx))].into(),
82            })),
83        }
84    };
85}
86
87// typical string
88// ie. abcdef, de234, jkl_mn, ...
89pub fn identifier(input: &str) -> NomResult<&str> {
90    pub fn _identifier(input: &str) -> NomResult<&str> {
91        recognize(pair(
92            alt((alpha1, tag("_"))),
93            many0(alt((alphanumeric1, tag("_"), tag(".")))),
94        ))(input)
95    }
96    wrap_parser!(_identifier(input), input, "identifier")
97}
98
99// node string
100// ie. abcdef, de234, jkl_mn, ...
101pub fn node(input: &str) -> NomResult<&str> {
102    pub fn _node(input: &str) -> NomResult<&str> {
103        recognize(many1(alt((alphanumeric1, tag("_"), tag(".")))))(input)
104    }
105    wrap_parser!(_node(input), input, "node")
106}
107
108// unsigned integer number
109// ie, 100, 350
110pub fn unsigned_int(input: &str) -> NomResult<u32> {
111    pub fn _unsigned_int(input: &str) -> NomResult<u32> {
112        let str_parser = recognize(digit1);
113        map_res(
114            str_parser,
115            |res: &str| u32::from_str(res)
116        )(input)
117    }
118    wrap_parser!(_unsigned_int(input), input, "unsigned_int")
119}
120
121// parse signed floating number
122// The following is modified from the Python parser by Valentin Lorentz (ProgVal).
123pub fn float(input: &str) -> NomResult<f64> {
124    pub fn _float(input: &str) -> NomResult<f64> {
125        map_res(
126            alt((
127                // Case one: 42. and 42.42
128                recognize(tuple((opt(char('-')), decimal, char('.'), opt(decimal)))),
129                recognize(tuple((opt(char('-')), decimal))), // case two: integer as float number
130            )),
131            |res: &str| f64::from_str(res),
132        )(input)
133    }
134    wrap_parser!(_float(input), input, "float")
135}
136
137fn decimal(input: &str) -> NomResult<&str> {
138    recognize(many1(terminated(one_of("0123456789"), many0(char('_')))))(input)
139}
140
141pub fn number(input: &str) -> NomResult<Number> {
142    pub fn _number(input: &str) -> NomResult<Number> {
143        let (input, value) = float(input)?;
144        let (input, suffix) = opt(alt((
145            tag_no_case("g").map(|_| Suffix::Mega),
146            tag_no_case("meg").map(|_| Suffix::Mega),
147            tag_no_case("k").map(|_| Suffix::Kilo),
148            tag_no_case("m").map(|_| Suffix::Milli),
149            tag_no_case("u").map(|_| Suffix::Micro),
150            tag_no_case("n").map(|_| Suffix::Nano),
151            tag_no_case("p").map(|_| Suffix::Pico),
152        )))(input)?;
153    
154        Ok((
155            input,
156            Number {
157                value,
158                suffix: suffix.unwrap_or(Suffix::None),
159            },
160        ))
161    }
162    wrap_parser!(_number(input), input, "expect number")
163}
164
165pub fn time_number(input: &str) -> NomResult<Time> {
166    pub fn _time_number(input: &str) -> NomResult<Time> {
167        let (input, value) = float(input)?;
168        let (input, suffix) = opt(alt((
169            tag_no_case("gs").map(|_| Suffix::Mega),
170            tag_no_case("megs").map(|_| Suffix::Mega),
171            tag_no_case("ks").map(|_| Suffix::Kilo),
172            tag_no_case("ms").map(|_| Suffix::Milli),
173            tag_no_case("us").map(|_| Suffix::Micro),
174            tag_no_case("ns").map(|_| Suffix::Nano),
175            tag_no_case("ps").map(|_| Suffix::Pico),
176            tag_no_case("g").map(|_| Suffix::Mega),
177            tag_no_case("meg").map(|_| Suffix::Mega),
178            tag_no_case("k").map(|_| Suffix::Kilo),
179            tag_no_case("m").map(|_| Suffix::Milli),
180            tag_no_case("u").map(|_| Suffix::Micro),
181            tag_no_case("n").map(|_| Suffix::Nano),
182            tag_no_case("p").map(|_| Suffix::Pico),
183            tag_no_case("s").map(|_| Suffix::None),
184        )))(input)?;
185    
186        Ok((
187            input,
188            Number {
189                value,
190                suffix: suffix.unwrap_or(Suffix::None),
191            }.into(),
192        ))
193    }
194    wrap_parser!(_time_number(input), input, "expect time number")
195}
196
197pub fn voltage_number(input: &str) -> NomResult<Voltage> {
198    pub fn _voltage_number(input: &str) -> NomResult<Voltage> {
199        let (input, value) = float(input)?;
200        let (input, suffix) = opt(alt((
201            tag_no_case("gv").map(|_| Suffix::Mega),
202            tag_no_case("megv").map(|_| Suffix::Mega),
203            tag_no_case("kv").map(|_| Suffix::Kilo),
204            tag_no_case("mv").map(|_| Suffix::Milli),
205            tag_no_case("uv").map(|_| Suffix::Micro),
206            tag_no_case("nv").map(|_| Suffix::Nano),
207            tag_no_case("pv").map(|_| Suffix::Pico),
208            tag_no_case("g").map(|_| Suffix::Mega),
209            tag_no_case("meg").map(|_| Suffix::Mega),
210            tag_no_case("k").map(|_| Suffix::Kilo),
211            tag_no_case("m").map(|_| Suffix::Milli),
212            tag_no_case("u").map(|_| Suffix::Micro),
213            tag_no_case("n").map(|_| Suffix::Nano),
214            tag_no_case("p").map(|_| Suffix::Pico),
215            tag_no_case("v").map(|_| Suffix::None),
216        )))(input)?;
217    
218        Ok((
219            input,
220            Number {
221                value,
222                suffix: suffix.unwrap_or(Suffix::None),
223            }.into(),
224        ))
225    }
226    wrap_parser!(_voltage_number(input), input, "expect voltage number")
227}
228
229pub fn current_number(input: &str) -> NomResult<Current> {
230    pub fn _current_number(input: &str) -> NomResult<Current> {
231        let (input, value) = float(input)?;
232        let (input, suffix) = opt(alt((
233            tag_no_case("gA").map(|_| Suffix::Mega),
234            tag_no_case("megA").map(|_| Suffix::Mega),
235            tag_no_case("kA").map(|_| Suffix::Kilo),
236            tag_no_case("mA").map(|_| Suffix::Milli),
237            tag_no_case("uA").map(|_| Suffix::Micro),
238            tag_no_case("nA").map(|_| Suffix::Nano),
239            tag_no_case("pA").map(|_| Suffix::Pico),
240            tag_no_case("g").map(|_| Suffix::Mega),
241            tag_no_case("meg").map(|_| Suffix::Mega),
242            tag_no_case("k").map(|_| Suffix::Kilo),
243            tag_no_case("m").map(|_| Suffix::Milli),
244            tag_no_case("u").map(|_| Suffix::Micro),
245            tag_no_case("n").map(|_| Suffix::Nano),
246            tag_no_case("p").map(|_| Suffix::Pico),
247            tag_no_case("A").map(|_| Suffix::None),
248        )))(input)?;
249    
250        Ok((
251            input,
252            Number {
253                value,
254                suffix: suffix.unwrap_or(Suffix::None),
255            }.into(),
256        ))
257    }
258    wrap_parser!(_current_number(input), input, "expect current number")
259}
260
261pub fn resistance_number(input: &str) -> NomResult<Resistance> {
262    pub fn _resistance_number(input: &str) -> NomResult<Resistance> {
263        let (input, value) = float(input)?;
264        let (input, suffix) = opt(alt((
265            tag_no_case("gΩ").map(|_| Suffix::Mega),
266            tag_no_case("megΩ").map(|_| Suffix::Mega),
267            tag_no_case("kΩ").map(|_| Suffix::Kilo),
268            tag_no_case("mΩ").map(|_| Suffix::Milli),
269            tag_no_case("uΩ").map(|_| Suffix::Micro),
270            tag_no_case("nΩ").map(|_| Suffix::Nano),
271            tag_no_case("pΩ").map(|_| Suffix::Pico),
272            tag_no_case("g").map(|_| Suffix::Mega),
273            tag_no_case("meg").map(|_| Suffix::Mega),
274            tag_no_case("k").map(|_| Suffix::Kilo),
275            tag_no_case("m").map(|_| Suffix::Milli),
276            tag_no_case("u").map(|_| Suffix::Micro),
277            tag_no_case("n").map(|_| Suffix::Nano),
278            tag_no_case("p").map(|_| Suffix::Pico),
279            tag_no_case("Ω").map(|_| Suffix::None),
280        )))(input)?;
281    
282        Ok((
283            input,
284            Number {
285                value,
286                suffix: suffix.unwrap_or(Suffix::None),
287            }.into(),
288        ))
289    }
290    wrap_parser!(_resistance_number(input), input, "expect resistance number")
291}
292
293pub fn capacitance_number(input: &str) -> NomResult<Capacitance> {
294    pub fn _capacitance_number(input: &str) -> NomResult<Capacitance> {
295        let (input, value) = float(input)?;
296        let (input, suffix) = opt(alt((
297            tag_no_case("gF").map(|_| Suffix::Mega),
298            tag_no_case("megF").map(|_| Suffix::Mega),
299            tag_no_case("kF").map(|_| Suffix::Kilo),
300            tag_no_case("mF").map(|_| Suffix::Milli),
301            tag_no_case("uF").map(|_| Suffix::Micro),
302            tag_no_case("nF").map(|_| Suffix::Nano),
303            tag_no_case("pF").map(|_| Suffix::Pico),
304            tag_no_case("g").map(|_| Suffix::Mega),
305            tag_no_case("meg").map(|_| Suffix::Mega),
306            tag_no_case("k").map(|_| Suffix::Kilo),
307            tag_no_case("m").map(|_| Suffix::Milli),
308            tag_no_case("u").map(|_| Suffix::Micro),
309            tag_no_case("n").map(|_| Suffix::Nano),
310            tag_no_case("p").map(|_| Suffix::Pico),
311            tag_no_case("F").map(|_| Suffix::None),
312        )))(input)?;
313    
314        Ok((
315            input,
316            Number {
317                value,
318                suffix: suffix.unwrap_or(Suffix::None),
319            }.into(),
320        ))
321    }
322    wrap_parser!(_capacitance_number(input), input, "expect capacitance number")
323}
324
325pub fn inductance_number(input: &str) -> NomResult<Inductance> {
326    pub fn _inductance_number(input: &str) -> NomResult<Inductance> {
327        let (input, value) = float(input)?;
328        let (input, suffix) = opt(alt((
329            tag_no_case("gH").map(|_| Suffix::Mega),
330            tag_no_case("megH").map(|_| Suffix::Mega),
331            tag_no_case("kH").map(|_| Suffix::Kilo),
332            tag_no_case("mH").map(|_| Suffix::Milli),
333            tag_no_case("uH").map(|_| Suffix::Micro),
334            tag_no_case("nH").map(|_| Suffix::Nano),
335            tag_no_case("pH").map(|_| Suffix::Pico),
336            tag_no_case("g").map(|_| Suffix::Mega),
337            tag_no_case("meg").map(|_| Suffix::Mega),
338            tag_no_case("k").map(|_| Suffix::Kilo),
339            tag_no_case("m").map(|_| Suffix::Milli),
340            tag_no_case("u").map(|_| Suffix::Micro),
341            tag_no_case("n").map(|_| Suffix::Nano),
342            tag_no_case("p").map(|_| Suffix::Pico),
343            tag_no_case("H").map(|_| Suffix::Pico),
344        )))(input)?;
345    
346        Ok((
347            input,
348            Number {
349                value,
350                suffix: suffix.unwrap_or(Suffix::None),
351            }.into(),
352        ))
353    }
354    wrap_parser!(_inductance_number(input), input, "expect inductance number")
355}
356
357pub fn frequency_number(input: &str) -> NomResult<Frequency> {
358    let (input, n) = number(input)?;
359    Ok((input, n.into()))
360}
361
362pub fn angle_number(input: &str) -> NomResult<Angle> {
363    let (input, n) = number(input)?;
364    Ok((input, n.into()))
365}
366
367pub fn comment(input: &str) -> NomResult<&str> {
368    pub fn _comment(input: &str) -> NomResult<&str> {
369        map(
370        terminated(
371                preceded(
372                    alt((tag("*"), tag(";"))),
373                    preceded(space0, not_line_ending),
374                ),
375                alt((line_ending, nom::combinator::eof)),
376            ),
377            |text: &str| text.trim_end(),
378        )(input)
379    }
380    wrap_parser!(_comment(input), input, "comment")
381}
382
383#[allow(unused)]
384#[cfg(test)]
385mod tests {
386    use super::*;
387
388    #[test]
389    fn test_decimal() {
390        let res = decimal("012ds").unwrap();
391        assert_eq!(res.0, "ds");
392        assert_eq!(res.1, "012");
393    }
394
395    #[test]
396    fn test_float() {
397        let res = float("1.2323 hhh").unwrap();
398        assert_eq!(res.0, " hhh");
399        assert_eq!(res.1, 1.2323);
400    }
401
402    #[test]
403    fn test_unsigned_int() {
404        let res = unsigned_int("1231 hhh").unwrap();
405        assert_eq!(res.0, " hhh");
406        assert_eq!(res.1, 1231);
407    }
408
409    #[test]
410    fn test_tstring() {
411        let res = identifier("hello world!").unwrap();
412        assert_eq!(res.0, " world!");
413        assert_eq!(res.1, "hello");
414    }
415
416    #[test]
417    fn test_comment() {
418        let input = "* this is a comment\r\n.nextline";
419        let (rest, c) = comment(input).unwrap();
420        assert_eq!(c, "this is a comment");
421        assert_eq!(rest, ".nextline");
422    
423        let input = "; another comment without newline";
424        let (rest, c) = comment(input).unwrap();
425        assert_eq!(c, "another comment without newline");
426        assert_eq!(rest, "");
427    }
428}