1use chumsky::{prelude::recursive, IterParser, Parser as ChumskyParser};
2
3use crate::{
4 impl_block_properties_parser,
5 parser::{close_block, key_value_numeric, open_block, InternalParser, TokenError, TokenSource},
6 types::EditorData,
7 Parser,
8};
9
10#[derive(Debug, Default, Clone)]
11pub struct Group<'src> {
12 pub id: u32,
13 pub editor: Option<EditorData<'src>>,
14 pub groups: Vec<Group<'src>>,
15}
16
17#[derive(Debug, Clone)]
18enum GroupProperty<'src> {
19 Id(u32),
20 Editor(EditorData<'src>),
21 Child(Group<'src>),
22}
23
24impl<'src> Parser<'src> for Group<'src> {}
26
27impl<'src> InternalParser<'src> for Group<'src> {
46 fn parser<I>() -> impl ChumskyParser<'src, I, Self, TokenError<'src>>
47 where
48 I: TokenSource<'src>,
49 {
50 recursive(|group_parser| {
51 impl_block_properties_parser! {
52 property_list: GroupProperty = {
53 p_id = key_value_numeric("id") => GroupProperty::Id,
54 p_editor = EditorData::parser() => GroupProperty::Editor,
55 p_child = group_parser.clone() => GroupProperty::Child,
56 }
57 }
58
59 open_block("group")
60 .boxed()
61 .ignore_then(property_list.repeated().collect::<Vec<GroupProperty>>())
62 .then_ignore(close_block())
63 .map(|properties: Vec<GroupProperty>| {
64 let mut group = Group::default();
65 for prop in properties {
66 match prop {
67 GroupProperty::Id(val) => group.id = val,
68 GroupProperty::Editor(val) => group.editor = Some(val),
69 GroupProperty::Child(val) => group.groups.push(val),
70 }
71 }
72 group
73 })
74 .boxed()
75 })
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::util::lex;
83
84 #[test]
85 fn parse_simple_group() {
86 let input = lex(r#"
87 group
88 {
89 "id" "10"
90 editor
91 {
92 "color" "255 0 0"
93 "visgroupshown" "1"
94 "visgroupautoshown" "1"
95 }
96 }
97 "#);
98
99 let result = Group::parse(input);
100 assert!(result.is_ok(), "Parsing failed: {:?}", result.err());
101 let group = result.unwrap();
102 assert_eq!(group.id, 10);
103 assert!(group.editor.is_some());
104 }
105
106 #[test]
107 fn parse_nested_groups() {
108 let input = lex(r#"
109 group
110 {
111 "id" "100"
112 group
113 {
114 "id" "101"
115 }
116 }
117 "#);
118
119 let result = Group::parse(input);
120 assert!(result.is_ok(), "Parsing failed: {:?}", result.err());
121 let group = result.unwrap();
122 assert_eq!(group.id, 100);
123 assert_eq!(group.groups.len(), 1);
124 assert_eq!(group.groups[0].id, 101);
125 }
126}