|
1 | 1 | use std::str::FromStr;
|
2 | 2 |
|
3 |
| -use nom::{ |
4 |
| - branch::alt, |
5 |
| - bytes::complete::{is_a, tag}, |
6 |
| - character::complete::{char, digit1, space0}, |
7 |
| - combinator::{map, map_res, opt, recognize}, |
8 |
| - error::ErrorKind, |
9 |
| - sequence::{delimited, pair, preceded}, |
10 |
| - Err, IResult, |
11 |
| -}; |
| 3 | +use winnow::ascii::digit1; |
| 4 | +use winnow::ascii::space0; |
| 5 | +use winnow::combinator::dispatch; |
| 6 | +use winnow::combinator::eof; |
| 7 | +use winnow::combinator::fail; |
| 8 | +use winnow::combinator::opt; |
| 9 | +use winnow::combinator::repeat; |
| 10 | +use winnow::combinator::seq; |
| 11 | +use winnow::error::ContextError; |
| 12 | +use winnow::prelude::*; |
| 13 | +use winnow::token::any; |
| 14 | +use winnow::token::take_while; |
12 | 15 |
|
13 | 16 | use crate::path::Expression;
|
14 | 17 |
|
15 |
| -pub(crate) fn from_str(input: &str) -> Result<Expression, ErrorKind> { |
16 |
| - match ident(input) { |
17 |
| - Ok((mut rem, mut expr)) => { |
18 |
| - while !rem.is_empty() { |
19 |
| - match postfix(expr)(rem) { |
20 |
| - Ok((rem_, expr_)) => { |
21 |
| - rem = rem_; |
22 |
| - expr = expr_; |
23 |
| - } |
24 |
| - |
25 |
| - // Forward Incomplete and Error |
26 |
| - result => { |
27 |
| - return result.map(|(_, o)| o).map_err(to_error_kind); |
28 |
| - } |
29 |
| - } |
30 |
| - } |
31 |
| - |
32 |
| - Ok(expr) |
33 |
| - } |
34 |
| - |
35 |
| - // Forward Incomplete and Error |
36 |
| - result => result.map(|(_, o)| o).map_err(to_error_kind), |
37 |
| - } |
| 18 | +pub(crate) fn from_str(mut input: &str) -> Result<Expression, ContextError> { |
| 19 | + let input = &mut input; |
| 20 | + path(input).map_err(|e| e.into_inner().unwrap()) |
38 | 21 | }
|
39 | 22 |
|
40 |
| -fn ident(i: &str) -> IResult<&str, Expression> { |
41 |
| - map(raw_ident, Expression::Identifier)(i) |
| 23 | +fn path(i: &mut &str) -> PResult<Expression> { |
| 24 | + let root = ident.parse_next(i)?; |
| 25 | + let expr = repeat(0.., postfix) |
| 26 | + .fold( |
| 27 | + || root.clone(), |
| 28 | + |prev, cur| match cur { |
| 29 | + Child::Key(k) => Expression::Child(Box::new(prev), k), |
| 30 | + Child::Index(k) => Expression::Subscript(Box::new(prev), k), |
| 31 | + }, |
| 32 | + ) |
| 33 | + .parse_next(i)?; |
| 34 | + eof.parse_next(i)?; |
| 35 | + Ok(expr) |
42 | 36 | }
|
43 | 37 |
|
44 |
| -fn postfix<'a>(expr: Expression) -> impl FnMut(&'a str) -> IResult<&'a str, Expression> { |
45 |
| - let e2 = expr.clone(); |
46 |
| - let child = map(preceded(tag("."), raw_ident), move |id| { |
47 |
| - Expression::Child(Box::new(expr.clone()), id) |
48 |
| - }); |
49 |
| - |
50 |
| - let subscript = map(delimited(char('['), integer, char(']')), move |num| { |
51 |
| - Expression::Subscript(Box::new(e2.clone()), num) |
52 |
| - }); |
| 38 | +fn ident(i: &mut &str) -> PResult<Expression> { |
| 39 | + raw_ident.map(Expression::Identifier).parse_next(i) |
| 40 | +} |
53 | 41 |
|
54 |
| - alt((child, subscript)) |
| 42 | +fn postfix(i: &mut &str) -> PResult<Child> { |
| 43 | + dispatch! {any; |
| 44 | + '[' => seq!(integer.map(Child::Index), _: ']').map(|(i,)| i), |
| 45 | + '.' => raw_ident.map(Child::Key), |
| 46 | + _ => fail, |
| 47 | + } |
| 48 | + .parse_next(i) |
55 | 49 | }
|
56 | 50 |
|
57 |
| -fn raw_ident(i: &str) -> IResult<&str, String> { |
58 |
| - map( |
59 |
| - is_a( |
60 |
| - "abcdefghijklmnopqrstuvwxyz \ |
61 |
| - ABCDEFGHIJKLMNOPQRSTUVWXYZ \ |
62 |
| - 0123456789 \ |
63 |
| - _-", |
64 |
| - ), |
65 |
| - ToString::to_string, |
66 |
| - )(i) |
| 51 | +enum Child { |
| 52 | + Key(String), |
| 53 | + Index(isize), |
67 | 54 | }
|
68 | 55 |
|
69 |
| -fn integer(i: &str) -> IResult<&str, isize> { |
70 |
| - map_res( |
71 |
| - delimited(space0, recognize(pair(opt(tag("-")), digit1)), space0), |
72 |
| - FromStr::from_str, |
73 |
| - )(i) |
| 56 | +fn raw_ident(i: &mut &str) -> PResult<String> { |
| 57 | + take_while(1.., ('a'..='z', 'A'..='Z', '0'..='9', '_', '-')) |
| 58 | + .map(ToString::to_string) |
| 59 | + .parse_next(i) |
74 | 60 | }
|
75 | 61 |
|
76 |
| -fn to_error_kind(e: Err<nom::error::Error<&str>>) -> ErrorKind { |
77 |
| - match e { |
78 |
| - Err::Incomplete(_) => ErrorKind::Complete, |
79 |
| - Err::Failure(e) | Err::Error(e) => e.code, |
80 |
| - } |
| 62 | +fn integer(i: &mut &str) -> PResult<isize> { |
| 63 | + seq!( |
| 64 | + _: space0, |
| 65 | + (opt('-'), digit1).take().try_map(FromStr::from_str), |
| 66 | + _: space0 |
| 67 | + ) |
| 68 | + .map(|(i,)| i) |
| 69 | + .parse_next(i) |
81 | 70 | }
|
82 | 71 |
|
83 | 72 | #[cfg(test)]
|
|
0 commit comments