diff options
Diffstat (limited to 'src/atom/parsers.rs')
| -rw-r--r-- | src/atom/parsers.rs | 599 |
1 files changed, 0 insertions, 599 deletions
diff --git a/src/atom/parsers.rs b/src/atom/parsers.rs deleted file mode 100644 index c7ff586..0000000 --- a/src/atom/parsers.rs +++ /dev/null @@ -1,599 +0,0 @@ -use core::option::Option::None; - -use mon::{ - Parser, ParserIter, ascii_alphanumeric, ascii_numeric, ascii_numeric1, eof, r#if, - input::InputIter, one_of, tag, -}; - -use crate::{ - Parseable, - atom::{ - Atom, Blocker, BuildId, Category, Cp, Cpv, Name, Repo, Slot, SlotName, SlotOperator, - UseDep, UseDepCondition, UseDepNegate, UseDepSign, Version, VersionNumber, VersionNumbers, - VersionOperator, VersionSuffix, VersionSuffixKind, VersionSuffixes, Wildcard, - }, - useflag::UseFlag, -}; - -impl<'a> Parseable<'a, &'a str> for Blocker { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - tag("!!") - .map(|_| Blocker::Strong) - .or(tag("!").map(|_| Blocker::Weak)) - } -} - -impl<'a> Parseable<'a, &'a str> for VersionOperator { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - tag("<=") - .map(|_| VersionOperator::LtEq) - .or(tag(">=").map(|_| VersionOperator::GtEq)) - .or(tag("<").map(|_| VersionOperator::Lt)) - .or(tag(">").map(|_| VersionOperator::Gt)) - .or(tag("=").map(|_| VersionOperator::Eq)) - .or(tag("~").map(|_| VersionOperator::Roughly)) - } -} - -impl<'a> Parseable<'a, &'a str> for VersionNumber { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - ascii_numeric1().map(|output: &str| VersionNumber(output.to_string())) - } -} - -impl<'a> Parseable<'a, &'a str> for BuildId { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let start = ascii_numeric().and_not(tag("0")); - let rest = ascii_numeric().repeated().many(); - - start - .and(rest) - .recognize() - .or(tag("0")) - .map(|output: &str| BuildId(output.to_string())) - } -} - -impl<'a> Parseable<'a, &'a str> for VersionSuffixKind { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - tag("alpha") - .map(|_| VersionSuffixKind::Alpha) - .or(tag("beta").map(|_| VersionSuffixKind::Beta)) - .or(tag("pre").map(|_| VersionSuffixKind::Pre)) - .or(tag("rc").map(|_| VersionSuffixKind::Rc)) - .or(tag("p").map(|_| VersionSuffixKind::P)) - } -} - -impl<'a> Parseable<'a, &'a str> for VersionSuffix { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - VersionSuffixKind::parser() - .and(VersionNumber::parser().opt()) - .map(|(kind, number)| VersionSuffix { kind, number }) - } -} - -impl<'a> Parseable<'a, &'a str> for VersionNumbers { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - VersionNumber::parser() - .separated_by(tag(".")) - .at_least(1) - .map(VersionNumbers) - } -} - -impl<'a> Parseable<'a, &'a str> for VersionSuffixes { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - VersionSuffix::parser() - .separated_by(tag("_")) - .at_least(1) - .map(VersionSuffixes) - } -} - -impl<'a> Parseable<'a, &'a str> for Version { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let rev = VersionNumber::parser().preceded_by(tag("-r")); - let build_id = BuildId::parser().preceded_by(tag("-")); - - VersionNumbers::parser() - .and(r#if(|c: &char| c.is_ascii_alphabetic() && c.is_ascii_lowercase()).opt()) - .and(VersionSuffixes::parser().preceded_by(tag("_")).opt()) - .and(rev.opt()) - .and(build_id.opt()) - .map(|((((numbers, letter), suffixes), rev), build_id)| Version { - numbers, - letter, - suffixes: suffixes.unwrap_or(VersionSuffixes(Vec::new())), - rev, - build_id, - }) - } -} - -impl<'a> Parseable<'a, &'a str> for Category { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let start = ascii_alphanumeric().or(one_of("_".chars())); - let rest = ascii_alphanumeric() - .or(one_of("+_.-".chars())) - .repeated() - .many(); - - start - .and(rest) - .recognize() - .map(|output: &str| Category(output.to_string())) - } -} - -impl<'a> Parseable<'a, &'a str> for Name { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let start = || ascii_alphanumeric().or(one_of("_".chars())); - - let rest = ascii_alphanumeric() - .or(one_of("_+".chars())) - .or(one_of("-".chars()).and_not( - Version::parser() - .preceded_by(tag("-")) - .followed_by(ascii_alphanumeric().or(one_of("_+-".chars())).not()), - )) - .repeated() - .many(); - - let verify = ascii_alphanumeric() - .or(one_of("_+".chars())) - .or(one_of("-".chars()) - .and_not(Version::parser().preceded_by(tag("-")).followed_by(eof()))) - .repeated() - .many(); - - start() - .and(rest) - .recognize() - .verify_output(move |output: &&str| { - verify.check_finished(InputIter::new(*output)).is_ok() - }) - .map(|output: &str| Name(output.to_string())) - } -} - -impl<'a> Parseable<'a, &'a str> for SlotOperator { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - tag("=") - .map(|_| SlotOperator::Eq) - .or(tag("*").map(|_| SlotOperator::Star)) - } -} - -impl<'a> Parseable<'a, &'a str> for SlotName { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let start = ascii_alphanumeric().or(one_of("_".chars())); - let rest = ascii_alphanumeric() - .or(one_of("+_.-".chars())) - .repeated() - .many(); - - start - .and(rest) - .recognize() - .map(|output: &str| SlotName(output.to_string())) - } -} - -impl<'a> Parseable<'a, &'a str> for Slot { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let wildcard = tag("*").map(|_| Slot::Wildcard); - let equal = tag("=").map(|_| Slot::Equal); - let name_equal = SlotName::parser() - .and(SlotName::parser().preceded_by(tag("/")).opt()) - .followed_by(tag("=")) - .map(|(primary, sub)| Slot::NameEqual { primary, sub }); - let name = SlotName::parser() - .and(SlotName::parser().preceded_by(tag("/")).opt()) - .map(|(primary, sub)| Self::Name { primary, sub }); - - wildcard.or(equal).or(name_equal).or(name) - } -} - -impl<'a> Parseable<'a, &'a str> for UseDepSign { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - tag("(-)") - .map(|_| UseDepSign::Disabled) - .or(tag("(+)").map(|_| UseDepSign::Enabled)) - } -} - -impl<'a> Parseable<'a, &'a str> for Repo { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let start = ascii_alphanumeric().or(one_of("_".chars())); - let rest = ascii_alphanumeric() - .or(one_of("_-".chars())) - .repeated() - .many(); - - start - .and(rest) - .recognize() - .verify_output(move |output: &&str| { - Name::parser() - .check_finished(InputIter::new(*output)) - .is_ok() - }) - .map(|output: &str| Repo(output.to_string())) - } -} - -impl<'a> Parseable<'a, &'a str> for UseDep { - type Parser = impl Parser<&'a str, Output = Self>; - - #[allow(clippy::many_single_char_names)] - fn parser() -> Self::Parser { - let a = UseFlag::parser() - .and(UseDepSign::parser().opt()) - .preceded_by(tag("-")) - .map(|(flag, sign)| UseDep { - negate: Some(UseDepNegate::Minus), - flag, - sign, - condition: None, - }); - - let b = UseFlag::parser() - .and(UseDepSign::parser().opt()) - .preceded_by(tag("!")) - .followed_by(tag("?")) - .map(|(flag, sign)| UseDep { - negate: Some(UseDepNegate::Exclamation), - flag, - sign, - condition: Some(UseDepCondition::Question), - }); - - let c = UseFlag::parser() - .and(UseDepSign::parser().opt()) - .followed_by(tag("?")) - .map(|(flag, sign)| UseDep { - negate: None, - flag, - sign, - condition: Some(UseDepCondition::Question), - }); - - let d = UseFlag::parser() - .and(UseDepSign::parser().opt()) - .preceded_by(tag("!")) - .followed_by(tag("=")) - .map(|(flag, sign)| UseDep { - negate: Some(UseDepNegate::Exclamation), - flag, - sign, - condition: Some(UseDepCondition::Eq), - }); - - let e = UseFlag::parser() - .and(UseDepSign::parser().opt()) - .followed_by(tag("=")) - .map(|(flag, sign)| UseDep { - negate: None, - flag, - sign, - condition: Some(UseDepCondition::Eq), - }); - - let f = UseFlag::parser() - .and(UseDepSign::parser().opt()) - .map(|(flag, sign)| UseDep { - negate: None, - flag, - sign, - condition: None, - }); - - a.or(b).or(c).or(d).or(e).or(f) - } -} - -impl<'a> Parseable<'a, &'a str> for Atom { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - let usedeps = || { - UseDep::parser() - .separated_by(tag(",")) - .at_least(1) - .delimited_by(tag("["), tag("]")) - .opt() - }; - - let without_version = Blocker::parser() - .opt() - .and(Category::parser()) - .and(Name::parser().preceded_by(tag("/"))) - .and(Slot::parser().preceded_by(tag(":")).opt()) - .and(Repo::parser().preceded_by(tag("::")).opt()) - .and(usedeps()) - .map( - |(((((blocker, category), name), slot), repo), usedeps)| Atom { - blocker, - category, - name, - version: None, - slot, - repo, - usedeps: usedeps.unwrap_or(Vec::new()), - }, - ); - - let with_version = Blocker::parser() - .opt() - .and(VersionOperator::parser()) - .and(Category::parser()) - .and(Name::parser().preceded_by(tag("/"))) - .and(Version::parser().preceded_by(tag("-"))) - .and(tag("*").map(|_| Wildcard).opt()) - .and(Slot::parser().preceded_by(tag(":")).opt()) - .and(Repo::parser().preceded_by(tag("::")).opt()) - .and(usedeps()) - .verify_output( - |((((((((_, version_operator), _), _), version), star), _), _), _)| { - matches!( - (version_operator, star), - (VersionOperator::Eq, Some(_) | None) | (_, None) - ) && matches!((version.build_id(), star), (Some(_), None) | (None, _)) - }, - ) - .map( - |( - ( - ((((((blocker, version_operator), category), name), version), star), slot), - repo, - ), - usedeps, - )| { - Atom { - blocker, - category, - name, - version: Some((version_operator, version, star)), - slot, - repo, - usedeps: usedeps.unwrap_or(Vec::new()), - } - }, - ); - - with_version.or(without_version) - } -} - -impl<'a> Parseable<'a, &'a str> for Cp { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - Category::parser() - .and(Name::parser().preceded_by(tag("/"))) - .map(|(category, name)| Cp { category, name }) - } -} - -impl<'a> Parseable<'a, &'a str> for Cpv { - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - Category::parser() - .and(Name::parser().preceded_by(tag("/"))) - .and(Version::parser().preceded_by(tag("-"))) - .and(Slot::parser().preceded_by(tag(":")).opt()) - .map(|(((category, name), version), slot)| Cpv { - category, - name, - version, - slot, - }) - } -} - -#[cfg(test)] -mod test { - - use mon::input::InputIter; - - use super::*; - - #[test] - fn test_version() { - let it = InputIter::new("1.0.0v_alpha1_beta1-r1"); - - Version::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_name() { - let it = InputIter::new("foo-1-bar-1.0.0"); - - match Name::parser().parse(it) { - Ok((_, output)) => { - assert_eq!(output.0.as_str(), "foo-1-bar"); - } - _ => unreachable!(), - } - } - - #[test] - fn test_atom() { - let it = InputIter::new( - "!!>=cat/pkg-1-foo-1.0.0v_alpha1_p20250326-r1:primary/sub=[use,use=,!use=,use?,!use?,-use,use(+),use(-)]", - ); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_cursed_atom() { - let it = InputIter::new( - "!!>=_.+-0-/_-test-T-123_beta1_-4a-6+-_p--1.00.02b_alpha3_pre_p4-r5:slot/_-+6-9=[test(+),test(-)]", - ); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_atom_with_star_in_non_empty_slot() { - let it = InputIter::new("foo/bar:*/subslot"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_invalid_usedep() { - let it = InputIter::new("foo-bar:slot/sub=[!use]"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_empty_slot() { - let it = InputIter::new("=dev-ml/uucp-17*:"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_usedep_with_underscore() { - let it = InputIter::new("foo/bar[use_dep]"); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_version_with_uppercase_letter() { - let it = InputIter::new("=foo/bar-1.0.0V"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_version_with_version_operator_without_version() { - let it = InputIter::new("=foo/bar"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_version_with_version_without_version_operator() { - let it = InputIter::new("foo/bar-1.0.0"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_atom_with_eq_version_operator() { - let it = InputIter::new("=foo/bar-1.0.0"); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_atom_with_star_in_version() { - let it = InputIter::new("=foo/bar-1.2*"); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_atom_with_star_in_version_without_eq_version_operator() { - let it = InputIter::new(">=foo/bar-1.2*"); - - assert!(Atom::parser().check_finished(it).is_err()); - } - - #[test] - fn test_atom_with_trailing_dash_and_letter() { - let it = InputIter::new("dev-db/mysql-connector-c"); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_cpv_with_slot() { - let it = InputIter::new("foo/bar-1.0:slot/sub="); - - Cpv::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_cpv_without_version_but_trailing_almost_version() { - let it = InputIter::new("dev-perl/mod-p-2.3_"); - - assert!(Cpv::parser().parse_finished(it).is_err()); - } - - #[test] - fn test_empty_slot_with_operator() { - let it = InputIter::new("foo/bar:="); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_with_repo() { - let it = InputIter::new("=foo/bar-1.0.0:slot/sub=::gentoo[a,b,c]"); - - Atom::parser().check_finished(it).unwrap(); - } - - #[test] - fn test_against_fuzzer_false_positives() { - let atoms = [ - "media-libs/libsdl2[haptitick(+),sound(+)vd,eio(+)]", - "=kde-frameworks/kcodecs-6.19*86", - "=dev-ml/stdio-0.17*t:=[ocamlopt?]", - ">=dev-libs/libgee-0-8.5:0..8=", - "<dev-haskell/wai-3.3:=[]", - ">=kde-frameworks/kcrash-2.16.0:6*", - "0-f/merreka+m::k+", - "iev-a/h:/n=", - "=dev-ml/stdio-0-17*:=[ocamlopt?]", - ]; - - for atom in atoms { - assert!( - Atom::parser().check_finished(InputIter::new(atom)).is_err(), - "{atom}" - ); - } - } -} |
