use crate::instructions::*; use indexmap::IndexSet; fn capture_offset(line: &Line, index: usize, stack: &mut Vec) -> bool { match line { &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => { stack.push(index + offset); } &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) | &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => { stack.push(index + offset); } &Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset))) if offset > 0 => { stack.push(index + offset); } &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))) if offset > 0 => { stack.push(index + offset); } &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => { stack.push(index + offset); } &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => { stack.push(index + offset); return true; } &Line::Control(ControlInstruction::Proceed) | &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => { return true; } &Line::Control(ControlInstruction::RevJmpBy(offset)) => { if offset > 0 { stack.push(index - offset); } else { return true; } } _ => {} }; false } /* This function walks the code of a single predicate, supposed to * begin in code at the offset p. Each instruction is passed to the * walker function. */ pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) { let mut stack = vec![p]; let mut visited_indices = IndexSet::new(); while let Some(first_index) = stack.pop() { if visited_indices.contains(&first_index) { continue; } else { visited_indices.insert(first_index); } for (index, instr) in code[first_index..].iter().enumerate() { walker(instr); if capture_offset(instr, first_index + index, &mut stack) { break; } } } } /* A function for code walking that might result in modification to * the code. Otherwise identical to walk_code. */ /* pub(crate) fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line)) { let mut queue = VecDeque::from(vec![p]); while let Some(first_idx) = queue.pop_front() { let mut last_idx = first_idx; capture_next_range(code, &mut queue, &mut last_idx); for instr in &mut code[first_idx .. last_idx + 1] { walker(instr); } } } */