Skip to content

Commit

Permalink
Merge pull request #616 from epage/path
Browse files Browse the repository at this point in the history
fix(error)!: Remove nom from ConfigError
  • Loading branch information
epage authored Dec 17, 2024
2 parents 35ba3bd + f25e6a2 commit 199dc39
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 87 deletions.
22 changes: 3 additions & 19 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ async = ["async-trait"]

[dependencies]
serde = "1.0"
nom = "7"

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

[dev-dependencies]
serde_derive = "1.0"
Expand Down
5 changes: 3 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ impl fmt::Display for Unexpected {

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

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

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

ConfigError::PathParse(ref kind) => write!(f, "{}", kind.description()),
ConfigError::PathParse { ref cause } => write!(f, "{cause}"),

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

Expand Down
21 changes: 20 additions & 1 deletion src/path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,29 @@ impl FromStr for Expression {
type Err = ConfigError;

fn from_str(s: &str) -> Result<Self> {
parser::from_str(s).map_err(ConfigError::PathParse)
parser::from_str(s).map_err(|e| ConfigError::PathParse {
cause: Box::new(ParseError::new(e)),
})
}
}

#[derive(Debug)]
struct ParseError(String);

impl ParseError {
fn new(inner: winnow::error::ContextError) -> Self {
Self(inner.to_string())
}
}

impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}

impl std::error::Error for ParseError {}

fn sindex_to_uindex(index: isize, len: usize) -> usize {
if index >= 0 {
index as usize
Expand Down
117 changes: 53 additions & 64 deletions src/path/parser.rs
Original file line number Diff line number Diff line change
@@ -1,83 +1,72 @@
use std::str::FromStr;

use nom::{
branch::alt,
bytes::complete::{is_a, tag},
character::complete::{char, digit1, space0},
combinator::{map, map_res, opt, recognize},
error::ErrorKind,
sequence::{delimited, pair, preceded},
Err, IResult,
};
use winnow::ascii::digit1;
use winnow::ascii::space0;
use winnow::combinator::dispatch;
use winnow::combinator::eof;
use winnow::combinator::fail;
use winnow::combinator::opt;
use winnow::combinator::repeat;
use winnow::combinator::seq;
use winnow::error::ContextError;
use winnow::prelude::*;
use winnow::token::any;
use winnow::token::take_while;

use crate::path::Expression;

fn raw_ident(i: &str) -> IResult<&str, String> {
map(
is_a(
"abcdefghijklmnopqrstuvwxyz \
ABCDEFGHIJKLMNOPQRSTUVWXYZ \
0123456789 \
_-",
),
ToString::to_string,
)(i)
pub(crate) fn from_str(mut input: &str) -> Result<Expression, ContextError> {
let input = &mut input;
path(input).map_err(|e| e.into_inner().unwrap())
}

fn integer(i: &str) -> IResult<&str, isize> {
map_res(
delimited(space0, recognize(pair(opt(tag("-")), digit1)), space0),
FromStr::from_str,
)(i)
fn path(i: &mut &str) -> PResult<Expression> {
let root = ident.parse_next(i)?;
let expr = repeat(0.., postfix)
.fold(
|| root.clone(),
|prev, cur| match cur {
Child::Key(k) => Expression::Child(Box::new(prev), k),
Child::Index(k) => Expression::Subscript(Box::new(prev), k),
},
)
.parse_next(i)?;
eof.parse_next(i)?;
Ok(expr)
}

fn ident(i: &str) -> IResult<&str, Expression> {
map(raw_ident, Expression::Identifier)(i)
fn ident(i: &mut &str) -> PResult<Expression> {
raw_ident.map(Expression::Identifier).parse_next(i)
}

fn postfix<'a>(expr: Expression) -> impl FnMut(&'a str) -> IResult<&'a str, Expression> {
let e2 = expr.clone();
let child = map(preceded(tag("."), raw_ident), move |id| {
Expression::Child(Box::new(expr.clone()), id)
});

let subscript = map(delimited(char('['), integer, char(']')), move |num| {
Expression::Subscript(Box::new(e2.clone()), num)
});
fn postfix(i: &mut &str) -> PResult<Child> {
dispatch! {any;
'[' => seq!(integer.map(Child::Index), _: ']').map(|(i,)| i),
'.' => raw_ident.map(Child::Key),
_ => fail,
}
.parse_next(i)
}

alt((child, subscript))
enum Child {
Key(String),
Index(isize),
}

pub(crate) fn from_str(input: &str) -> Result<Expression, ErrorKind> {
match ident(input) {
Ok((mut rem, mut expr)) => {
while !rem.is_empty() {
match postfix(expr)(rem) {
Ok((rem_, expr_)) => {
rem = rem_;
expr = expr_;
}

// Forward Incomplete and Error
result => {
return result.map(|(_, o)| o).map_err(to_error_kind);
}
}
}

Ok(expr)
}

// Forward Incomplete and Error
result => result.map(|(_, o)| o).map_err(to_error_kind),
}
fn raw_ident(i: &mut &str) -> PResult<String> {
take_while(1.., ('a'..='z', 'A'..='Z', '0'..='9', '_', '-'))
.map(ToString::to_string)
.parse_next(i)
}

pub(crate) fn to_error_kind(e: Err<nom::error::Error<&str>>) -> ErrorKind {
match e {
Err::Incomplete(_) => ErrorKind::Complete,
Err::Failure(e) | Err::Error(e) => e.code,
}
fn integer(i: &mut &str) -> PResult<isize> {
seq!(
_: space0,
(opt('-'), digit1).take().try_map(FromStr::from_str),
_: space0
)
.map(|(i,)| i)
.parse_next(i)
}

#[cfg(test)]
Expand Down

0 comments on commit 199dc39

Please sign in to comment.