(
&mut self,
expr: &Hir,
greedy: bool,
min: u32,
max: u32,
)
| 587 | } |
| 588 | |
| 589 | fn c_repeat_range( |
| 590 | &mut self, |
| 591 | expr: &Hir, |
| 592 | greedy: bool, |
| 593 | min: u32, |
| 594 | max: u32, |
| 595 | ) -> Result { |
| 596 | let (min, max) = (u32_to_usize(min), u32_to_usize(max)); |
| 597 | let patch_concat = self.c_concat(iter::repeat(expr).take(min))?; |
| 598 | let initial_entry = patch_concat.entry; |
| 599 | if min == max { |
| 600 | return Ok(patch_concat); |
| 601 | } |
| 602 | // It is much simpler to compile, e.g., `a{2,5}` as: |
| 603 | // |
| 604 | // aaa?a?a? |
| 605 | // |
| 606 | // But you end up with a sequence of instructions like this: |
| 607 | // |
| 608 | // 0: 'a' |
| 609 | // 1: 'a', |
| 610 | // 2: split(3, 4) |
| 611 | // 3: 'a' |
| 612 | // 4: split(5, 6) |
| 613 | // 5: 'a' |
| 614 | // 6: split(7, 8) |
| 615 | // 7: 'a' |
| 616 | // 8: MATCH |
| 617 | // |
| 618 | // This is *incredibly* inefficient because the splits end |
| 619 | // up forming a chain, which has to be resolved everything a |
| 620 | // transition is followed. |
| 621 | let mut holes = vec![]; |
| 622 | let mut prev_hole = patch_concat.hole; |
| 623 | for _ in min..max { |
| 624 | self.fill_to_next(prev_hole); |
| 625 | let split = self.push_split_hole(); |
| 626 | let Patch { hole, entry } = self.c(expr)?; |
| 627 | prev_hole = hole; |
| 628 | if greedy { |
| 629 | holes.push(self.fill_split(split, Some(entry), None)); |
| 630 | } else { |
| 631 | holes.push(self.fill_split(split, None, Some(entry))); |
| 632 | } |
| 633 | } |
| 634 | holes.push(prev_hole); |
| 635 | Ok(Patch { hole: Hole::Many(holes), entry: initial_entry }) |
| 636 | } |
| 637 | |
| 638 | fn fill(&mut self, hole: Hole, goto: InstPtr) { |
| 639 | match hole { |
no test coverage detected