From 217eb6240f619e6a81fa50487a6e72bd619991b6 Mon Sep 17 00:00:00 2001 From: Joakim Soderlund Date: Wed, 20 Mar 2024 17:52:40 +0100 Subject: [PATCH] Upgrade dependency Nom to v7 --- Cargo.lock | 82 +++++------------ query/Cargo.toml | 6 +- query/src/parser.rs | 220 +++++++++++++++++++++++--------------------- 3 files changed, 145 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b76732e..5a1d395 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,23 +32,11 @@ dependencies = [ "libc", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "bitflags" @@ -247,9 +235,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -266,19 +254,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags 1.3.2", - "cfg-if", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.153" @@ -297,6 +272,12 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -312,7 +293,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -320,13 +301,12 @@ dependencies = [ [[package]] name = "nom" -version = "5.1.3" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "lexical-core", "memchr", - "version_check", + "minimal-lexical", ] [[package]] @@ -364,9 +344,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -384,9 +364,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -407,9 +387,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rustyline" @@ -417,7 +397,7 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" dependencies = [ - "bitflags 2.5.0", + "bitflags", "cfg-if", "clipboard-win", "libc", @@ -464,26 +444,20 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", "serde", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "syn" -version = "2.0.53" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -514,12 +488,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "wasm-bindgen" version = "0.2.92" diff --git a/query/Cargo.toml b/query/Cargo.toml index 95e0b7b..0ccaa8a 100644 --- a/query/Cargo.toml +++ b/query/Cargo.toml @@ -13,11 +13,11 @@ version = "*" [dependencies.chrono-english] version = "*" +[dependencies.nom] +version = "7" + [dependencies.rayon] version = "*" [dependencies.regex] version = "*" - -[dependencies.nom] -version = "5" diff --git a/query/src/parser.rs b/query/src/parser.rs index 27ef887..dac5290 100644 --- a/query/src/parser.rs +++ b/query/src/parser.rs @@ -1,11 +1,28 @@ //! Query parser. -use chrono::prelude::*; +use chrono::DateTime; +use chrono::Utc; -use nom::character::complete::*; +use nom::branch::alt; +use nom::bytes::complete::escaped; +use nom::bytes::complete::tag; +use nom::character::complete::char; +use nom::character::complete::none_of; +use nom::character::complete::one_of; +use nom::character::complete::space0; +use nom::combinator::eof; +use nom::combinator::map; +use nom::combinator::value; +use nom::error::Error as NomError; use nom::error::ErrorKind as NomErrorKind; -use nom::sequence::*; -use nom::*; +use nom::multi::separated_list1; +use nom::sequence::delimited; +use nom::sequence::preceded; +use nom::sequence::terminated; +use nom::sequence::tuple; +use nom::Err as NomErr; +use nom::Finish; +use nom::IResult; use fimfareader::archive::Story; use fimfareader::error::*; @@ -20,6 +37,7 @@ pub enum Source { DtuFn(Box &Option> + Sync>), } +#[derive(Clone)] pub enum Operator { Exact, Fuzzy, @@ -28,67 +46,79 @@ pub enum Operator { } macro_rules! sfn { - ($func:expr) => { - |_| Source::StrFn(Box::new($func)) + ($tag:expr => $func:expr) => { + preceded(tag($tag), |input| { + Ok((input, Source::StrFn(Box::new($func)))) + }) }; } macro_rules! ifn { - ($func:expr) => { - |_| Source::IntFn(Box::new($func)) - }; + ($tag:expr => $func:expr) => {{ + preceded(tag($tag), |input| { + Ok((input, Source::IntFn(Box::new($func)))) + }) + }}; } macro_rules! dfn { - ($func:expr) => { - |_| Source::DtuFn(Box::new($func)) + ($tag:expr => $func:expr) => { + preceded(tag($tag), |input| { + Ok((input, Source::DtuFn(Box::new($func)))) + }) }; } -named!(source<&str, Source>, preceded!(space0, alt!( - tag!("id") => { ifn!(|s| s.id) } | +fn source(input: &str) -> IResult<&str, Source> { + let story = alt(( + ifn!("id" => |s| s.id), + sfn!("story" => |s| &s.title), + sfn!("title" => |s| &s.title), + sfn!("description" => |s| &s.description_html), + sfn!("short description" => |s| &s.short_description), + sfn!("url" => |s| &s.url), + dfn!("modified" => |s| &s.date_modified), + dfn!("published" => |s| &s.date_published), + dfn!("updated" => |s| &s.date_updated), + ifn!("chapters" => |s| i64::from(s.num_chapters)), + ifn!("comments" => |s| i64::from(s.num_comments)), + ifn!("dislikes" => |s| i64::from(s.num_dislikes)), + ifn!("likes" => |s| i64::from(s.num_likes)), + ifn!("total views" => |s| i64::from(s.total_num_views)), + ifn!("views" => |s| i64::from(s.num_views)), + ifn!("words" => |s| i64::from(s.num_words)), + )); - tag!("story") => { sfn!(|s| &s.title) } | - tag!("title") => { sfn!(|s| &s.title) } | + let author = alt(( + sfn!("author" => |s| &s.author.name), + sfn!("author name" => |s| &s.author.name), + ifn!("author id" => |s| s.author.id), + dfn!("author joined" => |s| &s.author.date_joined), + )); - tag!("description") => { sfn!(|s| &s.description_html) } | - tag!("short description") => { sfn!(|s| &s.short_description) } | - tag!("url") => { sfn!(|s| &s.url) } | + let archive = alt(( + sfn!("path" => |s| &s.archive.path), + sfn!("archive" => |s| &s.archive.path), + sfn!("archive path" => |s| &s.archive.path), + dfn!("entry checked" => |s| &s.archive.date_checked), + dfn!("entry created" => |s| &s.archive.date_created), + dfn!("entry fetched" => |s| &s.archive.date_fetched), + dfn!("entry updated" => |s| &s.archive.date_updated), + )); - tag!("modified") => { dfn!(|s| &s.date_modified) } | - tag!("published") => { dfn!(|s| &s.date_published) } | - tag!("updated") => { dfn!(|s| &s.date_updated) } | + preceded(space0, alt((story, author, archive)))(input) +} - tag!("chapters") => { ifn!(|s| i64::from(s.num_chapters)) } | - tag!("comments") => { ifn!(|s| i64::from(s.num_comments)) } | - tag!("dislikes") => { ifn!(|s| i64::from(s.num_dislikes)) } | - tag!("likes") => { ifn!(|s| i64::from(s.num_likes)) } | - tag!("total views") => { ifn!(|s| i64::from(s.total_num_views)) } | - tag!("views") => { ifn!(|s| i64::from(s.num_views)) } | - tag!("words") => { ifn!(|s| i64::from(s.num_words)) } | +fn operator(input: &str) -> IResult<&str, Operator> { + let operator = alt(( + value(Operator::Exact, char('=')), + value(Operator::Fuzzy, char(':')), + value(Operator::LessThan, char('<')), + value(Operator::MoreThan, char('>')), + )); - tag!("author") => { sfn!(|s| &s.author.name) } | - tag!("author name") => { sfn!(|s| &s.author.name) } | - - tag!("author id") => { ifn!(|s| s.author.id) } | - tag!("author joined") => { dfn!(|s| &s.author.date_joined) } | - - tag!("path") => { sfn!(|s| &s.archive.path) } | - tag!("archive") => { sfn!(|s| &s.archive.path) } | - tag!("archive path") => { sfn!(|s| &s.archive.path) } | - - tag!("entry checked") => { dfn!(|s| &s.archive.date_checked) } | - tag!("entry created") => { dfn!(|s| &s.archive.date_created) } | - tag!("entry fetched") => { dfn!(|s| &s.archive.date_fetched) } | - tag!("entry updated") => { dfn!(|s| &s.archive.date_updated) } -))); - -named!(operator<&str, Operator>, preceded!(space0, alt!( - tag!("=") => { |_| Operator::Exact } | - tag!(":") => { |_| Operator::Fuzzy } | - tag!("<") => { |_| Operator::LessThan } | - tag!(">") => { |_| Operator::MoreThan } -))); + preceded(space0, operator)(input) +} fn unescape(input: &str) -> String { input @@ -98,47 +128,50 @@ fn unescape(input: &str) -> String { .replace("\\\\", "\\") } -named!(value<&str, &str>, - escaped!(none_of!("),|\\"), '\\', one_of!("),|\\")) -); +fn evalue(input: &str) -> IResult<&str, &str> { + escaped(none_of("),|\\"), '\\', one_of("),|\\"))(input) +} -named!(target<&str, String>, preceded!(space0, - map!(value, |value| unescape(value.trim())) -)); +fn target(input: &str) -> IResult<&str, String> { + preceded(space0, map(evalue, |value| unescape(value.trim())))(input) +} fn item(input: &str) -> IResult<&str, Filter> { let result = tuple((source, operator, target))(input)?; let (left, (src, op, value)) = result; let Ok(filter) = optimize(src, op, &value) else { - return Err(Err::Failure((input, NomErrorKind::Permutation))); + let error = NomError::new(input, NomErrorKind::Permutation); + return Err(NomErr::Failure(error)); }; Ok((left, filter)) } -named!(parens<&str, Filter>, alt!( - delimited!( - preceded!(space0, tag!("(")), - preceded!(space0, call!(ofunc)), - preceded!(space0, tag!(")")) - ) | - call!(item) -)); +fn parens(input: &str) -> IResult<&str, Filter> { + let group = delimited( + preceded(space0, char('(')), + preceded(space0, ofunc), + preceded(space0, char(')')), + ); -fn negate(input: &str) -> IResult<&str, Filter> { - let (left, filter) = parens(input)?; - - Ok((left, Box::new(move |s| !filter(s)))) + alt((group, item))(input) } -named!(nlist<&str, Filter>, preceded!(space0, alt!( - preceded!(char('!'), call!(negate)) | call!(parens) -))); +fn negate(input: &str) -> IResult<&str, Filter> { + let (input, filter) = parens(input)?; + Ok((input, Box::new(move |s| !filter(s)))) +} -named!(alist<&str, Vec>, separated_nonempty_list!( - preceded!(space0, char(',')), call!(nlist) -)); +fn nlist(input: &str) -> IResult<&str, Filter> { + let negated = preceded(char('!'), negate); + preceded(space0, alt((negated, parens)))(input) +} + +fn alist(input: &str) -> IResult<&str, Vec> { + let sep = preceded(space0, char(',')); + separated_list1(sep, nlist)(input) +} fn afunc(input: &str) -> IResult<&str, Filter> { let (left, mut filters) = alist(input)?; @@ -160,9 +193,10 @@ fn afunc(input: &str) -> IResult<&str, Filter> { Ok((left, filter)) } -named!(olist<&str, Vec>, separated_nonempty_list!( - preceded!(space0, char('|')), call!(afunc) -)); +fn olist(input: &str) -> IResult<&str, Vec> { + let sep = preceded(space0, char('|')); + separated_list1(sep, afunc)(input) +} fn ofunc(input: &str) -> IResult<&str, Filter> { let (left, mut filters) = olist(input)?; @@ -184,33 +218,13 @@ fn ofunc(input: &str) -> IResult<&str, Filter> { Ok((left, filter)) } -fn format_error(query: &str, input: &str, error: NomErrorKind) -> String { - let description = error.description().to_lowercase(); - let position = query.len() - input.len(); - - format!("Invalid {} at {}", description, position) -} - -fn translate_error(query: &str, error: Err<(&str, NomErrorKind)>) -> Error { - let message = match error { - Err::Error((i, e)) => format_error(query, i, e), - Err::Failure((i, e)) => format_error(query, i, e), - Err::Incomplete(_) => String::from("Incomplete input"), - }; - - Error::query(message) -} - -fn translate_incomplete(query: &str, input: &str) -> Error { - let position = query.len() - input.len(); - - Error::query(format!("Incomplete input at {}", position)) +fn complete(input: &str) -> IResult<&str, Filter> { + terminated(ofunc, eof)(input.trim()) } pub fn parse(query: &str) -> Result { - match ofunc(query.trim()) { - Ok(("", filter)) => Ok(filter), - Ok((i, _)) => Err(translate_incomplete(query, i)), - Err(e) => Err(translate_error(query, e)), + match complete(query).finish() { + Ok((_, filter)) => Ok(filter), + Err(e) => Err(Error::query(e)), } }