diff --git a/Cargo.lock b/Cargo.lock index e13b23420..f4425ed80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4131,6 +4131,24 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nom-language" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2de2bc5b451bfedaef92c90b8939a8fff5770bdcc1fafd6239d086aab8fa6b29" +dependencies = [ + "nom 8.0.0", +] + [[package]] name = "notify" version = "6.1.1" @@ -4621,7 +4639,8 @@ dependencies = [ "ignore", "lockfile_generator", "log", - "nom 7.1.3", + "nom 8.0.0", + "nom-language", "phylum_types", "purl", "quick-xml", diff --git a/lockfile/Cargo.toml b/lockfile/Cargo.toml index 39ddc7add..c295ab323 100644 --- a/lockfile/Cargo.toml +++ b/lockfile/Cargo.toml @@ -15,7 +15,8 @@ anyhow = "1.0.44" ignore = "0.4.20" lockfile_generator = { path = "../lockfile_generator", optional = true } log = "0.4.6" -nom = "7.1.1" +nom = "8.0.0" +nom-language = "0.1.0" phylum_types = { git = "https://github.com/phylum-dev/phylum-types", branch = "development" } purl = "0.1.1" quick-xml = { version = "0.37.1", features = [ diff --git a/lockfile/src/golang.rs b/lockfile/src/golang.rs index a68f5e8fe..8410682b1 100644 --- a/lockfile/src/golang.rs +++ b/lockfile/src/golang.rs @@ -6,8 +6,8 @@ use anyhow::{anyhow, Context}; use lockfile_generator::go::Go as GoGenerator; #[cfg(feature = "generator")] use lockfile_generator::Generator; -use nom::error::convert_error; use nom::Finish; +use nom_language::error::convert_error; use crate::parsers::{go_mod, go_sum}; use crate::{Package, Parse}; diff --git a/lockfile/src/java.rs b/lockfile/src/java.rs index 4f5a9fa0a..f812dddf3 100644 --- a/lockfile/src/java.rs +++ b/lockfile/src/java.rs @@ -8,8 +8,8 @@ use lockfile_generator::gradle::Gradle as GradleGenerator; use lockfile_generator::maven::Maven as MavenGenerator; #[cfg(feature = "generator")] use lockfile_generator::Generator; -use nom::error::convert_error; use nom::Finish; +use nom_language::error::convert_error; use phylum_types::ecosystems::maven::{Dependency, Plugin, Project}; use phylum_types::types::package::PackageType; use serde::Deserialize; diff --git a/lockfile/src/javascript.rs b/lockfile/src/javascript.rs index 2be845f92..3d69d9219 100644 --- a/lockfile/src/javascript.rs +++ b/lockfile/src/javascript.rs @@ -13,8 +13,8 @@ use lockfile_generator::yarn::Yarn as YarnGenerator; #[cfg(feature = "generator")] use lockfile_generator::Generator; use log::debug; -use nom::error::convert_error; use nom::Finish; +use nom_language::error::convert_error; use phylum_types::types::package::PackageType; use serde::Deserialize; use serde_json::Value as JsonValue; diff --git a/lockfile/src/parsers/gem.rs b/lockfile/src/parsers/gem.rs index dd7305111..f1b7d5993 100644 --- a/lockfile/src/parsers/gem.rs +++ b/lockfile/src/parsers/gem.rs @@ -2,10 +2,10 @@ use nom::branch::alt; use nom::bytes::complete::{tag, take_until}; use nom::character::complete::{line_ending, not_line_ending, satisfy, space0}; use nom::combinator::{opt, recognize}; -use nom::error::{VerboseError, VerboseErrorKind}; use nom::multi::{many1, many_till}; -use nom::sequence::{delimited, tuple}; -use nom::Err as NomErr; +use nom::sequence::delimited; +use nom::{Err as NomErr, Parser}; +use nom_language::error::{VerboseError, VerboseErrorKind}; use phylum_types::types::package::PackageType; use crate::parsers::{take_till_blank_line, IResult}; @@ -36,7 +36,8 @@ impl<'a> Section<'a> { let (new_input, consumed) = recognize(many_till( take_till_line_end, alt((tag("GEM"), tag("GIT"), tag("PATH"), tag("BUNDLED WITH"))), - ))(input)?; + )) + .parse(input)?; // Check for type of section head. let section_type = if consumed.ends_with("GEM") { @@ -193,10 +194,8 @@ fn revision(input: &str) -> IResult<&str, &str> { } fn specs(input: &str) -> IResult<&str, &str> { - recognize(many_till( - take_till_line_end, - recognize(tuple((space0, tag("specs:"), opt(line_ending)))), - ))(input) + recognize(many_till(take_till_line_end, recognize((space0, tag("specs:"), opt(line_ending))))) + .parse(input) } fn package(input: &str) -> Result, NomErr>> { @@ -219,8 +218,8 @@ fn package(input: &str) -> Result, NomErr IResult<&str, &str> { - let (input, _) = recognize(space0)(input)?; - recognize(alt((take_until(" "), not_line_ending)))(input) + let (input, _) = recognize(space0).parse(input)?; + recognize(alt((take_until(" "), not_line_ending))).parse(input) } /// Parser allowing for loose `(>= 1.2.0, < 2.0, != 1.2.3)` and strict @@ -238,7 +237,8 @@ fn loose_package_version(input: &str) -> IResult<&str, &str> { c.is_ascii_alphanumeric() || LOOSE_VERSION_CHARS.contains(&c) }))), tag(")"), - )(input) + ) + .parse(input) } /// Parser allowing only strict `1.2.3.alpha.1` versions. @@ -246,19 +246,20 @@ fn strict_package_version(input: &str) -> IResult<&str, &str> { let (input, _) = space0(input)?; recognize(many1(satisfy(|c: char| { c.is_ascii_alphanumeric() || STRICT_VERSION_CHARS.contains(&c) - })))(input) + }))) + .parse(input) } /// Get the value for a key in a ` key: value` line. fn key<'a>(input: &'a str, key: &str) -> IResult<&'a str, &'a str> { - let (input, _key) = recognize(tuple((space0, tag(key), tag(": "))))(input)?; + let (input, _key) = recognize((space0, tag(key), tag(": "))).parse(input)?; take_till_line_end(input) } /// Take everything until a line end, swallowing the line end character /// completely. fn take_till_line_end(input: &str) -> IResult<&str, &str> { - let (input, consumed) = recognize(alt((take_until("\n"), take_until("\r\n"))))(input)?; - let (input, _) = alt((tag("\n"), tag("\r\n")))(input)?; + let (input, consumed) = recognize(alt((take_until("\n"), take_until("\r\n")))).parse(input)?; + let (input, _) = alt((tag("\n"), tag("\r\n"))).parse(input)?; Ok((input, consumed)) } diff --git a/lockfile/src/parsers/go_mod.rs b/lockfile/src/parsers/go_mod.rs index e4139fadd..c3632fb2d 100644 --- a/lockfile/src/parsers/go_mod.rs +++ b/lockfile/src/parsers/go_mod.rs @@ -5,8 +5,8 @@ use nom::bytes::complete::{tag, take_till, take_till1, take_while}; use nom::character::complete::{char, multispace0, space0, space1}; use nom::combinator::{map, opt}; use nom::multi::many0; -use nom::sequence::{delimited, preceded, tuple}; -use nom::IResult; +use nom::sequence::{delimited, preceded}; +use nom::{IResult, Parser}; use crate::golang::GoDeps; use crate::{Package, PackageType, PackageVersion}; @@ -68,7 +68,7 @@ impl From for Package { } pub fn parse(input: &str) -> IResult<&str, GoDeps> { - let (_, directives) = many0(directive)(input)?; + let (_, directives) = many0(directive).parse(input)?; let mut required: Vec = Vec::new(); let mut excluded: Vec = Vec::new(); @@ -126,28 +126,26 @@ pub fn parse(input: &str) -> IResult<&str, GoDeps> { fn directive(input: &str) -> IResult<&str, Directive<'_>> { let (input, _) = take_while(|c: char| c == '\n')(input)?; - alt((module_directive, go_directive, require_directive, replace_directive, exclude_directive))( - input.trim(), - ) + alt((module_directive, go_directive, require_directive, replace_directive, exclude_directive)) + .parse(input.trim()) } fn module_directive(input: &str) -> IResult<&str, Directive<'_>> { let (input, module_name) = - preceded(tuple((tag("module"), space1)), take_till(|c| c == '\n'))(input)?; + preceded((tag("module"), space1), take_till(|c| c == '\n')).parse(input)?; Ok((input, Directive::Module(module_name))) } fn go_directive(input: &str) -> IResult<&str, Directive<'_>> { let (input, go_version) = - preceded(tuple((tag("go"), space1)), take_till(|c| c == '\n'))(input)?; + preceded((tag("go"), space1), take_till(|c| c == '\n')).parse(input)?; Ok((input, Directive::Go(go_version.trim()))) } fn require_directive(input: &str) -> IResult<&str, Directive<'_>> { - let (input, deps) = preceded( - tuple((tag("require"), space1)), - alt((module_block, map(require_spec, |r| vec![r]))), - )(input)?; + let (input, deps) = + preceded((tag("require"), space1), alt((module_block, map(require_spec, |r| vec![r])))) + .parse(input)?; Ok((input, Directive::Require(deps))) } @@ -158,7 +156,8 @@ fn require_spec(input: &str) -> IResult<&str, Module> { let (input, _) = space0(input)?; // Check if there is a comment starting with "//". - let (input, comments) = opt(preceded(tag("//"), take_till1(|c: char| c == '\n')))(input)?; + let (input, comments) = + opt(preceded(tag("//"), take_till1(|c: char| c == '\n'))).parse(input)?; // Determine if the comment indicates the module is indirect. let indirect = comments.is_some_and(|s: &str| s.trim().eq("indirect")); @@ -168,10 +167,9 @@ fn require_spec(input: &str) -> IResult<&str, Module> { } fn replace_directive(input: &str) -> IResult<&str, Directive<'_>> { - preceded(tuple((tag("replace"), space1)), alt((replace_block, map(replace_spec, |r| vec![r]))))( - input, - ) - .map(|(next_input, reps)| (next_input, Directive::Replace(reps))) + preceded((tag("replace"), space1), alt((replace_block, map(replace_spec, |r| vec![r])))) + .parse(input) + .map(|(next_input, reps)| (next_input, Directive::Replace(reps))) } fn replace_spec(input: &str) -> IResult<&str, ModuleReplacement> { @@ -187,13 +185,14 @@ fn replace_spec(input: &str) -> IResult<&str, ModuleReplacement> { }; // Consume "=>" with surrounding spaces. - let (input, _) = tuple((space1, tag("=>"), space1))(input)?; + let (input, _) = (space1, tag("=>"), space1).parse(input)?; // Parse the destination path and optional version. - let (input, (dest_path, dest_version)) = tuple(( + let (input, (dest_path, dest_version)) = ( take_till1(|c: char| c.is_whitespace()), opt(preceded(space1, take_till1(|c: char| c.is_whitespace()))), - ))(input)?; + ) + .parse(input)?; let replacement = if let Some(version) = dest_version { Replacement::Module(Module { @@ -213,10 +212,9 @@ fn replace_spec(input: &str) -> IResult<&str, ModuleReplacement> { } fn exclude_directive(input: &str) -> IResult<&str, Directive<'_>> { - preceded(tuple((tag("exclude"), space1)), alt((module_block, map(require_spec, |r| vec![r]))))( - input, - ) - .map(|(next_input, deps)| (next_input, Directive::Exclude(deps))) + preceded((tag("exclude"), space1), alt((module_block, map(require_spec, |r| vec![r])))) + .parse(input) + .map(|(next_input, deps)| (next_input, Directive::Exclude(deps))) } fn parse_block(input: &str, line_parser: F) -> IResult<&str, Vec> @@ -227,7 +225,8 @@ where char('('), many0(preceded(multispace0, line_parser)), preceded(multispace0, char(')')), - )(input) + ) + .parse(input) } fn module_block(input: &str) -> IResult<&str, Vec> { diff --git a/lockfile/src/parsers/go_sum.rs b/lockfile/src/parsers/go_sum.rs index 549312b38..a9a909957 100644 --- a/lockfile/src/parsers/go_sum.rs +++ b/lockfile/src/parsers/go_sum.rs @@ -3,14 +3,15 @@ use nom::bytes::complete::{tag, take_until}; use nom::character::complete::{alphanumeric1, line_ending, space0, space1}; use nom::combinator::{opt, recognize}; use nom::multi::{many0, many1}; -use nom::sequence::{preceded, tuple}; +use nom::sequence::preceded; +use nom::Parser; use phylum_types::types::package::PackageType; use crate::parsers::IResult; use crate::{Package, PackageVersion}; pub fn parse(input: &str) -> IResult<&str, Vec> { - let (input, pkgs) = many0(package)(input)?; + let (input, pkgs) = many0(package).parse(input)?; let pkgs = pkgs .into_iter() @@ -42,7 +43,7 @@ fn package_name(input: &str) -> IResult<&str, &str> { let (input, _) = space0(input)?; // The package name will be everything up until a space. - recognize(take_until(" "))(input) + recognize(take_until(" ")).parse(input) } fn package_version(input: &str) -> IResult<&str, &str> { @@ -50,11 +51,12 @@ fn package_version(input: &str) -> IResult<&str, &str> { let (input, _) = space0(input)?; // Accept all of `v[a-zA-Z0-9.+-]+` with an optional "/go.mod" suffix. - let (input, version) = recognize(tuple(( + let (input, version) = recognize(( tag("v"), many1(alt((alphanumeric1, tag("."), tag("-"), tag("+")))), opt(tag("/go.mod")), - )))(input)?; + )) + .parse(input)?; // Expect at least one whitespace after version. let (input, _) = space1(input)?; @@ -70,7 +72,7 @@ fn package_hash(input: &str) -> IResult<&str, &str> { let base64_parser = recognize(many1(alt((alphanumeric1, tag("+"), tag("/"), tag("="))))); // Parse base64 hash with `h1:` prefix. - let (input, hash) = preceded(tag("h1:"), base64_parser)(input)?; + let (input, hash) = preceded(tag("h1:"), base64_parser).parse(input)?; // Expect EOL. let (input, _) = line_ending(input)?; diff --git a/lockfile/src/parsers/gradle_dep.rs b/lockfile/src/parsers/gradle_dep.rs index 517a46a12..42dfd6b82 100644 --- a/lockfile/src/parsers/gradle_dep.rs +++ b/lockfile/src/parsers/gradle_dep.rs @@ -1,7 +1,8 @@ use nom::branch::alt; use nom::bytes::complete::{tag, take_till}; use nom::combinator::eof; -use nom::error::VerboseError; +use nom::Parser; +use nom_language::error::VerboseError; use phylum_types::types::package::PackageType; use crate::parsers::IResult; @@ -33,7 +34,7 @@ fn package(input: &str) -> Result>> { let (input, _) = tag(":")(input)?; let (input, version) = not_space_until(input, '=')?; - let _ = alt((tag("="), eof))(input)?; + let _ = alt((tag("="), eof)).parse(input)?; Ok(Package { name: format!("{group_id}:{artifact_id}"), diff --git a/lockfile/src/parsers/mod.rs b/lockfile/src/parsers/mod.rs index 8d1d876ca..b19077b41 100644 --- a/lockfile/src/parsers/mod.rs +++ b/lockfile/src/parsers/mod.rs @@ -2,10 +2,11 @@ use nom::branch::alt; use nom::bytes::complete::{tag, take_until}; use nom::character::complete::{line_ending, not_line_ending, space0}; use nom::combinator::{eof, opt, recognize, rest}; -use nom::error::{context, VerboseError}; +use nom::error::context; use nom::multi::many_till; -use nom::sequence::{delimited, terminated, tuple}; -use nom::AsChar; +use nom::sequence::{delimited, terminated}; +use nom::{AsChar, Parser}; +use nom_language::error::VerboseError; pub mod gem; pub mod go_mod; @@ -17,12 +18,12 @@ pub mod yarn; /// Consume everything until the next `\n` or `\r\n`. fn take_till_line_end(input: &str) -> IResult<&str, &str> { - recognize(terminated(not_line_ending, line_ending))(input) + recognize(terminated(not_line_ending, line_ending)).parse(input) } /// Consume everything until the next `\n\n` or `\r\n\r\n`. fn take_till_blank_line(input: &str) -> IResult<&str, &str> { - recognize(alt((take_until("\n\n"), take_until("\r\n\r\n"))))(input) + recognize(alt((take_until("\n\n"), take_until("\r\n\r\n")))).parse(input) } /// Consume the next line. @@ -32,7 +33,7 @@ fn take_till_blank_line(input: &str) -> IResult<&str, &str> { fn take_continued_line(mut input: &str) -> IResult<&str, ()> { loop { // Get everything up to the next NL or EOF. - let (new_input, line) = recognize(alt((take_till_line_end, rest)))(input)?; + let (new_input, line) = recognize(alt((take_till_line_end, rest))).parse(input)?; input = new_input; // Stop consuming lines once there are no continuations. diff --git a/lockfile/src/parsers/pypi.rs b/lockfile/src/parsers/pypi.rs index 5803a1928..e64dd60d4 100644 --- a/lockfile/src/parsers/pypi.rs +++ b/lockfile/src/parsers/pypi.rs @@ -4,10 +4,10 @@ use nom::branch::alt; use nom::bytes::complete::{tag, take_till, take_until}; use nom::character::complete::{alphanumeric1, char, line_ending, space1}; use nom::combinator::{eof, opt, recognize, rest, verify}; -use nom::error::{VerboseError, VerboseErrorKind}; use nom::multi::{many0, many1, separated_list0}; use nom::sequence::{delimited, pair, terminated}; -use nom::Err as NomErr; +use nom::{Err as NomErr, Parser}; +use nom_language::error::{VerboseError, VerboseErrorKind}; use phylum_types::types::package::PackageType; use crate::parsers::{self, IResult}; @@ -28,7 +28,7 @@ pub fn parse(mut input: &str) -> IResult<&str, Vec> { } // Strip comments. - let (_, line) = alt((take_until(" #"), rest))(line)?; + let (_, line) = alt((take_until(" #"), rest)).parse(line)?; // Parse dependency. let (_, pkg) = package(line, registry)?; @@ -43,7 +43,7 @@ fn line<'a>(input: &'a str, registry: &mut Option<&'a str>) -> IResult<&'a str, // Take everything until the next newline. // // This takes line continuation characters into account. - let (input, mut line) = recognize(parsers::take_continued_line)(input)?; + let (input, mut line) = recognize(parsers::take_continued_line).parse(input)?; // Remove irrelevant whitespace. line = line.trim(); @@ -74,7 +74,7 @@ fn line<'a>(input: &'a str, registry: &mut Option<&'a str>) -> IResult<&'a str, fn package<'a>(input: &'a str, registry: Option<&str>) -> IResult<&'a str, Package> { // Ignore everything after `;`. - let (_, input) = alt((take_until(";"), rest))(input)?; + let (_, input) = alt((take_until(";"), rest)).parse(input)?; // Parse for `-e` dependencies. if let Ok(editable) = editable(input) { @@ -104,7 +104,7 @@ fn package<'a>(input: &'a str, registry: Option<&str>) -> IResult<&'a str, Packa let (input, version) = package_version(input)?; // Parse local version specifier. - let (input, local_version) = opt(local_version)(input)?; + let (input, local_version) = opt(local_version).parse(input)?; let version = match (registry, local_version) { (_, Some(_)) => PackageVersion::Unknown, @@ -128,7 +128,7 @@ fn package<'a>(input: &'a str, registry: Option<&str>) -> IResult<&'a str, Packa /// repository, which does not have any path. fn editable(input: &str) -> IResult<&str, Package> { // Ensure `-e` is present and skip it. - let (input, _) = ws(tag("-e"))(input)?; + let (input, _) = ws(tag("-e")).parse(input)?; // Parse everything until the next whitespace. let (input, uri) = take_till(|c: char| c.is_whitespace())(input)?; @@ -171,23 +171,23 @@ fn editable(input: &str) -> IResult<&str, Package> { /// /// This includes path, git and internet dependencies. fn uri_version(input: &str) -> IResult<&str, &str> { - let (uri, _) = ws(tag("@"))(input)?; + let (uri, _) = ws(tag("@")).parse(input)?; Ok(("", uri)) } fn package_name(input: &str) -> IResult<&str, &str> { - terminated(ws(identifier), opt(ws(package_extras)))(input) + terminated(ws(identifier), opt(ws(package_extras))).parse(input) } fn package_version(input: &str) -> IResult<&str, &str> { // Ensure no `*` is in the version. - let (_, input) = verify(rest, |s: &str| !s.contains('*'))(input)?; + let (_, input) = verify(rest, |s: &str| !s.contains('*')).parse(input)?; // Skip exact version indicator. let (input, _) = tag("==")(input)?; // Take all valid semver character. - recognize(many1(alt((alphanumeric1, tag(".")))))(input.trim()) + recognize(many1(alt((alphanumeric1, tag("."))))).parse(input.trim()) } /// Parse local version specifiers. @@ -196,26 +196,25 @@ fn package_version(input: &str) -> IResult<&str, &str> { fn local_version(input: &str) -> IResult<&str, &str> { let (input, _) = tag("+")(input)?; - recognize(many1(alt((alphanumeric1, tag(".")))))(input) + recognize(many1(alt((alphanumeric1, tag("."))))).parse(input) } fn identifier(input: &str) -> IResult<&str, &str> { - recognize(pair(alphanumeric1, many0(alt((alphanumeric1, alt((tag("-"), tag("_"), tag("."))))))))( - input, - ) + recognize(pair(alphanumeric1, many0(alt((alphanumeric1, alt((tag("-"), tag("_"), tag(".")))))))) + .parse(input) } fn package_extras(input: &str) -> IResult<&str, &str> { - delimited(char('['), identifier_list, char(']'))(input) + delimited(char('['), identifier_list, char(']')).parse(input) } fn identifier_list(input: &str) -> IResult<&str, &str> { - recognize(separated_list0(char(','), ws(identifier)))(input) + recognize(separated_list0(char(','), ws(identifier))).parse(input) } fn line_done(input: &str) -> IResult<&str, &str> { // Allow for spaces and arguments not impacting resolution. - let (input, _) = recognize(many0(alt((nl_space1, package_hash))))(input)?; + let (input, _) = recognize(many0(alt((nl_space1, package_hash)))).parse(input)?; eof(input) } @@ -242,9 +241,9 @@ fn package_hash(input: &str) -> IResult<&str, &str> { /// A combinator that takes a parser `inner` and produces a parser that also /// consumes both leading and trailing whitespace, returning the output of /// `inner`. -fn ws<'a, F>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> +fn ws<'a, P>(inner: P) -> impl Parser<&'a str, Output = &'a str, Error = VerboseError<&'a str>> where - F: Fn(&'a str) -> IResult<&'a str, &'a str>, + P: Parser<&'a str, Output = &'a str, Error = VerboseError<&'a str>>, { delimited(nl_space0, inner, nl_space0) } @@ -253,17 +252,17 @@ where /// /// This automatically handles " \\\n" and treats it as normal space. fn nl_space0(input: &str) -> IResult<&str, &str> { - recognize(many0(alt((space1, line_continuation))))(input) + recognize(many0(alt((space1, line_continuation)))).parse(input) } /// Newline-aware space1. /// /// This automatically handles " \\\n" and treats it as normal space. fn nl_space1(input: &str) -> IResult<&str, &str> { - recognize(many1(alt((space1, line_continuation))))(input) + recognize(many1(alt((space1, line_continuation)))).parse(input) } /// Recognize line continuations. fn line_continuation(input: &str) -> IResult<&str, &str> { - recognize(pair(tag("\\"), line_ending))(input) + recognize(pair(tag("\\"), line_ending)).parse(input) } diff --git a/lockfile/src/parsers/spdx.rs b/lockfile/src/parsers/spdx.rs index 41490c6f9..193223ffe 100644 --- a/lockfile/src/parsers/spdx.rs +++ b/lockfile/src/parsers/spdx.rs @@ -2,10 +2,11 @@ use nom::branch::alt; use nom::bytes::complete::{tag, take_till, take_until, take_while}; use nom::character::complete::{line_ending, multispace0, not_line_ending, space0}; use nom::combinator::{eof, map_opt, opt, recognize}; -use nom::error::{context, VerboseError, VerboseErrorKind}; +use nom::error::context; use nom::multi::{many0, many1, many_till}; -use nom::sequence::{delimited, preceded, tuple}; -use nom::Err as NomErr; +use nom::sequence::{delimited, preceded}; +use nom::{Err as NomErr, Parser}; +use nom_language::error::{VerboseError, VerboseErrorKind}; use crate::parsers::{take_till_blank_line, take_till_line_end, IResult}; use crate::spdx::{ExternalRefs, PackageInformation, ReferenceCategory, Relationship, SpdxInfo}; @@ -14,7 +15,7 @@ pub(crate) fn parse(input: &str) -> IResult<&str, SpdxInfo> { let (_, relationships) = parse_relationships(input)?; let (_, document_describes) = parse_document_describes(input)?; let (i, spdx_id) = parse_spdx_id(input)?; - let (i, packages) = many1(package)(i)?; + let (i, packages) = many1(package).parse(i)?; Ok((i, SpdxInfo { spdx_id: spdx_id.into(), document_describes, packages, relationships })) } @@ -26,10 +27,9 @@ fn parse_spdx_id(input: &str) -> IResult<&str, &str> { } fn parse_document_describes(input: &str) -> IResult<&str, Vec> { - let (i, describes) = opt(preceded( - take_until("DocumentDescribes:"), - take_till(|c| c == '\n' || c == '\r'), - ))(input)?; + let (i, describes) = + opt(preceded(take_until("DocumentDescribes:"), take_till(|c| c == '\n' || c == '\r'))) + .parse(input)?; let describes_list = if let Some(describes_str) = describes { describes_str @@ -54,12 +54,12 @@ fn skip_until_tag<'a>(input: &'a str, line_tag: &'a str) -> IResult<&'a str, ()> } fn parse_relationships(input: &str) -> IResult<&str, Vec> { - many0(parse_relationship)(input) + many0(parse_relationship).parse(input) } fn parse_relationship(input: &str) -> IResult<&str, Relationship> { let (i, _) = skip_until_tag(input, "Relationship:")?; - let (i, rel) = recognize(ws(take_till_line_end))(i)?; + let (i, rel) = recognize(ws(take_till_line_end)).parse(i)?; let parts: Vec<&str> = rel.split_whitespace().collect(); if parts.len() == 3 { @@ -76,23 +76,22 @@ fn parse_relationship(input: &str) -> IResult<&str, Relationship> { } fn package_name(input: &str) -> IResult<&str, &str> { - recognize(take_until("PackageName:"))(input) + recognize(take_until("PackageName:")).parse(input) } fn package(input: &str) -> IResult<&str, PackageInformation> { let (i, _) = package_name(input)?; - let (i, capture) = recognize(many_till( - take_till_line_end, - recognize(tuple((space0, alt((line_ending, eof))))), - ))(i)?; + let (i, capture) = + recognize(many_till(take_till_line_end, recognize((space0, alt((line_ending, eof)))))) + .parse(i)?; let (_, my_entry) = parse_package(capture)?; Ok((i, my_entry)) } fn parse_package(input: &str) -> IResult<&str, PackageInformation> { - context("package", package_info)(input).map(|(next_input, res)| { + context("package", package_info).parse(input).map(|(next_input, res)| { let pi = res; (next_input, pi) }) @@ -103,18 +102,18 @@ fn package_info(input: &str) -> IResult<&str, PackageInformation> { // PackageName is required. let (i, _) = tag("PackageName:")(i)?; - let (i, name) = recognize(ws(take_till_line_end))(i)?; + let (i, name) = recognize(ws(take_till_line_end)).parse(i)?; let name = name.trim(); // SPDXID is required. let (i, _) = tag("SPDXID:")(i)?; - let (tail, spdx_id) = recognize(ws(take_till_line_end))(i)?; + let (tail, spdx_id) = recognize(ws(take_till_line_end)).parse(i)?; // PackageVersion is optional. // The version can be obtained from PURL if present, so we don't return an // error. - let (i, has_version) = opt(tag("PackageVersion:"))(tail)?; - let (i, v) = recognize(ws(take_till_line_end))(i)?; + let (i, has_version) = opt(tag("PackageVersion:")).parse(tail)?; + let (i, v) = recognize(ws(take_till_line_end)).parse(i)?; let version = has_version.map(|_| v.trim().to_string()); // Update input. @@ -125,12 +124,12 @@ fn package_info(input: &str) -> IResult<&str, PackageInformation> { // PackageDownloadLocation is required. let (i, _) = skip_until_tag(i, "PackageDownloadLocation:")?; - let (i, download_location) = recognize(ws(take_till_line_end))(i)?; + let (i, download_location) = recognize(ws(take_till_line_end)).parse(i)?; let download_location = download_location.trim(); // Look for external references. let (i, next_input) = extern_ref(i)?; - let (_, external_ref) = opt(recognize(ws(take_till_line_end)))(i)?; + let (_, external_ref) = opt(recognize(ws(take_till_line_end))).parse(i)?; let external_refs = external_ref .map(|er| parse_external_refs(er).map(|(_, external_ref)| vec![external_ref])) .unwrap_or_else(|| Ok(Vec::new()))?; @@ -149,16 +148,17 @@ fn extern_ref(input: &str) -> IResult<&str, &str> { take_until("ExternalRef: PACKAGE-MANAGER"), take_until("ExternalRef: PACKAGE_MANAGER"), take_till_blank_line, - )))(input) + ))) + .parse(input) } fn parse_external_refs(input: &str) -> IResult<&str, ExternalRefs> { let input = input.trim_start_matches("ExternalRef:").trim(); - let purl = tuple(( + let purl = ( ws(take_while(|c: char| !c.is_whitespace())), ws(take_while(|c: char| !c.is_whitespace())), ws(not_line_ending), - )); + ); map_opt(purl, |(reference_category, reference_type, reference_locator)| { let reference_category = match reference_category { @@ -174,15 +174,16 @@ fn parse_external_refs(input: &str) -> IResult<&str, ExternalRefs> { reference_type: reference_type.into(), reference_locator: reference_locator.into(), }) - })(input) + }) + .parse(input) } /// A combinator that takes a parser `inner` and produces a parser that also /// consumes both leading and trailing whitespace, returning the output of /// `inner`. -fn ws<'a, F>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> +fn ws<'a, P>(inner: P) -> impl Parser<&'a str, Output = &'a str, Error = VerboseError<&'a str>> where - F: Fn(&'a str) -> IResult<&'a str, &'a str>, + P: Parser<&'a str, Output = &'a str, Error = VerboseError<&'a str>>, { delimited(multispace0, inner, multispace0) } diff --git a/lockfile/src/parsers/yarn.rs b/lockfile/src/parsers/yarn.rs index 940ec2cb5..293109db1 100644 --- a/lockfile/src/parsers/yarn.rs +++ b/lockfile/src/parsers/yarn.rs @@ -2,7 +2,7 @@ use nom::bytes::complete::take_till; use nom::multi::many0; -use nom::InputTakeAtPosition; +use nom::{Input, Parser}; use phylum_types::types::package::PackageType; use super::*; @@ -22,22 +22,21 @@ pub fn parse(mut input: &str) -> IResult<&str, Vec> { fn entry(input: &str) -> IResult<&str, Option> { // Ignore comments. - if let Ok((input, _)) = recognize(tuple((tag("#"), take_till_line_end)))(input) { - let (input, _) = many0(line_ending)(input)?; + if let Ok((input, _)) = recognize((tag("#"), take_till_line_end)).parse(input) { + let (input, _) = many0(line_ending).parse(input)?; return Ok((input, None)); } - let (input, capture) = recognize(many_till( - take_till_line_end, - recognize(tuple((space0, alt((line_ending, eof))))), - ))(input)?; + let (input, capture) = + recognize(many_till(take_till_line_end, recognize((space0, alt((line_ending, eof)))))) + .parse(input)?; let (_, my_entry) = parse_entry(capture)?; Ok((input, my_entry)) } fn parse_entry(input: &str) -> IResult<&str, Option> { - let (input, (name, version)) = context("entry", tuple((entry_name, entry_version)))(input)?; + let (input, (name, version)) = context("entry", (entry_name, entry_version)).parse(input)?; let version = match version { Some(version) => version, @@ -51,17 +50,17 @@ fn parse_entry(input: &str) -> IResult<&str, Option> { fn entry_name(input: &str) -> IResult<&str, &str> { // Strip optional quotes. - let (input, _) = opt(tag(r#"""#))(input)?; + let (input, _) = opt(tag(r#"""#)).parse(input)?; // Strip optional aliased package name. - let (input, _) = recognize(opt(tuple((take_until("@npm:"), tag("@npm:")))))(input)?; + let (input, _) = recognize(opt((take_until("@npm:"), tag("@npm:")))).parse(input)?; // Allow for up to one leading `@` in package name (like `@angular/cli`). let opt_at = opt(tag("@")); // Consume everything until version separator as name. - let name_parser = tuple((opt_at, take_until("@"))); - context("name", recognize(name_parser))(input) + let name_parser = (opt_at, take_until("@")); + context("name", recognize(name_parser)).parse(input) } fn entry_version(input: &str) -> IResult<&str, Option> { @@ -85,9 +84,9 @@ fn entry_version(input: &str) -> IResult<&str, Option> { // Parse version field. let (input, _) = take_until(r#"version"#)(input)?; - let version_key = tuple((tag(r#"version"#), opt(tag(r#"""#)), tag(r#" ""#))); + let version_key = (tag(r#"version"#), opt(tag(r#"""#)), tag(r#" ""#)); let version_parser = delimited(version_key, is_version, tag(r#"""#)); - let (input, version) = context("version", version_parser)(input)?; + let (input, version) = context("version", version_parser).parse(input)?; let package_version = PackageVersion::FirstParty(version.to_string()); @@ -104,7 +103,7 @@ fn path_dep(input: &str) -> IResult<&str, Option> { fn git_dep(input: &str) -> IResult<&str, Option> { // Parse resolved field. let (input, _) = take_until(r#"resolved"#)(input)?; - let (input, _) = tuple((tag(r#"resolved"#), opt(tag(r#"""#)), tag(r#" ""#)))(input)?; + let (input, _) = (tag(r#"resolved"#), opt(tag(r#"""#)), tag(r#" ""#)).parse(input)?; let (input, url) = take_until("\"")(input)?; let package_version = PackageVersion::Git(url.into()); diff --git a/lockfile/src/python.rs b/lockfile/src/python.rs index d6e7174e9..955c10304 100644 --- a/lockfile/src/python.rs +++ b/lockfile/src/python.rs @@ -11,8 +11,8 @@ use lockfile_generator::pipenv::Pipenv as PipenvGenerator; use lockfile_generator::poetry::Poetry as PoetryGenerator; #[cfg(feature = "generator")] use lockfile_generator::Generator; -use nom::error::convert_error; use nom::Finish; +use nom_language::error::convert_error; use phylum_types::types::package::PackageType; use serde::Deserialize; diff --git a/lockfile/src/ruby.rs b/lockfile/src/ruby.rs index e3942a4eb..35f7451e7 100644 --- a/lockfile/src/ruby.rs +++ b/lockfile/src/ruby.rs @@ -6,8 +6,8 @@ use anyhow::{anyhow, Context}; use lockfile_generator::bundler::Bundler as BundlerGenerator; #[cfg(feature = "generator")] use lockfile_generator::Generator; -use nom::error::convert_error; use nom::Finish; +use nom_language::error::convert_error; use super::parsers::gem; use crate::{Package, Parse}; diff --git a/lockfile/src/spdx.rs b/lockfile/src/spdx.rs index 652d317f0..c7cce7efe 100644 --- a/lockfile/src/spdx.rs +++ b/lockfile/src/spdx.rs @@ -3,8 +3,8 @@ use std::path::Path; use std::str::FromStr; use anyhow::{anyhow, bail, Context}; -use nom::error::convert_error; use nom::Finish; +use nom_language::error::convert_error; use phylum_types::types::package::PackageType; use purl::GenericPurl; use serde::Deserialize;