fix bug in code walker causing entire clauses to be skipped (#736)
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user