1use nom::error::{ErrorKind, ParseError};
2
3use super::*;
4
5impl<'a> AstGroup<'a> {
6 #[inline]
8 pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
9 let (rest, (head, children, important)) =
10 tuple((AstStyle::parse, Self::parse_pair, opt(char('!'))))(input)?;
11 Ok((rest, Self { important: important.is_some(), head, children }))
12 }
13 #[inline]
14 fn parse_pair(input: &'a str) -> IResult<&'a str, Vec<AstGroupItem>> {
15 let (rest, paired) = delimited_paired('(', ')')(input)?;
16 Ok((rest, AstGroupItem::parse_many(paired.trim())?.1))
17 }
18}
19
20impl<'a> AstGroupItem<'a> {
21 #[inline]
23 pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
24 alt((Self::maybe_group, Self::maybe_style))(input)
25 }
26 #[inline]
27 fn parse_many(input: &'a str) -> IResult<&'a str, Vec<Self>> {
28 let head = AstGroupItem::parse;
29 let rest = many0(tuple((multispace1, AstGroupItem::parse)));
30 let (rest, (first, other)) = tuple((head, rest))(input)?;
31 let mut out = vec![first];
32 out.extend(other.into_iter().map(|s| s.1));
33 Ok((rest, out))
34 }
35 fn maybe_group(input: &'a str) -> IResult<&'a str, Self> {
36 let (rest, o) = AstGroup::parse(input)?;
37 Ok((rest, Self::Grouped(o)))
38 }
39 fn maybe_style(input: &'a str) -> IResult<&'a str, Self> {
40 let (rest, o) = AstStyle::parse(input)?;
41 Ok((rest, Self::Styled(o)))
42 }
43}
44
45impl<'a> AstStyle<'a> {
46 #[inline]
48 pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
49 let (rest, (variants, negative, elements, arbitrary, important)) = tuple((
50 many0(ASTVariant::parse),
51 opt(char('-')),
52 opt(AstElements::parse),
53 opt(AstArbitrary::parse),
54 opt(char('!')),
55 ))(input)?;
56
57 Ok((
58 rest,
59 Self {
60 important: important.is_some(),
61 negative: negative.is_some(),
62 variants,
63 elements: elements.unwrap_or_default().elements,
64 arbitrary: arbitrary.map(|s| s.arbitrary),
65 },
66 ))
67 }
68}
69
70impl<'a> AstElements<'a> {
71 #[inline]
73 pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
74 let (rest, (first, other)) = tuple((Self::parse_head, many0(Self::parse_rest)))(input)?;
75 let mut out = vec![first];
76 out.extend(other.into_iter());
77 Ok((rest, Self { elements: out }))
78 }
79 #[inline]
80 fn parse_head(input: &'a str) -> IResult<&'a str, &'a str> {
81 let stop = |c: char| -> bool {
82 matches!(c, ' ' | '\n' | '\r' | '-' | '[' | ']' | '(' | ')')
84 };
85 take_till1(stop)(input)
86 }
87 #[inline]
88 fn parse_rest(input: &'a str) -> IResult<&'a str, &'a str> {
89 let (rest, (_, out)) = tuple((char('-'), Self::parse_head))(input)?;
90 Ok((rest, out))
91 }
92}
93
94impl<'a> ASTVariant<'a> {
95 #[inline]
100 pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
101 let (rest, (mut v, s)) = tuple((Self::parse_one, alt((tag("::"), tag(":")))))(input)?;
102 if s == "::" {
103 v.pseudo = true
104 }
105 else {
106 v.pseudo = Self::check_pseudo(&v.names.iter().map(<_>::as_ref).collect::<Vec<_>>());
107 }
108 Ok((rest, v))
109 }
110 #[inline]
116 fn parse_one(input: &'a str) -> IResult<&'a str, Self> {
117 let not = opt(tuple((tag("not"), tag("-"))));
118 let vs = separated_list0(tag("-"), alphanumeric1);
119 let (rest, (not, names)) = tuple((not, vs))(input)?;
120 Ok((rest, Self { not: not.is_some(), pseudo: false, names }))
121 }
122 #[rustfmt::skip] #[inline]
124 fn check_pseudo(names: &[&str]) -> bool {
125 matches!(names
126 , ["after"]
127 | ["before"]
128 | ["backdrop"]
129 | ["marker"]
130 | ["placeholder"]
131 | ["selection"]
132 | ["first", "line"]
133 | ["first", "litter"]
134 | ["first", "selector", "button"]
135 | ["target", "text"]
136 )
137 }
138}
139
140impl<'a> AstArbitrary<'a> {
141 #[inline]
143 pub fn parse(input: &'a str) -> IResult<&'a str, Self> {
144 let pair = delimited(char('['), take_till1(|c| c == ']'), char(']'));
145 let (rest, (_, arbitrary)) = tuple((char('-'), pair))(input)?;
146 Ok((rest, Self { arbitrary }))
147 }
148}
149
150impl AstReference {
151 #[inline]
153 pub fn parse(input: &str) -> IResult<&str, Self> {
154 let (rest, _) = char('&')(input)?;
155 Ok((rest, Self {}))
156 }
157}
158
159fn delimited_paired(opening: char, closing: char) -> impl Fn(&str) -> IResult<&str, &str> {
160 move |input: &str| {
161 delimited(char(opening), take_until_unbalanced(opening, closing), char(closing))(input)
162 }
163}
164
165fn take_until_unbalanced(
167 opening_bracket: char,
168 closing_bracket: char,
169) -> impl Fn(&str) -> IResult<&str, &str> {
170 move |i: &str| {
171 let mut index = 0;
172 let mut bracket_counter = 0;
173 while let Some(n) = &i[index..].find(&[opening_bracket, closing_bracket, '\\'][..]) {
174 index += n;
175 let mut it = i[index..].chars();
176 match it.next().unwrap_or_default() {
177 c if c == '\\' => {
178 index += '\\'.len_utf8();
180 if let Some(c) = it.next() {
182 index += c.len_utf8();
183 }
184 }
185 c if c == opening_bracket => {
186 bracket_counter += 1;
187 index += opening_bracket.len_utf8();
188 }
189 c if c == closing_bracket => {
190 bracket_counter -= 1;
192 index += closing_bracket.len_utf8();
193 }
194 _ => unreachable!(),
196 };
197 if bracket_counter == -1 {
199 index -= closing_bracket.len_utf8();
201 return Ok((&i[index..], &i[0..index]));
202 };
203 }
204
205 if bracket_counter == 0 {
206 Ok(("", i))
207 }
208 else {
209 Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil)))
210 }
211 }
212}