Skip to content

Commit 199dc39

Browse files
authored
Merge pull request #616 from epage/path
fix(error)!: Remove nom from ConfigError
2 parents 35ba3bd + f25e6a2 commit 199dc39

File tree

5 files changed

+80
-87
lines changed

5 files changed

+80
-87
lines changed

Cargo.lock

Lines changed: 3 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ async = ["async-trait"]
122122

123123
[dependencies]
124124
serde = "1.0"
125-
nom = "7"
126125

127126
async-trait = { version = "0.1", optional = true }
128127
toml = { version = "0.8", optional = true }
@@ -134,6 +133,7 @@ json5_rs = { version = "0.4", optional = true, package = "json5" }
134133
indexmap = { version = "2.2", features = ["serde"], optional = true }
135134
convert_case = { version = "0.6", optional = true }
136135
pathdiff = "0.2"
136+
winnow = "0.6.20"
137137

138138
[dev-dependencies]
139139
serde_derive = "1.0"

src/error.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ impl fmt::Display for Unexpected {
3838

3939
/// Represents all possible errors that can occur when working with
4040
/// configuration.
41+
#[non_exhaustive]
4142
pub enum ConfigError {
4243
/// Configuration is frozen and no further mutations can be made.
4344
Frozen,
@@ -46,7 +47,7 @@ pub enum ConfigError {
4647
NotFound(String),
4748

4849
/// Configuration path could not be parsed.
49-
PathParse(nom::error::ErrorKind),
50+
PathParse { cause: Box<dyn Error + Send + Sync> },
5051

5152
/// Configuration could not be parsed from file.
5253
FileParse {
@@ -187,7 +188,7 @@ impl fmt::Display for ConfigError {
187188
match *self {
188189
ConfigError::Frozen => write!(f, "configuration is frozen"),
189190

190-
ConfigError::PathParse(ref kind) => write!(f, "{}", kind.description()),
191+
ConfigError::PathParse { ref cause } => write!(f, "{cause}"),
191192

192193
ConfigError::Message(ref s) => write!(f, "{s}"),
193194

src/path/mod.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,29 @@ impl FromStr for Expression {
1717
type Err = ConfigError;
1818

1919
fn from_str(s: &str) -> Result<Self> {
20-
parser::from_str(s).map_err(ConfigError::PathParse)
20+
parser::from_str(s).map_err(|e| ConfigError::PathParse {
21+
cause: Box::new(ParseError::new(e)),
22+
})
2123
}
2224
}
2325

26+
#[derive(Debug)]
27+
struct ParseError(String);
28+
29+
impl ParseError {
30+
fn new(inner: winnow::error::ContextError) -> Self {
31+
Self(inner.to_string())
32+
}
33+
}
34+
35+
impl std::fmt::Display for ParseError {
36+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37+
self.0.fmt(f)
38+
}
39+
}
40+
41+
impl std::error::Error for ParseError {}
42+
2443
fn sindex_to_uindex(index: isize, len: usize) -> usize {
2544
if index >= 0 {
2645
index as usize

src/path/parser.rs

Lines changed: 53 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,72 @@
11
use std::str::FromStr;
22

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;
1215

1316
use crate::path::Expression;
1417

15-
fn raw_ident(i: &str) -> IResult<&str, String> {
16-
map(
17-
is_a(
18-
"abcdefghijklmnopqrstuvwxyz \
19-
ABCDEFGHIJKLMNOPQRSTUVWXYZ \
20-
0123456789 \
21-
_-",
22-
),
23-
ToString::to_string,
24-
)(i)
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())
2521
}
2622

27-
fn integer(i: &str) -> IResult<&str, isize> {
28-
map_res(
29-
delimited(space0, recognize(pair(opt(tag("-")), digit1)), space0),
30-
FromStr::from_str,
31-
)(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)
3236
}
3337

34-
fn ident(i: &str) -> IResult<&str, Expression> {
35-
map(raw_ident, Expression::Identifier)(i)
38+
fn ident(i: &mut &str) -> PResult<Expression> {
39+
raw_ident.map(Expression::Identifier).parse_next(i)
3640
}
3741

38-
fn postfix<'a>(expr: Expression) -> impl FnMut(&'a str) -> IResult<&'a str, Expression> {
39-
let e2 = expr.clone();
40-
let child = map(preceded(tag("."), raw_ident), move |id| {
41-
Expression::Child(Box::new(expr.clone()), id)
42-
});
43-
44-
let subscript = map(delimited(char('['), integer, char(']')), move |num| {
45-
Expression::Subscript(Box::new(e2.clone()), num)
46-
});
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)
49+
}
4750

48-
alt((child, subscript))
51+
enum Child {
52+
Key(String),
53+
Index(isize),
4954
}
5055

51-
pub(crate) fn from_str(input: &str) -> Result<Expression, ErrorKind> {
52-
match ident(input) {
53-
Ok((mut rem, mut expr)) => {
54-
while !rem.is_empty() {
55-
match postfix(expr)(rem) {
56-
Ok((rem_, expr_)) => {
57-
rem = rem_;
58-
expr = expr_;
59-
}
60-
61-
// Forward Incomplete and Error
62-
result => {
63-
return result.map(|(_, o)| o).map_err(to_error_kind);
64-
}
65-
}
66-
}
67-
68-
Ok(expr)
69-
}
70-
71-
// Forward Incomplete and Error
72-
result => result.map(|(_, o)| o).map_err(to_error_kind),
73-
}
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)
7460
}
7561

76-
pub(crate) 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)
8170
}
8271

8372
#[cfg(test)]

0 commit comments

Comments
 (0)