forked from gentoo-utils/gentoo-utils
impl Parseable trait
This commit is contained in:
@@ -334,14 +334,14 @@ impl fmt::Display for Atom {
|
|||||||
mod test {
|
mod test {
|
||||||
use mon::{Parser, input::InputIter};
|
use mon::{Parser, input::InputIter};
|
||||||
|
|
||||||
use crate::atom::parsers;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::Parseable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_version_display() {
|
fn test_version_display() {
|
||||||
let s = "1.0.0_alpha1_beta1-r1";
|
let s = "1.0.0_alpha1_beta1-r1";
|
||||||
let version = parsers::version()
|
let version = Version::parser().parse_finished(InputIter::new(s)).unwrap();
|
||||||
.parse_finished(InputIter::new(s))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(version.to_string().as_str(), s);
|
assert_eq!(version.to_string().as_str(), s);
|
||||||
}
|
}
|
||||||
@@ -349,7 +349,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_display_atom() {
|
fn test_display_atom() {
|
||||||
let s = "!!>=foo/bar-1.0.0v_alpha1_beta1-r1:slot/sub=[a,b,c]";
|
let s = "!!>=foo/bar-1.0.0v_alpha1_beta1-r1:slot/sub=[a,b,c]";
|
||||||
let atom = parsers::atom().parse_finished(InputIter::new(s)).unwrap();
|
let atom = Atom::parser().parse_finished(InputIter::new(s)).unwrap();
|
||||||
|
|
||||||
assert_eq!(atom.to_string().as_str(), s);
|
assert_eq!(atom.to_string().as_str(), s);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,21 +3,29 @@ use core::option::Option::None;
|
|||||||
use mon::{Parser, r#if, numeric1, one_of, tag};
|
use mon::{Parser, r#if, numeric1, one_of, tag};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
Parseable,
|
||||||
atom::{
|
atom::{
|
||||||
Atom, Blocker, Category, Name, Slot, SlotName, SlotOperator, UseDep, UseDepCondition,
|
Atom, Blocker, Category, Name, Slot, SlotName, SlotOperator, UseDep, UseDepCondition,
|
||||||
UseDepNegate, UseDepSign, Version, VersionNumber, VersionOperator, VersionSuffix,
|
UseDepNegate, UseDepSign, Version, VersionNumber, VersionOperator, VersionSuffix,
|
||||||
VersionSuffixKind,
|
VersionSuffixKind,
|
||||||
},
|
},
|
||||||
useflag::parsers::useflag,
|
useflag::UseFlag,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn blocker<'a>() -> impl Parser<&'a str, Output = Blocker> {
|
impl<'a> Parseable<'a, &'a str> for Blocker {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
tag("!!")
|
tag("!!")
|
||||||
.map(|_| Blocker::Strong)
|
.map(|_| Blocker::Strong)
|
||||||
.or(tag("!").map(|_| Blocker::Weak))
|
.or(tag("!").map(|_| Blocker::Weak))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn version_operator<'a>() -> impl Parser<&'a str, Output = VersionOperator> {
|
impl<'a> Parseable<'a, &'a str> for VersionOperator {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
tag("<=")
|
tag("<=")
|
||||||
.map(|_| VersionOperator::LtEq)
|
.map(|_| VersionOperator::LtEq)
|
||||||
.or(tag(">=").map(|_| VersionOperator::GtEq))
|
.or(tag(">=").map(|_| VersionOperator::GtEq))
|
||||||
@@ -26,15 +34,23 @@ pub fn version_operator<'a>() -> impl Parser<&'a str, Output = VersionOperator>
|
|||||||
.or(tag("=").map(|_| VersionOperator::Eq))
|
.or(tag("=").map(|_| VersionOperator::Eq))
|
||||||
.or(tag("~").map(|_| VersionOperator::Roughly))
|
.or(tag("~").map(|_| VersionOperator::Roughly))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn version_number<'a>() -> impl Parser<&'a str, Output = VersionNumber> {
|
impl<'a> Parseable<'a, &'a str> for VersionNumber {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
numeric1()
|
numeric1()
|
||||||
.followed_by(tag("*").opt())
|
.followed_by(tag("*").opt())
|
||||||
.recognize()
|
.recognize()
|
||||||
.map(|output: &str| VersionNumber(output.to_string()))
|
.map(|output: &str| VersionNumber(output.to_string()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn version_suffix_kind<'a>() -> impl Parser<&'a str, Output = VersionSuffixKind> {
|
impl<'a> Parseable<'a, &'a str> for VersionSuffixKind {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
tag("alpha")
|
tag("alpha")
|
||||||
.map(|_| VersionSuffixKind::Alpha)
|
.map(|_| VersionSuffixKind::Alpha)
|
||||||
.or(tag("beta").map(|_| VersionSuffixKind::Beta))
|
.or(tag("beta").map(|_| VersionSuffixKind::Beta))
|
||||||
@@ -42,17 +58,25 @@ pub fn version_suffix_kind<'a>() -> impl Parser<&'a str, Output = VersionSuffixK
|
|||||||
.or(tag("rc").map(|_| VersionSuffixKind::Rc))
|
.or(tag("rc").map(|_| VersionSuffixKind::Rc))
|
||||||
.or(tag("p").map(|_| VersionSuffixKind::P))
|
.or(tag("p").map(|_| VersionSuffixKind::P))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn version_suffix<'a>() -> impl Parser<&'a str, Output = VersionSuffix> {
|
|
||||||
version_suffix_kind()
|
|
||||||
.and(version_number().opt())
|
|
||||||
.map(|(kind, number)| VersionSuffix { kind, number })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn version<'a>() -> impl Parser<&'a str, Output = Version> {
|
impl<'a> Parseable<'a, &'a str> for VersionSuffix {
|
||||||
let numbers = version_number().separated_list(tag("."), 1..);
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
let suffixes = version_suffix().separated_list(tag("_"), 0..);
|
|
||||||
let rev = version_number().preceded_by(tag("-r"));
|
fn parser() -> Self::Parser {
|
||||||
|
VersionSuffixKind::parser()
|
||||||
|
.and(VersionNumber::parser().opt())
|
||||||
|
.map(|(kind, number)| VersionSuffix { kind, number })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parseable<'a, &'a str> for Version {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
let numbers = VersionNumber::parser().separated_list(tag("."), 1..);
|
||||||
|
let suffixes = VersionSuffix::parser().separated_list(tag("_"), 0..);
|
||||||
|
let rev = VersionNumber::parser().preceded_by(tag("-r"));
|
||||||
|
|
||||||
numbers
|
numbers
|
||||||
.and(r#if(|c: &char| c.is_ascii_alphabetic() && c.is_ascii_lowercase()).opt())
|
.and(r#if(|c: &char| c.is_ascii_alphabetic() && c.is_ascii_lowercase()).opt())
|
||||||
@@ -65,8 +89,12 @@ pub fn version<'a>() -> impl Parser<&'a str, Output = Version> {
|
|||||||
rev,
|
rev,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn category<'a>() -> impl Parser<&'a str, Output = Category> {
|
impl<'a> Parseable<'a, &'a str> for Category {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
let start = r#if(|c: &char| c.is_ascii_alphanumeric() || *c == '_');
|
let start = r#if(|c: &char| c.is_ascii_alphanumeric() || *c == '_');
|
||||||
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_.-".contains(*c)).list(0..);
|
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_.-".contains(*c)).list(0..);
|
||||||
|
|
||||||
@@ -75,15 +103,19 @@ pub fn category<'a>() -> impl Parser<&'a str, Output = Category> {
|
|||||||
.recognize()
|
.recognize()
|
||||||
.map(|output: &str| Category(output.to_string()))
|
.map(|output: &str| Category(output.to_string()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name<'a>() -> impl Parser<&'a str, Output = Name> {
|
impl<'a> Parseable<'a, &'a str> for Name {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
let start = r#if(|c: &char| c.is_ascii_alphanumeric() || *c == '_');
|
let start = r#if(|c: &char| c.is_ascii_alphanumeric() || *c == '_');
|
||||||
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "_+".contains(*c))
|
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "_+".contains(*c))
|
||||||
.or(one_of("-".chars()).and_not(
|
.or(
|
||||||
version().preceded_by(tag("-")).followed_by(
|
one_of("-".chars()).and_not(Version::parser().preceded_by(tag("-")).followed_by(
|
||||||
r#if(|c: &char| c.is_ascii_alphanumeric() || "_+-".contains(*c)).not(),
|
r#if(|c: &char| c.is_ascii_alphanumeric() || "_+-".contains(*c)).not(),
|
||||||
),
|
)),
|
||||||
))
|
)
|
||||||
.list(0..);
|
.list(0..);
|
||||||
|
|
||||||
start
|
start
|
||||||
@@ -91,14 +123,22 @@ pub fn name<'a>() -> impl Parser<&'a str, Output = Name> {
|
|||||||
.recognize()
|
.recognize()
|
||||||
.map(|output: &str| Name(output.to_string()))
|
.map(|output: &str| Name(output.to_string()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn slot_operator<'a>() -> impl Parser<&'a str, Output = SlotOperator> {
|
impl<'a> Parseable<'a, &'a str> for SlotOperator {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
tag("=")
|
tag("=")
|
||||||
.map(|_| SlotOperator::Eq)
|
.map(|_| SlotOperator::Eq)
|
||||||
.or(tag("*").map(|_| SlotOperator::Star))
|
.or(tag("*").map(|_| SlotOperator::Star))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn slotname<'a>() -> impl Parser<&'a str, Output = SlotName> {
|
impl<'a> Parseable<'a, &'a str> for SlotName {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
let start = r#if(|c: &char| c.is_ascii_alphanumeric() || *c == '_');
|
let start = r#if(|c: &char| c.is_ascii_alphanumeric() || *c == '_');
|
||||||
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_.-".contains(*c)).list(0..);
|
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_.-".contains(*c)).list(0..);
|
||||||
|
|
||||||
@@ -107,28 +147,40 @@ pub fn slotname<'a>() -> impl Parser<&'a str, Output = SlotName> {
|
|||||||
.recognize()
|
.recognize()
|
||||||
.map(|output: &str| SlotName(output.to_string()))
|
.map(|output: &str| SlotName(output.to_string()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn slot<'a>() -> impl Parser<&'a str, Output = Slot> {
|
impl<'a> Parseable<'a, &'a str> for Slot {
|
||||||
slotname()
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
SlotName::parser()
|
||||||
.opt()
|
.opt()
|
||||||
.and(slotname().preceded_by(tag("/")).opt())
|
.and(SlotName::parser().preceded_by(tag("/")).opt())
|
||||||
.and(slot_operator().opt())
|
.and(SlotOperator::parser().opt())
|
||||||
.map(|((slot, sub), operator)| Slot {
|
.map(|((slot, sub), operator)| Slot {
|
||||||
slot,
|
slot,
|
||||||
sub,
|
sub,
|
||||||
operator,
|
operator,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn usedep_sign<'a>() -> impl Parser<&'a str, Output = UseDepSign> {
|
impl<'a> Parseable<'a, &'a str> for UseDepSign {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
tag("(-)")
|
tag("(-)")
|
||||||
.map(|_| UseDepSign::Disabled)
|
.map(|_| UseDepSign::Disabled)
|
||||||
.or(tag("(+)").map(|_| UseDepSign::Enabled))
|
.or(tag("(+)").map(|_| UseDepSign::Enabled))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
impl<'a> Parseable<'a, &'a str> for UseDep {
|
||||||
let a = useflag()
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
.and(usedep_sign().opt())
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
let a = UseFlag::parser()
|
||||||
|
.and(UseDepSign::parser().opt())
|
||||||
.preceded_by(tag("-"))
|
.preceded_by(tag("-"))
|
||||||
.map(|(flag, sign)| UseDep {
|
.map(|(flag, sign)| UseDep {
|
||||||
negate: Some(UseDepNegate::Minus),
|
negate: Some(UseDepNegate::Minus),
|
||||||
@@ -137,8 +189,8 @@ pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
|||||||
condition: None,
|
condition: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let b = useflag()
|
let b = UseFlag::parser()
|
||||||
.and(usedep_sign().opt())
|
.and(UseDepSign::parser().opt())
|
||||||
.preceded_by(tag("!"))
|
.preceded_by(tag("!"))
|
||||||
.followed_by(tag("?"))
|
.followed_by(tag("?"))
|
||||||
.map(|(flag, sign)| UseDep {
|
.map(|(flag, sign)| UseDep {
|
||||||
@@ -148,8 +200,8 @@ pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
|||||||
condition: Some(UseDepCondition::Question),
|
condition: Some(UseDepCondition::Question),
|
||||||
});
|
});
|
||||||
|
|
||||||
let c = useflag()
|
let c = UseFlag::parser()
|
||||||
.and(usedep_sign().opt())
|
.and(UseDepSign::parser().opt())
|
||||||
.followed_by(tag("?"))
|
.followed_by(tag("?"))
|
||||||
.map(|(flag, sign)| UseDep {
|
.map(|(flag, sign)| UseDep {
|
||||||
negate: None,
|
negate: None,
|
||||||
@@ -158,8 +210,8 @@ pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
|||||||
condition: Some(UseDepCondition::Question),
|
condition: Some(UseDepCondition::Question),
|
||||||
});
|
});
|
||||||
|
|
||||||
let d = useflag()
|
let d = UseFlag::parser()
|
||||||
.and(usedep_sign().opt())
|
.and(UseDepSign::parser().opt())
|
||||||
.preceded_by(tag("!"))
|
.preceded_by(tag("!"))
|
||||||
.followed_by(tag("="))
|
.followed_by(tag("="))
|
||||||
.map(|(flag, sign)| UseDep {
|
.map(|(flag, sign)| UseDep {
|
||||||
@@ -169,8 +221,8 @@ pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
|||||||
condition: Some(UseDepCondition::Eq),
|
condition: Some(UseDepCondition::Eq),
|
||||||
});
|
});
|
||||||
|
|
||||||
let e = useflag()
|
let e = UseFlag::parser()
|
||||||
.and(usedep_sign().opt())
|
.and(UseDepSign::parser().opt())
|
||||||
.followed_by(tag("="))
|
.followed_by(tag("="))
|
||||||
.map(|(flag, sign)| UseDep {
|
.map(|(flag, sign)| UseDep {
|
||||||
negate: None,
|
negate: None,
|
||||||
@@ -179,8 +231,8 @@ pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
|||||||
condition: Some(UseDepCondition::Eq),
|
condition: Some(UseDepCondition::Eq),
|
||||||
});
|
});
|
||||||
|
|
||||||
let f = useflag()
|
let f = UseFlag::parser()
|
||||||
.and(usedep_sign().opt())
|
.and(UseDepSign::parser().opt())
|
||||||
.map(|(flag, sign)| UseDep {
|
.map(|(flag, sign)| UseDep {
|
||||||
negate: None,
|
negate: None,
|
||||||
flag,
|
flag,
|
||||||
@@ -190,23 +242,28 @@ pub fn usedep<'a>() -> impl Parser<&'a str, Output = UseDep> {
|
|||||||
|
|
||||||
a.or(b).or(c).or(d).or(e).or(f)
|
a.or(b).or(c).or(d).or(e).or(f)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn atom<'a>() -> impl Parser<&'a str, Output = Atom> {
|
impl<'a> Parseable<'a, &'a str> for Atom {
|
||||||
blocker()
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
Blocker::parser()
|
||||||
.opt()
|
.opt()
|
||||||
.and(version_operator().opt())
|
.and(VersionOperator::parser().opt())
|
||||||
.and(category())
|
.and(Category::parser())
|
||||||
.and(name().preceded_by(tag("/")))
|
.and(Name::parser().preceded_by(tag("/")))
|
||||||
.and(version().preceded_by(tag("-")).opt())
|
.and(Version::parser().preceded_by(tag("-")).opt())
|
||||||
.and(slot().preceded_by(tag(":")).opt())
|
.and(Slot::parser().preceded_by(tag(":")).opt())
|
||||||
.and(
|
.and(
|
||||||
usedep()
|
UseDep::parser()
|
||||||
.separated_list(tag(","), 0..)
|
.separated_list(tag(","), 0..)
|
||||||
.delimited_by(tag("["), tag("]"))
|
.delimited_by(tag("["), tag("]"))
|
||||||
.opt(),
|
.opt(),
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
|((((((blocker, version_operator), category), name), version), slot), usedeps)| Atom {
|
|((((((blocker, version_operator), category), name), version), slot), usedeps)| {
|
||||||
|
Atom {
|
||||||
blocker,
|
blocker,
|
||||||
version_operator,
|
version_operator,
|
||||||
category,
|
category,
|
||||||
@@ -214,6 +271,7 @@ pub fn atom<'a>() -> impl Parser<&'a str, Output = Atom> {
|
|||||||
version,
|
version,
|
||||||
slot,
|
slot,
|
||||||
usedeps: usedeps.unwrap_or(Vec::new()),
|
usedeps: usedeps.unwrap_or(Vec::new()),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.verify_output(|atom| match (&atom.version_operator, &atom.version) {
|
.verify_output(|atom| match (&atom.version_operator, &atom.version) {
|
||||||
@@ -230,6 +288,7 @@ pub fn atom<'a>() -> impl Parser<&'a str, Output = Atom> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
@@ -242,14 +301,14 @@ mod test {
|
|||||||
fn test_version() {
|
fn test_version() {
|
||||||
let it = InputIter::new("1.0.0v_alpha1_beta1-r1");
|
let it = InputIter::new("1.0.0v_alpha1_beta1-r1");
|
||||||
|
|
||||||
version().check_finished(it).unwrap();
|
Version::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_name() {
|
fn test_name() {
|
||||||
let it = InputIter::new("foo-1-bar-1.0.0");
|
let it = InputIter::new("foo-1-bar-1.0.0");
|
||||||
|
|
||||||
match name().parse(it) {
|
match Name::parser().parse(it) {
|
||||||
Ok((_, output)) => {
|
Ok((_, output)) => {
|
||||||
assert_eq!(output.0.as_str(), "foo-1-bar");
|
assert_eq!(output.0.as_str(), "foo-1-bar");
|
||||||
}
|
}
|
||||||
@@ -263,7 +322,7 @@ mod test {
|
|||||||
"!!>=cat/pkg-1-foo-1.0.0v_alpha1_p20250326-r1:primary/sub=[use,use=,!use=,use?,!use?,-use,use(+),use(-)]",
|
"!!>=cat/pkg-1-foo-1.0.0v_alpha1_p20250326-r1:primary/sub=[use,use=,!use=,use?,!use?,-use,use(+),use(-)]",
|
||||||
);
|
);
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -272,83 +331,83 @@ mod test {
|
|||||||
"!!>=_.+-0-/_-test-T-123_beta1_-4a-6+-_p--1.00.02b_alpha3_pre_p4-r5:slot/_-+6-9=[test(+),test(-)]",
|
"!!>=_.+-0-/_-test-T-123_beta1_-4a-6+-_p--1.00.02b_alpha3_pre_p4-r5:slot/_-+6-9=[test(+),test(-)]",
|
||||||
);
|
);
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atom_with_star_in_non_empty_slot() {
|
fn test_atom_with_star_in_non_empty_slot() {
|
||||||
let it = InputIter::new("foo/bar:*/subslot");
|
let it = InputIter::new("foo/bar:*/subslot");
|
||||||
|
|
||||||
assert!(atom().check_finished(it).is_err());
|
assert!(Atom::parser().check_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invalid_usedep() {
|
fn test_invalid_usedep() {
|
||||||
let it = InputIter::new("foo-bar:slot/sub=[!use]");
|
let it = InputIter::new("foo-bar:slot/sub=[!use]");
|
||||||
|
|
||||||
assert!(atom().check_finished(it).is_err())
|
assert!(Atom::parser().check_finished(it).is_err())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_slot() {
|
fn test_empty_slot() {
|
||||||
let it = InputIter::new("foo/bar:=");
|
let it = InputIter::new("foo/bar:=");
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_usedep_with_underscore() {
|
fn test_usedep_with_underscore() {
|
||||||
let it = InputIter::new("foo/bar[use_dep]");
|
let it = InputIter::new("foo/bar[use_dep]");
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_version_with_uppercase_letter() {
|
fn test_version_with_uppercase_letter() {
|
||||||
let it = InputIter::new("=foo/bar-1.0.0V");
|
let it = InputIter::new("=foo/bar-1.0.0V");
|
||||||
|
|
||||||
assert!(atom().check_finished(it).is_err());
|
assert!(Atom::parser().check_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_version_with_version_operator_without_version() {
|
fn test_version_with_version_operator_without_version() {
|
||||||
let it = InputIter::new("=foo/bar");
|
let it = InputIter::new("=foo/bar");
|
||||||
|
|
||||||
assert!(atom().check_finished(it).is_err());
|
assert!(Atom::parser().check_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_version_with_version_without_version_operator() {
|
fn test_version_with_version_without_version_operator() {
|
||||||
let it = InputIter::new("foo/bar-1.0.0");
|
let it = InputIter::new("foo/bar-1.0.0");
|
||||||
|
|
||||||
assert!(atom().check_finished(it).is_err());
|
assert!(Atom::parser().check_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atom_with_eq_version_operator() {
|
fn test_atom_with_eq_version_operator() {
|
||||||
let it = InputIter::new("=foo/bar-1.0.0");
|
let it = InputIter::new("=foo/bar-1.0.0");
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atom_with_star_in_version() {
|
fn test_atom_with_star_in_version() {
|
||||||
let it = InputIter::new("=foo/bar-1.2*");
|
let it = InputIter::new("=foo/bar-1.2*");
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atom_with_star_in_version_without_eq_version_operator() {
|
fn test_atom_with_star_in_version_without_eq_version_operator() {
|
||||||
let it = InputIter::new(">=foo/bar-1.2*");
|
let it = InputIter::new(">=foo/bar-1.2*");
|
||||||
|
|
||||||
assert!(atom().check_finished(it).is_err());
|
assert!(Atom::parser().check_finished(it).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_atom_with_trailing_dash_and_letter() {
|
fn test_atom_with_trailing_dash_and_letter() {
|
||||||
let it = InputIter::new("dev-db/mysql-connector-c");
|
let it = InputIter::new("dev-db/mysql-connector-c");
|
||||||
|
|
||||||
atom().check_finished(it).unwrap();
|
Atom::parser().check_finished(it).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,73 @@
|
|||||||
use mon::{Parser, ParserResult, input::InputIter, tag, whitespace1};
|
use mon::{Parser, tag, whitespace1};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
atom,
|
Parseable,
|
||||||
|
atom::Atom,
|
||||||
depend::{Conditional, Expr},
|
depend::{Conditional, Expr},
|
||||||
useflag,
|
useflag::UseFlag,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn expr(it: InputIter<&str>) -> ParserResult<&str, Expr> {
|
impl<'a> Parseable<'a, &'a str> for Expr {
|
||||||
let all_of = expr
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
|it| {
|
||||||
|
let all_of = Expr::parser()
|
||||||
.separated_list(whitespace1(), 1..)
|
.separated_list(whitespace1(), 1..)
|
||||||
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
||||||
.map(|exprs| Expr::AllOf(exprs));
|
.map(|exprs| Expr::AllOf(exprs));
|
||||||
|
|
||||||
let any_of = expr
|
let any_of = Expr::parser()
|
||||||
.separated_list(whitespace1(), 1..)
|
.separated_list(whitespace1(), 1..)
|
||||||
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
||||||
.preceded_by(tag("||").followed_by(whitespace1()))
|
.preceded_by(tag("||").followed_by(whitespace1()))
|
||||||
.map(|exprs| Expr::AnyOf(exprs));
|
.map(|exprs| Expr::AnyOf(exprs));
|
||||||
|
|
||||||
let one_of = expr
|
let one_of = Expr::parser()
|
||||||
.separated_list(whitespace1(), 1..)
|
.separated_list(whitespace1(), 1..)
|
||||||
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
.delimited_by(tag("(").followed_by(whitespace1()), tag(")"))
|
||||||
.preceded_by(tag("^^").followed_by(whitespace1()))
|
.preceded_by(tag("^^").followed_by(whitespace1()))
|
||||||
.map(|exprs| Expr::OneOf(exprs));
|
.map(|exprs| Expr::OneOf(exprs));
|
||||||
|
|
||||||
atom::parsers::atom()
|
Atom::parser()
|
||||||
.map(|atom| Expr::Atom(atom))
|
.map(|atom| Expr::Atom(atom))
|
||||||
.or(conditional().map(|conditional| Expr::Conditional(conditional)))
|
.or(Conditional::parser().map(|conditional| Expr::Conditional(conditional)))
|
||||||
.or(any_of)
|
.or(any_of)
|
||||||
.or(all_of)
|
.or(all_of)
|
||||||
.or(one_of)
|
.or(one_of)
|
||||||
.parse(it)
|
.parse(it)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn conditional<'a>() -> impl Parser<&'a str, Output = Conditional> {
|
impl<'a> Parseable<'a, &'a str> for Conditional {
|
||||||
useflag::parsers::useflag()
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
UseFlag::parser()
|
||||||
.preceded_by(tag("!"))
|
.preceded_by(tag("!"))
|
||||||
.followed_by(tag("?"))
|
.followed_by(tag("?"))
|
||||||
.map(|flag| Conditional::Negative(flag))
|
.map(|flag| Conditional::Negative(flag))
|
||||||
.or(useflag::parsers::useflag()
|
.or(UseFlag::parser()
|
||||||
.followed_by(tag("?"))
|
.followed_by(tag("?"))
|
||||||
.map(|flag| Conditional::Positive(flag)))
|
.map(|flag| Conditional::Positive(flag)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exprs<'a>() -> impl Parser<&'a str, Output = Vec<Expr>> {
|
|
||||||
expr.separated_list(whitespace1(), 0..)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
|
use mon::input::InputIter;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_expr() {
|
fn test_expr() {
|
||||||
let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )");
|
let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )");
|
||||||
|
|
||||||
exprs().check_finished(it).unwrap();
|
Expr::parser()
|
||||||
|
.separated_list(whitespace1(), 0..)
|
||||||
|
.check_finished(it)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
#![deny(clippy::pedantic)]
|
#![deny(clippy::pedantic)]
|
||||||
#![allow(dead_code, unstable_name_collisions)]
|
#![allow(dead_code, unstable_name_collisions)]
|
||||||
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
|
use mon::{Parser, input::Input};
|
||||||
|
|
||||||
|
pub trait Parseable<'a, I: Input + 'a> {
|
||||||
|
type Parser: Parser<I, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser;
|
||||||
|
}
|
||||||
|
|
||||||
pub mod atom;
|
pub mod atom;
|
||||||
pub mod depend;
|
pub mod depend;
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
use mon::{Parser, r#if, tag};
|
use mon::{Parser, r#if, tag};
|
||||||
|
|
||||||
use crate::useflag::{IUseFlag, UseFlag};
|
use crate::{
|
||||||
|
Parseable,
|
||||||
|
useflag::{IUseFlag, UseFlag},
|
||||||
|
};
|
||||||
|
|
||||||
pub fn useflag<'a>() -> impl Parser<&'a str, Output = UseFlag> {
|
impl<'a> Parseable<'a, &'a str> for UseFlag {
|
||||||
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
let start = r#if(|c: &char| c.is_ascii_alphanumeric());
|
let start = r#if(|c: &char| c.is_ascii_alphanumeric());
|
||||||
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_@-".contains(*c)).list(0..);
|
let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_@-".contains(*c)).list(0..);
|
||||||
|
|
||||||
@@ -11,16 +17,21 @@ pub fn useflag<'a>() -> impl Parser<&'a str, Output = UseFlag> {
|
|||||||
.recognize()
|
.recognize()
|
||||||
.map(|output: &str| UseFlag(output.to_string()))
|
.map(|output: &str| UseFlag(output.to_string()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iuseflag<'a>() -> impl Parser<&'a str, Output = IUseFlag> {
|
impl<'a> Parseable<'a, &'a str> for IUseFlag {
|
||||||
useflag()
|
type Parser = impl Parser<&'a str, Output = Self>;
|
||||||
|
|
||||||
|
fn parser() -> Self::Parser {
|
||||||
|
UseFlag::parser()
|
||||||
.preceded_by(tag("+"))
|
.preceded_by(tag("+"))
|
||||||
.map(|flag| IUseFlag {
|
.map(|flag| IUseFlag {
|
||||||
default: true,
|
default: true,
|
||||||
flag,
|
flag,
|
||||||
})
|
})
|
||||||
.or(useflag().map(|flag| IUseFlag {
|
.or(UseFlag::parser().map(|flag| IUseFlag {
|
||||||
default: false,
|
default: false,
|
||||||
flag,
|
flag,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use gentoo_utils::depend;
|
use gentoo_utils::{
|
||||||
use mon::{Parser, eof, input::InputIter, tag};
|
Parseable,
|
||||||
|
depend::{self, Expr},
|
||||||
|
};
|
||||||
|
use mon::{Parser, eof, input::InputIter, tag, whitespace1};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -14,7 +17,8 @@ fn parse_md5_cache() {
|
|||||||
if line.starts_with("DEPEND=") {
|
if line.starts_with("DEPEND=") {
|
||||||
eprintln!("{line}");
|
eprintln!("{line}");
|
||||||
eprintln!();
|
eprintln!();
|
||||||
depend::parsers::exprs()
|
Expr::parser()
|
||||||
|
.separated_list(whitespace1(), 0..)
|
||||||
.ignore()
|
.ignore()
|
||||||
.or(eof())
|
.or(eof())
|
||||||
.preceded_by(tag("DEPEND="))
|
.preceded_by(tag("DEPEND="))
|
||||||
|
|||||||
Reference in New Issue
Block a user