blob: 917d39c76434c19034741eeb77a48c798642712f [file] [log] [blame]
use std::mem;
use std::ops::Index;
use std::ops::IndexMut;
use std::usize;
pub(crate) struct Stack {
// program: Arc<ProgramEnvironment>,
entries: Vec<StackEntry>,
overflow_depth: usize,
}
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub(crate) struct StackDepth {
depth: usize,
}
/// The data we actively keep for each goal on the stack.
pub(crate) struct StackEntry {
/// Was this a coinductive goal?
coinductive_goal: bool,
/// Initially false, set to true when some subgoal depends on us.
cycle: bool,
}
impl Stack {
pub(crate) fn new(
// program: &Arc<ProgramEnvironment>,
overflow_depth: usize,
) -> Self {
Stack {
// program: program.clone(),
entries: vec![],
overflow_depth,
}
}
pub(crate) fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub(crate) fn push(&mut self, coinductive_goal: bool) -> StackDepth {
let depth = StackDepth {
depth: self.entries.len(),
};
if depth.depth >= self.overflow_depth {
// This shoudl perhaps be a result or something, though
// really I'd prefer to move to subgoal abstraction for
// guaranteeing termination. -nmatsakis
panic!("overflow depth reached")
}
self.entries.push(StackEntry {
coinductive_goal,
cycle: false,
});
depth
}
pub(crate) fn pop(&mut self, depth: StackDepth) {
assert_eq!(
depth.depth + 1,
self.entries.len(),
"mismatched stack push/pop"
);
self.entries.pop();
}
/// True if all the goals from the top of the stack down to (and
/// including) the given depth are coinductive.
pub(crate) fn coinductive_cycle_from(&self, depth: StackDepth) -> bool {
self.entries[depth.depth..]
.iter()
.all(|entry| entry.coinductive_goal)
}
}
impl StackEntry {
pub(crate) fn flag_cycle(&mut self) {
self.cycle = true;
}
pub(crate) fn read_and_reset_cycle_flag(&mut self) -> bool {
mem::replace(&mut self.cycle, false)
}
}
impl Index<StackDepth> for Stack {
type Output = StackEntry;
fn index(&self, depth: StackDepth) -> &StackEntry {
&self.entries[depth.depth]
}
}
impl IndexMut<StackDepth> for Stack {
fn index_mut(&mut self, depth: StackDepth) -> &mut StackEntry {
&mut self.entries[depth.depth]
}
}