diff --git a/src/depend/mod.rs b/src/depend/mod.rs deleted file mode 100644 index 1d85005..0000000 --- a/src/depend/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::useflag::UseFlag; - -pub mod parsers; - -#[derive(Clone, Debug)] -pub enum Conditional { - Negative(UseFlag), - Positive(UseFlag), -} - -#[derive(Clone, Debug)] -pub enum Expr { - Element(T), - AllOf(Vec), - AnyOf(Vec), - OneOf(Vec), - ConditionalGroup(Conditional, Vec), -} diff --git a/src/depend/parsers.rs b/src/depend/parsers.rs deleted file mode 100644 index 975bbe6..0000000 --- a/src/depend/parsers.rs +++ /dev/null @@ -1,86 +0,0 @@ -use mon::{Parser, tag, whitespace1}; - -use crate::{ - Parseable, - depend::{Conditional, Expr}, - useflag::UseFlag, -}; - -impl<'a, T> Parseable<'a, &'a str> for Expr -where - T: Parseable<'a, &'a str>, -{ - type Parser = impl Parser<&'a str, Output = Self>; - - fn parser() -> Self::Parser { - |it| { - let all_of_group = Expr::parser() - .separated_list(whitespace1(), 1..) - .delimited_by(tag("(").followed_by(whitespace1()), tag(")")) - .map(|exprs| Expr::AllOf(exprs)); - - let any_of_group = Expr::parser() - .separated_list(whitespace1(), 1..) - .delimited_by(tag("(").followed_by(whitespace1()), tag(")")) - .preceded_by(tag("||").followed_by(whitespace1())) - .map(|exprs| Expr::AnyOf(exprs)); - - let one_of_group = Expr::parser() - .separated_list(whitespace1(), 1..) - .delimited_by(tag("(").followed_by(whitespace1()), tag(")")) - .preceded_by(tag("^^").followed_by(whitespace1())) - .map(|exprs| Expr::OneOf(exprs)); - - let conditional_group = Conditional::parser() - .followed_by(whitespace1()) - .and( - Expr::parser() - .separated_list(whitespace1(), 1..) - .delimited_by(tag("(").followed_by(whitespace1()), tag(")")), - ) - .map(|(conditional, exprs)| Expr::ConditionalGroup(conditional, exprs)); - - T::parser() - .map(|e| Expr::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(|flag| Conditional::Negative(flag)) - .or(UseFlag::parser() - .followed_by(tag("?")) - .map(|flag| Conditional::Positive(flag))) - } -} - -#[cfg(test)] -mod test { - - use mon::input::InputIter; - - use crate::atom::Atom; - - use super::*; - - #[test] - fn test_expr() { - let it = InputIter::new("flag? ( || ( foo/bar foo/bar ) )"); - - Expr::::parser() - .separated_list(whitespace1(), 0..) - .check_finished(it) - .unwrap(); - } -} diff --git a/src/ebuild/mod.rs b/src/ebuild/mod.rs new file mode 100644 index 0000000..2558cf4 --- /dev/null +++ b/src/ebuild/mod.rs @@ -0,0 +1,57 @@ +use get::Get; +use std::path::PathBuf; + +use crate::{ + atom::{Atom, Name, Slot, Version}, + useflag::{IUseFlag, UseFlag}, +}; + +pub mod parsers; + +#[derive(Clone, Debug)] +pub enum Conditional { + Negative(UseFlag), + Positive(UseFlag), +} + +#[derive(Clone, Debug)] +pub enum Depend { + Element(T), + AllOf(Vec), + AnyOf(Vec), + OneOf(Vec), + ConditionalGroup(Conditional, Vec), +} + +#[derive(Debug, Clone, Get)] +pub struct SrcUri { + uri: String, + file_name: Option, +} + +#[derive(Debug, Clone, Get)] +pub struct License(#[get(method = "get", kind = "deref")] String); + +#[derive(Debug, Clone, Get)] +pub struct Eapi(#[get(method = "get", kind = "deref")] String); + +#[derive(Debug, Clone, Get)] +pub struct Eclass(#[get(method = "get", kind = "deref")] String); + +#[derive(Debug, Clone, Get)] +pub struct Ebuild { + name: Name, + version: Version, + slot: Option, + homepage: Option, + src_uri: Vec>, + eapi: Option, + inherit: Vec, + iuse: Vec, + license: Vec>, + description: Option, + depend: Vec>, + bdepend: Vec>, + rdpened: Vec>, + idepend: Vec>, +} diff --git a/src/ebuild/parsers.rs b/src/ebuild/parsers.rs new file mode 100644 index 0000000..d079609 --- /dev/null +++ b/src/ebuild/parsers.rs @@ -0,0 +1,155 @@ +use std::path::PathBuf; + +use mon::{Parser, alpha1, r#if, tag, whitespace1}; + +use crate::{ + Parseable, + ebuild::{Conditional, Depend, Eapi, License, SrcUri}, + useflag::UseFlag, +}; + +impl<'a> Parseable<'a, &'a str> for SrcUri { + type Parser = impl Parser<&'a str, Output = Self>; + + fn parser() -> Self::Parser { + let protocol = alpha1::<&str>().followed_by(tag("://")); + + let uri = r#if(|c: &char| !c.is_ascii_whitespace()) + .list(1..) + .recognize() + .map(|output: &str| output.to_string()); + + let name = r#if(|c: &char| !c.is_ascii_whitespace()) + .list(1..) + .recognize() + .map(|output: &str| PathBuf::from(output)); + + uri.preceded_by(protocol) + .and( + name.preceded_by(tag("->").delimited_by(whitespace1(), whitespace1())) + .opt(), + ) + .map(|(uri, file_name)| SrcUri { uri, file_name }) + } +} + +impl<'a> Parseable<'a, &'a str> for License { + type Parser = impl Parser<&'a str, Output = Self>; + + fn parser() -> Self::Parser { + let start = r#if(|c: &char| c.is_ascii_alphanumeric() || "_".contains(*c)); + let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_.-".contains(*c)).list(0..); + + 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 = r#if(|c: &char| c.is_ascii_alphanumeric() || "_".contains(*c)); + let rest = r#if(|c: &char| c.is_ascii_alphanumeric() || "+_.-".contains(*c)).list(0..); + + start + .and(rest) + .recognize() + .map(|output: &str| Eapi(output.to_string())) + } +} + +impl<'a, T> Parseable<'a, &'a str> for Depend +where + T: Parseable<'a, &'a str>, +{ + type Parser = impl Parser<&'a str, Output = Self>; + + fn parser() -> Self::Parser { + |it| { + let all_of_group = Depend::parser() + .separated_list(whitespace1(), 1..) + .delimited_by(tag("(").followed_by(whitespace1()), tag(")")) + .map(|exprs| Depend::AllOf(exprs)); + + let any_of_group = Depend::parser() + .separated_list(whitespace1(), 1..) + .delimited_by(tag("(").followed_by(whitespace1()), tag(")")) + .preceded_by(tag("||").followed_by(whitespace1())) + .map(|exprs| Depend::AnyOf(exprs)); + + let one_of_group = Depend::parser() + .separated_list(whitespace1(), 1..) + .delimited_by(tag("(").followed_by(whitespace1()), tag(")")) + .preceded_by(tag("^^").followed_by(whitespace1())) + .map(|exprs| Depend::OneOf(exprs)); + + let conditional_group = Conditional::parser() + .followed_by(whitespace1()) + .and( + Depend::parser() + .separated_list(whitespace1(), 1..) + .delimited_by(tag("(").followed_by(whitespace1()), tag(")")), + ) + .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(|flag| Conditional::Negative(flag)) + .or(UseFlag::parser() + .followed_by(tag("?")) + .map(|flag| Conditional::Positive(flag))) + } +} + +#[cfg(test)] +mod test { + + use mon::input::InputIter; + + use crate::{atom::Atom, 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::::parser() + .separated_list(whitespace1(), 0..) + .check_finished(it) + .unwrap(); + } +} diff --git a/src/lib.rs b/src/lib.rs index ab209e9..fdaf714 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,5 +11,5 @@ pub trait Parseable<'a, I: Input + 'a> { } pub mod atom; -pub mod depend; +pub mod ebuild; pub mod useflag; diff --git a/tests/depend.rs b/tests/depend.rs index 02c59f2..3738854 100644 --- a/tests/depend.rs +++ b/tests/depend.rs @@ -1,8 +1,4 @@ -use gentoo_utils::{ - Parseable, - atom::Atom, - depend::{self, Expr}, -}; +use gentoo_utils::{Parseable, atom::Atom, ebuild::Depend}; use mon::{Parser, eof, input::InputIter, tag, whitespace1}; use std::fs; @@ -18,7 +14,7 @@ fn parse_md5_cache() { if line.starts_with("DEPEND=") { eprintln!("{line}"); eprintln!(); - Expr::::parser() + Depend::::parser() .separated_list(whitespace1(), 0..) .ignore() .or(eof())