use super::loop_balance::LoopBalanceMap;
use common::Count;
use peephole::{Statement, Program};
pub trait BoundsAnalysis {
fn new(program: &Program) -> Self;
fn move_left(&mut self, count: Count) -> bool;
fn move_right(&mut self, count: Count) -> bool;
fn check_left(&self, count: Count) -> bool;
fn check_right(&self, count: Count) -> bool;
fn reset_left(&mut self);
fn reset_right(&mut self);
fn enter_loop(&mut self, body: &Box<[Statement]>);
fn leave_loop(&mut self);
}
#[derive(Debug)]
pub struct AbstractInterpreter {
left_mark: usize,
right_mark: usize,
loop_stack: Vec<(usize, usize)>,
loop_balances: LoopBalanceMap,
}
impl BoundsAnalysis for AbstractInterpreter {
fn new(program: &Program) -> Self {
AbstractInterpreter {
left_mark: 0,
right_mark: 0,
loop_stack: Vec::new(),
loop_balances: LoopBalanceMap::new(program),
}
}
fn move_left(&mut self, count: Count) -> bool {
let count = count as usize;
self.right_mark += count;
if count <= self.left_mark {
self.left_mark -= count;
true
} else {
self.left_mark = 0;
false
}
}
fn move_right(&mut self, count: Count) -> bool {
let count = count as usize;
self.left_mark += count;
if count <= self.right_mark {
self.right_mark -= count;
true
} else {
self.right_mark = 0;
false
}
}
fn check_left(&self, count: Count) -> bool {
count <= self.left_mark
}
fn check_right(&self, count: Count) -> bool {
count <= self.right_mark
}
fn reset_left(&mut self) {
self.left_mark = 0;
}
fn reset_right(&mut self) {
self.right_mark = 0;
}
fn enter_loop(&mut self, body: &Box<[Statement]>) {
let balance = self.loop_balances.get(body);
if balance.is_balanced() {
} else if balance.is_right_only() {
self.reset_right();
} else if balance.is_left_only() {
self.reset_left();
} else {
self.reset_left();
self.reset_right();
}
self.loop_stack.push((self.left_mark, self.right_mark));
}
fn leave_loop(&mut self) {
let (left_mark, right_mark) = self.loop_stack.pop()
.expect("got exit_loop without matching enter_loop");
self.left_mark = left_mark;
self.right_mark = right_mark;
}
}
pub struct NoAnalysis;
impl BoundsAnalysis for NoAnalysis {
fn new(_program: &Program) -> Self { NoAnalysis }
fn move_left(&mut self, _count: Count) -> bool { false }
fn move_right(&mut self, _count: Count) -> bool { false }
fn check_left(&self, _count: Count) -> bool { false }
fn check_right(&self, _count: Count) -> bool { false }
fn reset_left(&mut self) { }
fn reset_right(&mut self) { }
fn enter_loop(&mut self, _body: &Box<[Statement]>) { }
fn leave_loop(&mut self) { }
}