fix bug in code walker causing entire clauses to be skipped (#736)

This commit is contained in:
Mark Thom
2020-12-26 22:35:28 -07:00
parent dd07226ab4
commit 01f73b11d8

View File

@@ -2,30 +2,57 @@ use crate::instructions::*;
use std::collections::VecDeque; use std::collections::VecDeque;
fn scan_for_trust_me(code: &Code, jmp_offsets: &mut VecDeque<usize>, after_idx: &mut usize) { fn scan_for_trust_me(
for (idx, instr) in code[*after_idx..].iter().enumerate() { code: &Code,
match instr { jmp_offsets: &mut VecDeque<usize>,
&Line::Choice(ChoiceInstruction::TrustMe) before_idx: usize,
| &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => { after_idx: &mut usize,
*after_idx += idx; ) {
return; // record the location of the line after the TrustMe capping the
// choice instruction sequence to after_idx.
loop {
match &code[*after_idx] {
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) |
&Line::Choice(ChoiceInstruction::RetryMeElse(offset)) |
&Line::IndexedChoice(IndexedChoiceInstruction::Retry(offset)) => {
*after_idx += offset;
} }
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => { &Line::Choice(ChoiceInstruction::DefaultTrustMe) |
jmp_offsets.push_back(*after_idx + idx + offset) &Line::Choice(ChoiceInstruction::TrustMe) |
&Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
break;
}
_ => {
*after_idx += 1;
} }
_ => {}
} }
} }
// search the code in the range for JmpBy instructions and record their
// offsets for future scanning.
for (idx, instr) in code[before_idx .. *after_idx].iter().enumerate() {
match instr {
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
jmp_offsets.push_back(before_idx + idx + offset)
}
_ => {
}
}
}
*after_idx += 1;
} }
fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) { fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
loop { loop {
match &code[*last_idx] { match &code[*last_idx] {
&Line::Choice(ChoiceInstruction::TryMeElse(..)) &Line::Choice(ChoiceInstruction::TryMeElse(offset)) |
| &Line::IndexedChoice(IndexedChoiceInstruction::Try(..)) => { &Line::IndexedChoice(IndexedChoiceInstruction::Try(offset)) => {
*last_idx += 1; let before_idx = *last_idx;
scan_for_trust_me(code, queue, last_idx); *last_idx += offset;
}
scan_for_trust_me(code, queue, before_idx, last_idx);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => { &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
queue.push_back(*last_idx + offset); queue.push_back(*last_idx + offset);
*last_idx += 1; *last_idx += 1;
@@ -34,8 +61,8 @@ fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut u
queue.push_back(*last_idx + offset); queue.push_back(*last_idx + offset);
break; break;
} }
&Line::Control(ControlInstruction::Proceed) &Line::Control(ControlInstruction::Proceed) |
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) =>
break, break,
_ => _ =>
*last_idx += 1, *last_idx += 1,