| 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 { |