forked from gentoo-utils/gentoo-utils
206 lines
5.6 KiB
Rust
206 lines
5.6 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use mon::{
|
|
Parser, ParserIter, ascii_alpha1, ascii_alphanumeric, ascii_whitespace1, r#if, one_of, tag,
|
|
};
|
|
|
|
use crate::{
|
|
Parseable,
|
|
repo::ebuild::{Conditional, Depend, Eapi, Eclass, License, SrcUri, Uri, UriPrefix},
|
|
useflag::UseFlag,
|
|
};
|
|
|
|
impl<'a> Parseable<'a, &'a str> for UriPrefix {
|
|
type Parser = impl Parser<&'a str, Output = Self>;
|
|
|
|
fn parser() -> Self::Parser {
|
|
tag("+mirror")
|
|
.map(|_| UriPrefix::Mirror)
|
|
.or(tag("+fetch").map(|_| UriPrefix::Fetch))
|
|
}
|
|
}
|
|
|
|
impl<'a> Parseable<'a, &'a str> for Uri {
|
|
type Parser = impl Parser<&'a str, Output = Self>;
|
|
|
|
fn parser() -> Self::Parser {
|
|
let protocol = ascii_alpha1::<&str>()
|
|
.followed_by(tag("://"))
|
|
.map(|output: &str| output.to_string());
|
|
let path = r#if(|c: &char| !c.is_ascii_whitespace())
|
|
.repeated()
|
|
.at_least(1)
|
|
.recognize()
|
|
.map(|output: &str| output.to_string());
|
|
|
|
protocol
|
|
.and(path)
|
|
.map(|(protocol, path)| Uri { protocol, path })
|
|
}
|
|
}
|
|
|
|
impl<'a> Parseable<'a, &'a str> for SrcUri {
|
|
type Parser = impl Parser<&'a str, Output = Self>;
|
|
|
|
fn parser() -> Self::Parser {
|
|
let filename = || {
|
|
r#if(|c: &char| !c.is_ascii_whitespace())
|
|
.repeated()
|
|
.at_least(1)
|
|
.recognize()
|
|
.map(|output: &str| PathBuf::from(output))
|
|
};
|
|
|
|
let uri = UriPrefix::parser()
|
|
.opt()
|
|
.and(Uri::parser())
|
|
.and(filename().preceded_by(tag(" -> ")).opt())
|
|
.map(|((prefix, uri), filename)| SrcUri::Uri {
|
|
prefix,
|
|
uri,
|
|
filename,
|
|
});
|
|
|
|
uri.or(filename().map(|path: PathBuf| SrcUri::Filename(path)))
|
|
}
|
|
}
|
|
|
|
impl<'a> Parseable<'a, &'a str> for License {
|
|
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| License(output.to_string()))
|
|
}
|
|
}
|
|
|
|
impl<'a> Parseable<'a, &'a str> for Eapi {
|
|
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| Eapi(output.to_string()))
|
|
}
|
|
}
|
|
|
|
// TODO:
|
|
// Cant find information about eclass names in pms so we allow anything except
|
|
// for whitespace.
|
|
impl<'a> Parseable<'a, &'a str> for Eclass {
|
|
type Parser = impl Parser<&'a str, Output = Self>;
|
|
|
|
fn parser() -> Self::Parser {
|
|
r#if(|c: &char| !c.is_ascii_whitespace())
|
|
.repeated()
|
|
.at_least(1)
|
|
.recognize()
|
|
.map(|output: &str| Eclass(output.to_string()))
|
|
}
|
|
}
|
|
|
|
impl<'a, T> Parseable<'a, &'a str> for Depend<T>
|
|
where
|
|
T: Parseable<'a, &'a str>,
|
|
{
|
|
type Parser = impl Parser<&'a str, Output = Self>;
|
|
|
|
fn parser() -> Self::Parser {
|
|
|it| {
|
|
let exprs = || {
|
|
Depend::parser()
|
|
.separated_by_with_trailing(ascii_whitespace1())
|
|
.at_least(1)
|
|
.delimited_by(tag("(").followed_by(ascii_whitespace1()), tag(")"))
|
|
};
|
|
|
|
let all_of_group = exprs().map(|exprs| Depend::AllOf(exprs));
|
|
|
|
let any_of_group = exprs()
|
|
.preceded_by(tag("||").followed_by(ascii_whitespace1()))
|
|
.map(|exprs| Depend::AnyOf(exprs));
|
|
|
|
let one_of_group = exprs()
|
|
.preceded_by(tag("^^").followed_by(ascii_whitespace1()))
|
|
.map(|exprs| Depend::OneOf(exprs));
|
|
|
|
let conditional_group = Conditional::parser()
|
|
.followed_by(ascii_whitespace1())
|
|
.and(exprs())
|
|
.map(|(conditional, exprs)| Depend::ConditionalGroup(conditional, exprs));
|
|
|
|
T::parser()
|
|
.map(|e| Depend::Element(e))
|
|
.or(conditional_group)
|
|
.or(any_of_group)
|
|
.or(all_of_group)
|
|
.or(one_of_group)
|
|
.parse(it)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Parseable<'a, &'a str> for Conditional {
|
|
type Parser = impl Parser<&'a str, Output = Self>;
|
|
|
|
fn parser() -> Self::Parser {
|
|
UseFlag::parser()
|
|
.preceded_by(tag("!"))
|
|
.followed_by(tag("?"))
|
|
.map(Conditional::Negative)
|
|
.or(UseFlag::parser()
|
|
.followed_by(tag("?"))
|
|
.map(Conditional::Positive))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
|
|
use mon::{ParserIter, input::InputIter};
|
|
|
|
use crate::{atom::Atom, repo::ebuild::Depend};
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_src_uri() {
|
|
let tests = [
|
|
"https://example.com/foo/bar.tar.gz",
|
|
"https://example.com/foo/bar.tar.gz -> bar.tar.gz",
|
|
];
|
|
|
|
for test in tests {
|
|
SrcUri::parser()
|
|
.check_finished(InputIter::new(test))
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_expr() {
|
|
let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )");
|
|
|
|
Depend::<Atom>::parser()
|
|
.separated_by(ascii_whitespace1())
|
|
.many()
|
|
.check_finished(it)
|
|
.unwrap();
|
|
}
|
|
}
|