diff --git a/Cargo.toml b/Cargo.toml index 8e59ac1..22fd23d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,6 @@ keywords = ["kdl", "document", "serialization", "config"] edition = "2018" [dependencies] -nom = "6.0.1" +nom = { version = "6.0.1", default-features = false } phf = { version = "0.8.0", features = ["macros"] } thiserror = "1.0.22" diff --git a/src/lib.rs b/src/lib.rs index 584717e..0f31bfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,7 @@ pub use crate::node::{KdlNode, KdlValue}; mod error; mod node; +mod nom_compat; mod parser; /// Parse a KDL document from a string into a list of [`KdlNode`]s. diff --git a/src/nom_compat.rs b/src/nom_compat.rs new file mode 100644 index 0000000..784a9d7 --- /dev/null +++ b/src/nom_compat.rs @@ -0,0 +1,100 @@ +use nom::error::{ErrorKind, ParseError}; +use nom::{Err, IResult, Parser}; + +pub fn many0(mut f: F) -> impl FnMut(I) -> IResult, E> +where + I: Clone + PartialEq, + F: Parser, + E: ParseError, +{ + move |mut i: I| { + let mut acc = Vec::with_capacity(4); + loop { + match f.parse(i.clone()) { + Err(Err::Error(_)) => return Ok((i, acc)), + Err(e) => return Err(e), + Ok((i1, o)) => { + if i1 == i { + return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many0))); + } + + i = i1; + acc.push(o); + } + } + } + } +} + +pub fn many1(mut f: F) -> impl FnMut(I) -> IResult, E> +where + I: Clone + PartialEq, + F: Parser, + E: ParseError, +{ + move |mut i: I| match f.parse(i.clone()) { + Err(Err::Error(err)) => Err(Err::Error(E::append(i, ErrorKind::Many1, err))), + Err(e) => Err(e), + Ok((i1, o)) => { + let mut acc = Vec::with_capacity(4); + acc.push(o); + i = i1; + + loop { + match f.parse(i.clone()) { + Err(Err::Error(_)) => return Ok((i, acc)), + Err(e) => return Err(e), + Ok((i1, o)) => { + if i1 == i { + return Err(Err::Error(E::from_error_kind(i, ErrorKind::Many1))); + } + + i = i1; + acc.push(o); + } + } + } + } + } +} + +pub fn many_till( + mut f: F, + mut g: G, +) -> impl FnMut(I) -> IResult, P), E> +where + I: Clone + PartialEq, + F: Parser, + G: Parser, + E: ParseError, +{ + move |mut i: I| { + let mut res = Vec::new(); + loop { + match g.parse(i.clone()) { + Ok((i1, o)) => return Ok((i1, (res, o))), + Err(Err::Error(_)) => { + match f.parse(i.clone()) { + Err(Err::Error(err)) => { + return Err(Err::Error(E::append(i, ErrorKind::ManyTill, err))) + } + Err(e) => return Err(e), + Ok((i1, o)) => { + // loop trip must always consume (otherwise infinite loops) + if i1 == i { + return Err(Err::Error(E::from_error_kind( + i1, + ErrorKind::ManyTill, + ))); + } + + res.push(o); + i = i1; + } + } + } + Err(e) => return Err(e), + } + } + } +} diff --git a/src/parser.rs b/src/parser.rs index 79d1269..bd9b922 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,12 +1,13 @@ use std::{collections::HashMap, iter::from_fn}; +use crate::nom_compat::{many0, many1, many_till}; use nom::branch::alt; use nom::bytes::complete::{tag, take_until, take_while_m_n}; use nom::character::complete::{anychar, char, none_of, one_of}; use nom::combinator::{ all_consuming, eof, iterator, map, map_opt, map_res, not, opt, recognize, value, }; -use nom::multi::{fold_many0, many0, many1, many_till}; +use nom::multi::fold_many0; use nom::sequence::{delimited, pair, preceded, terminated, tuple}; use nom::Finish; use nom::IResult;