use chumsky::{prelude::recursive, IterParser, Parser as ChumskyParser};
use crate::{
parser::{
any_quoted_string, close_block, number, open_block, quoted_string, InternalParser,
TokenError, TokenSource,
},
types::Color,
Parser,
};
#[derive(Debug, Clone, PartialEq)]
pub struct VisGroup<'a> {
name: &'a str,
visgroupid: u32,
color: Color,
children: Vec<VisGroup<'a>>,
}
impl<'a> VisGroup<'a> {
pub fn new(
name: &'a str,
visgroupid: u32,
color: Color,
children: Vec<VisGroup<'a>>,
) -> VisGroup<'a> {
VisGroup {
name,
visgroupid,
color,
children,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct VisGroups<'a>(Vec<VisGroup<'a>>);
impl<'a> VisGroups<'a> {
pub fn new(visgroups: Vec<VisGroup<'a>>) -> VisGroups<'a> {
Self(visgroups)
}
}
impl<'src> Parser<'src> for VisGroups<'src> {}
impl<'src> InternalParser<'src> for VisGroups<'src> {
fn parser<I>() -> impl ChumskyParser<'src, I, Self, TokenError<'src>>
where
I: TokenSource<'src>,
{
open_block("visgroups")
.ignore_then(VisGroup::parser::<I>().repeated().collect())
.then_ignore(close_block())
.map(VisGroups::new)
}
}
impl<'src> Parser<'src> for VisGroup<'src> {}
impl<'src> InternalParser<'src> for VisGroup<'src> {
fn parser<I>() -> impl ChumskyParser<'src, I, Self, TokenError<'src>>
where
I: TokenSource<'src>,
{
recursive(|vis_group| {
open_block("visgroup")
.boxed()
.ignore_then(
quoted_string("name")
.boxed()
.ignore_then(any_quoted_string().boxed())
.then_ignore(quoted_string("visgroupid").boxed())
.then(number::<u32, I>().boxed())
.then(Color::parser::<I>().boxed())
.then(vis_group.repeated().collect().boxed()),
)
.then_ignore(close_block().boxed())
.map(|(((name, id), color), children)| VisGroup::new(name, id, color, children))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{parser::util::lex, Parser};
#[test]
fn test_single_visgroup() {
let input = lex(r#"
visgroup {
"name" "Tree_1"
"visgroupid" "5"
"color" "65 45 0"
}
"#);
let parsed = VisGroup::parse(input).unwrap();
assert_eq!(parsed.name, "Tree_1");
assert_eq!(parsed.visgroupid, 5);
assert_eq!(parsed.color.r, 65);
assert_eq!(parsed.color.g, 45);
assert_eq!(parsed.color.b, 0);
assert!(parsed.children.is_empty());
}
#[test]
fn test_nested_visgroup() {
let input = lex(r#"
visgroup {
"name" "Parent"
"visgroupid" "1"
"color" "10 20 30"
visgroup {
"name" "Child"
"visgroupid" "2"
"color" "100 100 100"
}
}
"#);
let parsed = VisGroup::parse(input).unwrap();
assert_eq!(parsed.name, "Parent");
assert_eq!(parsed.children.len(), 1);
assert_eq!(parsed.children[0].name, "Child");
assert_eq!(parsed.children[0].color.r, 100);
}
#[test]
fn test_visgroups_block() {
let input = lex(r#"
visgroups {
visgroup {
"name" "One"
"visgroupid" "11"
"color" "11 22 33"
}
visgroup {
"name" "Two"
"visgroupid" "12"
"color" "44 55 66"
}
}
"#);
let parsed = VisGroups::parse(input).unwrap();
assert_eq!(parsed.0.len(), 2);
assert_eq!(parsed.0[0].name, "One");
assert_eq!(parsed.0[1].name, "Two");
}
#[test]
fn test_empty_visgroups() {
let input = lex(r#"
visgroups {
}
"#);
let parsed = VisGroups::parse(input).unwrap();
assert_eq!(parsed.0.len(), 0);
}
}