1#![deny(warnings)]
2use heck::ToPascalCase;
3use proc_macro2::{Span, TokenStream};
4use quote::{ToTokens, TokenStreamExt, format_ident};
5use std::{
6 fmt::Display,
7 ops::{Deref, Range},
8};
9use syn::{
10 Error, Ident, Lit, LitFloat, LitInt, LitStr, Result, Token, braced, bracketed,
11 ext::IdentExt,
12 parenthesized,
13 parse::{Parse, ParseStream},
14 parse2, token,
15};
16
17#[cfg(test)]
18mod test;
19
20pub struct StrWrapped<T: Parse>(pub T);
21impl<T: Parse> Parse for StrWrapped<T> {
22 fn parse(input_raw: ParseStream) -> Result<Self> {
23 Ok(Self(parse2::<T>(
24 input_raw.parse::<LitStr>()?.value().replace("'", "\"").replace("∞", "").parse::<TokenStream>()?,
25 )?))
26 }
27}
28
29#[derive(Debug, PartialEq, Clone)]
30pub enum Def {
31 Ident(DefIdent),
32 Function(DefIdent, Box<Def>),
33 AutoOr(Box<Def>),
34 NoneOr(Box<Def>),
35 AutoNoneOr(Box<Def>),
36 NormalOr(Box<Def>),
37 Type(DefType),
38 StyleValue(DefType),
39 FunctionType(DefType),
40 Optional(Box<Def>), Combinator(Vec<Def>, DefCombinatorStyle),
42 Group(Box<Def>, DefGroupStyle),
43 Multiplier(Box<Def>, DefMultiplierSeparator, DefRange),
44 Punct(char),
45 IntLiteral(i32),
46 DimensionLiteral(f32, String),
47}
48
49#[derive(Debug, PartialEq, Copy, Clone)]
50pub enum DefGroupStyle {
51 None, OneMustOccur, }
54
55#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
56pub enum DefCombinatorStyle {
57 Ordered, AllMustOccur, Options, Alternatives, }
62
63#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
64pub enum DefMultiplierSeparator {
65 None, Commas, }
68
69#[derive(Debug, PartialEq, Clone)]
70pub enum DefRange {
71 None,
72 Range(Range<f32>), RangeFrom(f32), RangeTo(f32), Fixed(f32), }
77
78#[derive(Debug, PartialEq, Clone)]
79pub struct DefIdent(pub String);
80
81#[derive(Debug, PartialEq, Clone)]
82pub struct DefType {
83 pub ident: DefIdent,
84 pub range: DefRange,
85}
86
87impl DefType {
88 pub fn new(str: &str, range: DefRange) -> Self {
89 DefType { ident: DefIdent(str.to_string()), range }
90 }
91
92 pub fn ident_str(&self) -> &str {
93 self.ident.0.as_str()
94 }
95
96 pub fn maybe_unsized(&self) -> bool {
97 matches!(
99 self.ident_str(),
100 "Color" | "Shadow" | "SpreadShadow" | "Image" | "Image1d" | "ContentList" | "ContentAltItem" | "ContentReplacement" | "Counter" | "CounterStyle" | "CursorImage" | "EasingFunction" | "LineWidthOrRepeat" | "LineWidthList" | "AutoLineWidthList" | "GapRuleList" | "GapAutoRuleList" | "FontFamilyName" | "VoiceFamilyName" | "BgImage" | "MaskLayer" | "MaskReference" | "DynamicRangeLimit" | "DynamicRangeLimitMixFunction" | "Outline"
128 | "SingleTransition"
129 | "Symbol" | "TransformList"
131 | "FilterValueList" | "FilterValue" | "FilterFunction" | "BgLayer" | "FinalBgLayer" | "BgPositionAndSize" )
138 }
139}
140
141impl Parse for Def {
142 fn parse(input: ParseStream) -> Result<Self> {
143 let mut root = if input.peek(Token![<]) {
144 input.parse::<Token![<]>()?;
145 let mut style_value = false;
146 let mut function = false;
147 let ident = if input.peek(LitStr) {
148 style_value = true;
149 input.parse::<StrWrapped<DefIdent>>()?.0.0
150 } else {
151 input.parse::<DefIdent>()?.0
152 }
153 .to_pascal_case();
154 let range = if input.peek(token::Bracket) {
155 let content;
156 bracketed!(content in input);
157 content.parse::<DefRange>()?
158 } else {
159 DefRange::None
160 };
161 if input.peek(token::Paren) {
162 let content;
163 parenthesized!(content in input);
164 if !content.is_empty() {
165 Err(Error::new(input.span(), "disallowed content inside deftype function"))?
166 }
167 debug_assert!(!style_value, "Can't be function and style value");
168 function = true;
169 }
170 debug_assert!(!(function && style_value), "Can't be function or style value and or-none");
171 let ty = if let Some(without_auto) = ident.strip_suffix("-or-auto") {
172 Self::AutoOr(Box::new(Def::Type(DefType { ident: DefIdent(without_auto.into()), range })))
173 } else if let Some(without_none) = ident.strip_suffix("-or-none") {
174 Self::NoneOr(Box::new(Def::Type(DefType { ident: DefIdent(without_none.into()), range })))
175 } else if function {
176 Self::FunctionType(DefType { ident: DefIdent(ident), range })
177 } else if style_value {
178 Self::StyleValue(DefType { ident: DefIdent(ident), range })
179 } else {
180 Self::Type(DefType { ident: DefIdent(ident), range })
181 };
182 input.parse::<Token![>]>()?;
183 ty
184 } else if input.peek(token::Bracket) {
185 let content;
186 bracketed!(content in input);
187 let inner = Box::new(content.parse::<Def>()?);
188 if input.peek(Token![!]) {
189 input.parse::<Token![!]>()?;
190 Self::Group(inner, DefGroupStyle::OneMustOccur)
191 } else if input.peek(Token![#]) {
192 input.parse::<Token![#]>()?;
193 Self::Multiplier(inner, DefMultiplierSeparator::Commas, DefRange::RangeFrom(1.))
194 } else if input.peek(Token![+]) {
195 input.parse::<Token![+]>()?;
196 Self::Multiplier(inner, DefMultiplierSeparator::None, DefRange::RangeFrom(1.))
197 } else if input.peek(token::Brace) {
198 let content;
199 braced!(content in input);
200 let range = content.parse::<DefRange>()?;
201 debug_assert!(matches!(range, DefRange::Range(_) | DefRange::Fixed(_)));
202 Self::Multiplier(inner, DefMultiplierSeparator::None, range)
203 } else {
204 Self::Group(inner, DefGroupStyle::None)
205 }
206 } else if input.peek(Ident::peek_any) {
207 let ident = input.parse::<DefIdent>()?;
208 if input.peek(token::Paren) {
209 let content;
210 parenthesized!(content in input);
211 Self::Function(ident, Box::new(content.parse::<Def>()?))
212 } else {
213 Self::Ident(ident)
214 }
215 } else if input.peek(Token![-]) && input.peek2(Ident::peek_any) {
216 input.parse::<Token![-]>()?;
217 let mut ident = input.parse::<DefIdent>()?;
218 ident.0.insert(0, '-');
219 Self::Ident(ident)
220 } else if input.peek(Lit) {
221 let lit = input.parse::<Lit>()?;
222 match lit {
223 Lit::Int(lit) => {
224 if lit.suffix() == "" {
225 Self::IntLiteral(lit.base10_parse::<i32>()?)
226 } else {
227 let unit = lit.suffix();
228 if unit.is_empty() {
229 Err(Error::new(lit.span(), "Invalid dimension unit"))?
230 }
231 Self::DimensionLiteral(lit.base10_parse::<f32>()?, unit.to_string())
232 }
233 }
234 Lit::Char(lit) => Self::Punct(lit.value()),
235 Lit::Str(lit) if lit.value().len() == 1 => Self::Punct(lit.value().chars().next().unwrap()),
236 _ => Err(Error::new(input.span(), "unknown token in Def parse"))?,
237 }
238 } else {
239 input.step(|cursor| {
240 if let Some((p, next)) = cursor.punct() {
241 return Ok((Self::Punct(p.as_char()), next));
242 }
243 Err(Error::new(input.span(), "unknown token in Def parse"))?
244 })?
245 }
246 .optimize();
247 loop {
248 if input.is_empty() {
249 return Ok(root);
250 } else if input.peek(Token![?]) {
251 input.parse::<Token![?]>()?;
252 let inner = root;
253 root = Self::Optional(Box::new(inner.optimize()));
254 } else if input.peek(Token![+])
255 || input.peek(Token![#])
256 || input.peek(token::Brace)
257 || input.peek(Token![*])
258 {
259 let inner = root;
260 let (sep, range) = if input.peek(Token![*]) {
261 input.parse::<Token![*]>()?;
262 (DefMultiplierSeparator::None, DefRange::RangeFrom(0.))
263 } else if input.peek(Token![+]) {
264 input.parse::<Token![+]>()?;
265 (DefMultiplierSeparator::None, DefRange::RangeFrom(1.))
266 } else if input.peek(Token![#]) {
267 input.parse::<Token![#]>()?;
268 let range = if input.peek(token::Brace) {
269 let content;
270 braced!(content in input);
271 content.parse::<DefRange>()?
272 } else if input.peek(Token![?]) {
273 input.parse::<Token![?]>()?;
274 DefRange::RangeFrom(0.)
275 } else {
276 DefRange::RangeFrom(1.)
277 };
278 (DefMultiplierSeparator::Commas, range)
279 } else if input.peek(token::Brace) {
280 let content;
281 braced!(content in input);
282 (DefMultiplierSeparator::None, content.parse::<DefRange>()?)
283 } else {
284 Err(Error::new(input.span(), "Unknown token in DefMultiplierStyle parse!"))?
285 };
286 root = Self::Multiplier(Box::new(inner.optimize()), sep, range).optimize();
287 } else {
288 let style = if input.peek(Token![||]) {
289 input.parse::<Token![||]>()?;
290 DefCombinatorStyle::Options
291 } else if input.peek(Token![|]) {
292 input.parse::<Token![|]>()?;
293 DefCombinatorStyle::Alternatives
294 } else if input.peek(Token![&&]) {
295 input.parse::<Token![&&]>()?;
296 DefCombinatorStyle::AllMustOccur
297 } else {
298 DefCombinatorStyle::Ordered
299 };
300 let mut next = input.parse::<Def>()?;
301 match (&mut root, &mut next) {
302 (_, &mut Self::Combinator(ref mut children, ref s)) if s == &style => {
303 children.insert(0, root);
304 root = next;
305 }
306 (&mut Self::Combinator(ref mut children, ref s), _) if s == &style => {
307 children.push(next);
308 }
309 (_, &mut Self::Combinator(ref mut children, ref other_style)) if &style < other_style => {
310 let options = Self::Combinator(vec![root, children.remove(0)], style);
311 children.insert(0, options);
312 root = next;
313 }
314 (_, Self::Group(inner, DefGroupStyle::None)) => {
315 let children = vec![root, inner.as_ref().clone()];
316 root = Self::Combinator(children, style);
317 }
318 (Self::Group(inner, DefGroupStyle::None), _) => {
319 let children = vec![inner.as_ref().clone(), next];
320 root = Self::Combinator(children, style);
321 }
322 _ => {
323 let children = vec![root, next];
324 root = Self::Combinator(children, style);
325 }
326 }
327 }
328 }
329 }
330}
331
332impl Def {
333 pub fn maybe_unsized(&self) -> bool {
336 match self {
337 Self::Ident(_) | Self::IntLiteral(_) | Self::DimensionLiteral(_, _) | Self::Punct(_) => false,
338 Self::Function(_, inner) => inner.maybe_unsized(),
340 Self::FunctionType(ty) => {
341 matches!(ty.ident_str(), "DynamicRangeLimitMix" | "Param" | "Repeat" | "Attr")
342 }
343 Self::Type(d) => d.maybe_unsized(),
344 Self::StyleValue(ty) => {
345 matches!(
346 ty.ident_str(),
347 "AnimationRangeEnd"
348 | "AnimationRangeStart"
349 | "BorderBlockStart"
350 | "BorderImageSource"
351 | "BorderTopClip" | "BorderTopColor"
352 | "CaretColor" | "ColumnRule"
353 | "ColumnRuleWidth"
354 | "Container" | "ContainerName"
355 | "DynamicRangeLimit"
356 | "EventTriggerName"
357 | "EventTriggerSource"
358 | "ListStyleImage" | "ListStyleType"
359 | "MaskBorderSource"
360 | "OutlineColor" | "PointerTimelineAxis"
361 | "PointerTimelineName"
362 | "PositionTryFallbacks"
363 | "RowRule" | "ScrollTimelineAxis"
364 | "ScrollTimelineName"
365 | "TextDecorationColor"
366 | "TextEmphasisColor"
367 | "TimelineTriggerActivationRange"
368 | "TimelineTriggerActivationRangeEnd"
369 | "TimelineTriggerActivationRangeStart"
370 | "TimelineTriggerActiveRange"
371 | "TimelineTriggerActiveRangeEnd"
372 | "TimelineTriggerActiveRangeStart"
373 | "TimelineTriggerName"
374 | "TimelineTriggerSource"
375 | "ViewTimelineAxis"
376 | "ViewTimelineInset"
377 | "ViewTimelineName"
378 )
379 }
380 Self::AutoOr(d) | Self::NoneOr(d) | Self::AutoNoneOr(d) | Self::NormalOr(d) => d.maybe_unsized(),
381 Self::Optional(d) => d.maybe_unsized(),
382 Self::Combinator(ds, _) => ds.iter().any(|d| d.maybe_unsized()),
383 Self::Group(d, _) => d.maybe_unsized(),
384 Self::Multiplier(inner, sep, range) => {
385 matches!(sep, DefMultiplierSeparator::Commas)
388 || matches!(range, DefRange::RangeFrom(_) | DefRange::RangeTo(_))
389 || inner.maybe_unsized()
390 }
391 }
392 }
393
394 pub fn suggested_data_type(&self) -> DataType {
395 match self {
396 Self::Combinator(_, DefCombinatorStyle::Alternatives) => DataType::Enum,
397 _ => DataType::SingleUnnamedStruct,
398 }
399 }
400
401 pub fn optimize(&self) -> Self {
402 if let Self::Combinator(defs, DefCombinatorStyle::Alternatives) = self {
403 let optimized: Vec<Def> = defs.iter().map(Self::optimize).collect();
404 if optimized.iter().any(|d| matches!(d, Def::Combinator(_, DefCombinatorStyle::Alternatives))) {
405 let flat: Vec<Def> = optimized
406 .into_iter()
407 .flat_map(|d| match d {
408 Def::Combinator(inner, DefCombinatorStyle::Alternatives) => inner,
409 other => vec![other],
410 })
411 .collect();
412 return Self::Combinator(flat, DefCombinatorStyle::Alternatives).optimize();
413 }
414 }
415 match self {
416 Self::Combinator(defs, DefCombinatorStyle::Alternatives)
417 if defs.iter().any(Self::has_distributable_group) =>
418 {
419 let distributed: Vec<Def> =
420 defs.iter()
421 .flat_map(|d| match d {
422 Def::Combinator(
423 children,
424 style @ (DefCombinatorStyle::Ordered | DefCombinatorStyle::AllMustOccur),
425 ) => {
426 if let Some((group_idx, alts, wrap_optional)) =
427 children.iter().enumerate().find_map(|(i, c)| {
428 Self::extract_alternatives(c).map(|(alts, wrap)| (i, alts, wrap))
429 }) {
430 let prefix = &children[..group_idx];
431 let suffix = &children[group_idx + 1..];
432 let mut result: Vec<Def> = alts
433 .iter()
434 .map(|alt| {
435 let mut new_children: Vec<Def> = prefix.to_vec();
436 new_children.push(alt.clone());
437 new_children.extend_from_slice(suffix);
438 Def::Combinator(new_children, *style)
439 })
440 .collect();
441 if wrap_optional {
442 let mut absent: Vec<Def> = prefix.to_vec();
443 absent.extend_from_slice(suffix);
444 match absent.len() {
445 0 => {}
446 1 => {
447 let single = absent.into_iter().next().unwrap();
448 if let Some((alts, _)) = Self::extract_alternatives(&single) {
449 result.extend(alts.iter().cloned());
450 } else {
451 result.push(single);
452 }
453 }
454 _ => result.push(Def::Combinator(absent, *style)),
455 }
456 }
457 result
458 } else {
459 vec![d.clone()]
460 }
461 }
462 _ => vec![d.clone()],
463 })
464 .collect();
465 return Self::Combinator(distributed, DefCombinatorStyle::Alternatives).optimize();
466 }
467
468 Self::Combinator(defs, DefCombinatorStyle::Alternatives) if defs.len() == 2 => {
469 let [first, second] = defs.as_slice() else { panic!("defs.len() was 2!") };
470 match (first, second) {
471 (Def::Ident(DefIdent(ident)), Def::AutoOr(def))
473 | (Def::AutoOr(def), Def::Ident(DefIdent(ident)))
474 if ident == "none" =>
475 {
476 Def::AutoNoneOr(Box::new(*def.clone()))
477 }
478 (Def::Ident(DefIdent(ident)), Def::NoneOr(def))
480 | (Def::NoneOr(def), Def::Ident(DefIdent(ident)))
481 if ident == "auto" =>
482 {
483 Def::AutoNoneOr(Box::new(*def.clone()))
484 }
485 (Def::Ident(DefIdent(ident)), def) | (def, Def::Ident(DefIdent(ident)))
487 if ident == "auto" &&
488 !matches!(def, Def::Ident(_) | Def::AutoOr(_) | Def::NoneOr(_)) =>
490 {
491 Def::AutoOr(Box::new(def.clone()))
492 }
493 (Def::Ident(DefIdent(ident)), def) | (def, Def::Ident(DefIdent(ident)))
495 if ident == "none" &&
496 !matches!(def, Def::Ident(_) | Def::AutoOr(_) | Def::NoneOr(_)) =>
498 {
499 Def::NoneOr(Box::new(def.clone()))
500 }
501 (Def::Ident(DefIdent(ident)), def) | (def, Def::Ident(DefIdent(ident)))
503 if ident == "normal" &&
504 !matches!(def, Def::Ident(_) | Def::AutoOr(_) | Def::NoneOr(_) | Def::NormalOr(_)) =>
506 {
507 Def::NormalOr(Box::new(def.clone()))
508 }
509 (Def::Type(type1), Def::Type(type2)) => match (type1.ident_str(), type2.ident_str()) {
511 ("GapRuleList", "GapAutoRuleList") => {
513 Def::Type(DefType::new("GapRuleList", type1.range.clone()))
514 }
515 ("GapAutoRuleList", "GapRuleList") => {
516 Def::Type(DefType::new("GapRuleList", type2.range.clone()))
517 }
518 ("LengthPercentage", "Flex") | ("Flex", "LengthPercentage") => {
519 Def::Type(DefType::new("LengthPercentageOrFlex", type1.range.clone()))
520 }
521 ("Number", "Percentage") | ("Percentage", "Number") => {
522 Def::Type(DefType::new("NumberPercentage", type1.range.clone()))
523 }
524 ("Number", "Length") | ("Length", "Number") => {
525 Def::Type(DefType::new("NumberLength", type1.range.clone()))
526 }
527 _ => {
528 return Self::Combinator(
529 vec![first.optimize(), second.optimize()],
530 DefCombinatorStyle::Alternatives,
531 );
532 }
533 },
534 _ => {
535 return Self::Combinator(
536 vec![first.optimize(), second.optimize()],
537 DefCombinatorStyle::Alternatives,
538 );
539 }
540 }
541 }
542 Self::Combinator(defs, DefCombinatorStyle::Alternatives) if defs.len() == 3 => {
543 let [first, second, third] = defs.as_slice() else { panic!("defs.len() was 3!") };
544 match (first, second, third) {
545 (def, Def::Ident(DefIdent(first)), Def::Ident(DefIdent(second)))
547 | (Def::Ident(DefIdent(first)), def, Def::Ident(DefIdent(second)))
548 | (Def::Ident(DefIdent(first)), Def::Ident(DefIdent(second)), def)
549 if matches!((first.as_str(), second.as_str()), ("auto", "none") | ("none", "auto")) &&
550 !matches!(def, Def::Ident(_) | Def::AutoOr(_) | Def::NoneOr(_)) =>
552 {
553 Def::AutoNoneOr(Box::new(def.clone()))
554 }
555 (Def::Type(type1), Def::Type(type2), Def::Ident(DefIdent(ident)))
557 | (Def::Ident(DefIdent(ident)), Def::Type(type1), Def::Type(type2))
558 | (Def::Type(type1), Def::Ident(DefIdent(ident)), Def::Type(type2))
559 if ident == "auto" =>
560 {
561 match (type1.ident_str(), type2.ident_str()) {
562 ("Number", "Length") | ("Length", "Number") => {
563 Def::AutoOr(Box::new(Def::Type(DefType::new("NumberLength", type1.range.clone()))))
564 }
565 ("Percentage", "Length") | ("Length", "Percentage") => {
566 Def::AutoOr(Box::new(Def::Type(DefType::new("LengthPercentage", type1.range.clone()))))
567 }
568 ("Number", "Percentage") | ("Percentage", "Number") => {
569 Def::AutoOr(Box::new(Def::Type(DefType::new("NumberPercentage", type1.range.clone()))))
570 }
571 ("LengthPercentage", "Number") | ("Number", "LengthPercentage") => Def::AutoOr(Box::new(
572 Def::Type(DefType::new("LengthPercentageNumber", type1.range.clone())),
573 )),
574 _ => {
575 return Self::Combinator(
576 vec![first.optimize(), second.optimize(), third.optimize()],
577 DefCombinatorStyle::Alternatives,
578 );
579 }
580 }
581 }
582 (def, Def::Type(type1), Def::Type(type2))
585 | (Def::Type(type1), def, Def::Type(type2))
586 | (Def::Type(type1), Def::Type(type2), def) => match (type1.ident_str(), type2.ident_str()) {
587 ("LengthPercentage", "Flex") | ("Flex", "LengthPercentage") => Def::Combinator(
588 vec![
589 def.optimize(),
590 Def::Type(DefType::new("LengthPercentageOrFlex", type1.range.clone())),
591 ],
592 DefCombinatorStyle::Alternatives,
593 ),
594 ("Number", "Percentage") | ("Percentage", "Number") => Def::Combinator(
595 vec![def.optimize(), Def::Type(DefType::new("NumberPercentage", type1.range.clone()))],
596 DefCombinatorStyle::Alternatives,
597 ),
598 ("Number", "Length") | ("Length", "Number") => Def::Combinator(
599 vec![def.optimize(), Def::Type(DefType::new("NumberLength", type1.range.clone()))],
600 DefCombinatorStyle::Alternatives,
601 ),
602 _ => {
603 return Self::Combinator(
604 vec![first.optimize(), second.optimize(), third.optimize()],
605 DefCombinatorStyle::Alternatives,
606 );
607 }
608 },
609 _ => {
610 return Self::Combinator(
611 vec![first.optimize(), second.optimize(), third.optimize()],
612 DefCombinatorStyle::Alternatives,
613 );
614 }
615 }
616 }
617 Self::Combinator(defs, style) => {
618 let optimized: Vec<Def> = defs.iter().map(|d| d.optimize()).collect();
620 let is_repeated_multiplier = {
621 let extractable: Vec<_> = optimized.iter().filter_map(Self::extract_alternatives).collect();
622 extractable.len() == optimized.len() && {
623 let first = extractable[0].0;
624 extractable.iter().all(|(alts, _)| *alts == first)
625 }
626 };
627 if !matches!(style, DefCombinatorStyle::Alternatives)
628 && !is_repeated_multiplier
629 && let Some((group_idx, alts, wrap_optional)) = optimized
630 .iter()
631 .enumerate()
632 .find_map(|(i, c)| Self::extract_distributable(c, *style).map(|(alts, wrap)| (i, alts, wrap)))
633 {
634 let prefix = &optimized[..group_idx];
635 let suffix = &optimized[group_idx + 1..];
636 let mut distributed: Vec<Def> = alts
637 .iter()
638 .map(|alt| {
639 let mut new_children: Vec<Def> = prefix.to_vec();
640 new_children.push(alt.clone());
641 new_children.extend_from_slice(suffix);
642 Def::Combinator(new_children, *style)
643 })
644 .collect();
645 if wrap_optional {
646 let mut absent: Vec<Def> = prefix.to_vec();
647 absent.extend_from_slice(suffix);
648 match absent.len() {
649 0 => {}
650 1 => {
651 let single = absent.into_iter().next().unwrap();
652 if let Some((alts, _)) = Self::extract_alternatives(&single) {
653 distributed.extend(alts.iter().cloned());
654 } else {
655 distributed.push(single);
656 }
657 }
658 _ => distributed.push(Def::Combinator(absent, *style)),
659 }
660 }
661 return Self::Combinator(distributed, DefCombinatorStyle::Alternatives).optimize();
662 }
663 return Self::Combinator(optimized, *style);
664 }
665 Self::Multiplier(inner, DefMultiplierSeparator::None, DefRange::Fixed(i)) => {
668 let opts: Vec<_> = (1..=*i as u32).map(|_| inner.deref().clone()).collect();
669 Self::Combinator(opts, DefCombinatorStyle::Ordered)
670 }
671 Self::Multiplier(inner, DefMultiplierSeparator::None, DefRange::Range(Range { start, end })) => {
674 let opts: Vec<Def> = (1..=*end as i32)
675 .map(|i| if i <= (*start as i32) { inner.deref().clone() } else { Self::Optional(inner.clone()) })
676 .collect();
677 Self::Combinator(opts, DefCombinatorStyle::Ordered)
678 }
679 Self::Multiplier(inner, sep, range) => {
680 return Self::Multiplier(Box::new(inner.optimize()), *sep, range.clone());
681 }
682 Self::Optional(inner) => return Self::Optional(Box::new(inner.optimize())),
683 Self::Group(inner, style) => return Self::Group(Box::new(inner.optimize()), *style),
684 _ => return self.clone(),
685 }
686 .optimize()
687 }
688
689 fn extract_alternatives(def: &Def) -> Option<(&[Def], bool)> {
690 match def {
691 Def::Combinator(alts, DefCombinatorStyle::Alternatives) => Some((alts, false)),
692 Def::Group(inner, _) => {
693 if let Def::Combinator(alts, DefCombinatorStyle::Alternatives) = inner.as_ref() {
694 Some((alts, false))
695 } else {
696 None
697 }
698 }
699 Def::Optional(inner) => {
700 let inner_def = match inner.as_ref() {
701 Def::Group(g, _) => g.as_ref(),
702 other => other,
703 };
704 if let Def::Combinator(alts, DefCombinatorStyle::Alternatives) = inner_def {
705 Some((alts, true))
706 } else {
707 None
708 }
709 }
710 _ => None,
711 }
712 }
713
714 fn extract_distributable(def: &Def, style: DefCombinatorStyle) -> Option<(&[Def], bool)> {
719 Self::extract_alternatives(def).filter(|(alts, _)| {
720 !matches!(style, DefCombinatorStyle::Ordered) || !alts.iter().all(|d| matches!(d, Def::Ident(_)))
721 })
722 }
723
724 fn has_distributable_group(def: &Def) -> bool {
725 match def {
726 Def::Combinator(children, DefCombinatorStyle::Ordered | DefCombinatorStyle::AllMustOccur) => {
727 let extractable: Vec<_> = children.iter().filter_map(Self::extract_alternatives).collect();
728 if extractable.is_empty() {
729 return false;
730 }
731 if extractable.len() == children.len() {
732 let first_alts = extractable[0].0;
733 if extractable.iter().all(|(alts, _)| *alts == first_alts) {
734 return false;
735 }
736 }
737 true
738 }
739 _ => false,
740 }
741 }
742
743 pub fn keyword_prefix_name(&self) -> Option<&str> {
749 let inner = match self {
750 Def::Group(inner, _) => inner.as_ref(),
751 Def::Combinator(_, DefCombinatorStyle::Ordered) => self,
752 _ => return None,
753 };
754 if let Def::Combinator(defs, DefCombinatorStyle::Ordered) = inner
755 && let Some(Def::Optional(first)) = defs.first()
756 && let Def::Ident(DefIdent(name)) = first.as_ref()
757 {
758 return Some(name.as_str());
759 }
760 None
761 }
762}
763
764impl Parse for DefIdent {
765 fn parse(input: ParseStream) -> Result<Self> {
766 let mut str = "".to_owned();
767 let mut last_was_ident = false;
768 loop {
769 if input.peek(Token![>]) || input.peek(token::Bracket) {
770 return Ok(Self(str));
771 } else if input.peek(Ident::peek_any) && !last_was_ident {
772 last_was_ident = true;
773 let ident = input.call(Ident::parse_any)?;
774 str.push_str(&ident.to_string());
775 } else if input.peek(LitInt) && last_was_ident {
777 last_was_ident = true;
778 let int = input.parse::<LitInt>()?;
779 str.push_str(&int.to_string());
780 } else if input.peek(Token![-]) {
781 last_was_ident = false;
782 input.parse::<Token![-]>()?;
783 str.push('-');
784 } else {
785 return Ok(Self(str));
786 }
787 }
788 }
789}
790
791impl Parse for DefRange {
792 fn parse(input: ParseStream) -> Result<Self> {
793 let mut lhs = None;
794 let mut rhs = None;
795 if input.peek(LitFloat) {
796 lhs = Some(input.parse::<LitFloat>()?.base10_parse()?);
797 } else if input.peek(LitInt) {
798 lhs = Some(input.parse::<LitInt>()?.base10_parse::<f32>()?);
799 }
800 if input.peek(Token![,]) {
801 input.parse::<Token![,]>()?;
802 if input.peek(LitFloat) {
803 rhs = Some(input.parse::<LitFloat>()?.base10_parse()?);
804 } else if input.peek(LitInt) {
805 rhs = Some(input.parse::<LitInt>()?.base10_parse::<f32>()?);
806 }
807 } else if let Some(lhs) = lhs {
808 return Ok(Self::Fixed(lhs));
809 }
810 Ok(match (lhs, rhs) {
811 (Some(start), Some(end)) => Self::Range(Range { start, end }),
812 (None, Some(end)) => Self::RangeTo(end),
813 (Some(start), None) => Self::RangeFrom(start),
814 (None, None) => Self::None,
815 })
816 }
817}
818
819pub enum DataType {
820 SingleUnnamedStruct,
821 Enum,
822}
823
824impl DataType {
825 pub fn is_struct(&self) -> bool {
826 matches!(self, Self::SingleUnnamedStruct)
827 }
828
829 pub fn is_enum(&self) -> bool {
830 matches!(self, Self::Enum)
831 }
832}
833
834impl Display for DefIdent {
835 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
836 self.0.fmt(f)
837 }
838}
839
840impl ToTokens for DefIdent {
841 fn to_tokens(&self, tokens: &mut TokenStream) {
842 tokens.append(Ident::new(&self.to_string(), Span::call_site()));
843 }
844}
845
846impl From<DefIdent> for Ident {
847 fn from(value: DefIdent) -> Self {
848 format_ident!("{}", value.0)
849 }
850}
851
852impl From<Ident> for DefIdent {
853 fn from(value: Ident) -> Self {
854 Self(value.to_string())
855 }
856}