Comparing addresses of function pointers is brittle.
Functions may be duplicated resulting in function pointers to the same function to compare !=.
Functions may be merged/de-duplicated resulting in function pointers to different function to compare ==.
The later shouldn't be relevant here as the function differ in behavior, but mentioning it for completeness.
}
_ => {
push_cell!(self, heap_loc_as_cell!(h), return);
- (self.bind_fn)(self, Ref::heap_cell(h), value);
+ self.occurs_check.bind(self, Ref::heap_cell(h), value);
}
);
}
push_cell!(self, heap_loc_as_cell!(h), return);
let addr = self.store(self[r]);
- (self.bind_fn)(self, Ref::heap_cell(h), addr);
+ self.occurs_check.bind(self, Ref::heap_cell(h), addr);
// the former code of this match arm was:
let h = self.heap.cell_len();
push_cell!(self, heap_loc_as_cell!(h), return);
- (self.bind_fn)(self, Ref::heap_cell(h), addr);
+ self.occurs_check.bind(self, Ref::heap_cell(h), addr);
self.registers[arg] = heap_loc_as_cell!(h);
}
if stored_v.is_stack_var() {
let h = self.heap.cell_len();
push_cell!(self, heap_loc_as_cell!(h), return);
- (self.bind_fn)(self, Ref::heap_cell(h), stored_v);
+ self.occurs_check.bind(self, Ref::heap_cell(h), stored_v);
} else {
push_cell!(self, stored_v, return);
}
Return,
Continue,
}
+pub(crate) trait OccursCheckImpl {
+ fn flag_value(&self) -> Atom;
+ fn unify(&self, state: &mut MachineState);
+ fn bind(&self, state: &mut MachineState, r: Ref, h: HeapCellValue);
+}
+
+/// Not subject to occurs-check
+pub(crate) struct Nsto;
+
+impl OccursCheckImpl for Nsto {
+ fn flag_value(&self) -> Atom {
+ atom!("false")
+ }
+
+ fn unify(&self, state: &mut MachineState) {
+ state.unify();
+ }
+
+ fn bind(&self, state: &mut MachineState, r: Ref, h: HeapCellValue) {
+ state.bind(r, h);
+ }
+}
+
+/// Subject to occurs-check
+pub(crate) struct Sto;
+
+impl OccursCheckImpl for Sto {
+ fn flag_value(&self) -> Atom {
+ atom!("true")
+ }
+
+ fn unify(&self, state: &mut MachineState) {
+ state.unify_with_occurs_check();
+ }
+
+ fn bind(&self, state: &mut MachineState, r: Ref, h: HeapCellValue) {
+ state.bind_with_occurs_check_wrapper(r, h);
+ }
+}
+
+/// Subject to occurs-check -> error
+pub(crate) struct StoError;
+
+impl OccursCheckImpl for StoError {
+ fn flag_value(&self) -> Atom {
+ atom!("error")
+ }
+
+ fn unify(&self, state: &mut MachineState) {
+ state.unify_with_occurs_check_with_error();
+ }
+
+ fn bind(&self, state: &mut MachineState, r: Ref, h: HeapCellValue) {
+ state.bind_with_occurs_check_with_error_wrapper(r, h);
+ }
+}
pub struct MachineState {
pub atom_tbl: Arc<AtomTable>,
pub(crate) cc: usize,
pub(crate) global_clock: usize,
pub(crate) dynamic_mode: FirstOrNext,
- pub(crate) unify_fn: fn(&mut MachineState),
- pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
+ pub(crate) occurs_check: &'static dyn OccursCheckImpl,
pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
}
.field("cc", &self.cc)
.field("global_clock", &self.global_clock)
.field("dynamic_mode", &self.dynamic_mode)
- .field(
- "unify_fn",
- if self.unify_fn as usize == MachineState::unify as usize {
- &"MachineState::unify"
- } else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
- &"MachineState::unify_with_occurs_check"
- } else {
- &"MachineState::unify_with_occurs_check_with_error"
- },
- )
- .field(
- "bind_fn",
- if self.bind_fn as usize == MachineState::bind as usize {
- &"MachineState::bind"
- } else if self.bind_fn as usize
- == MachineState::bind_with_occurs_check_wrapper as usize
- {
- &"MachineState::bind_with_occurs_check"
- } else {
- &"MachineState::bind_with_occurs_check_with_error_wrapper"
- },
- )
+ .field("unify_fn", &&*self.occurs_check.flag_value().as_str())
+ .field("bind_fn", &&*self.occurs_check.flag_value().as_str())
.finish()
}
}
cc: 0,
global_clock: 0,
dynamic_mode: FirstOrNext::First,
- unify_fn: MachineState::unify,
- bind_fn: MachineState::bind,
+ occurs_check: &Nsto,
run_cleaners_fn: |_| false,
}
}
}
};
- (self.bind_fn)(self, r, f_a);
+ self.occurs_check.bind(self, r, f_a);
Ok(())
}
use crate::machine::system_calls::BrentAlgState;
use crate::types::*;
+trait StepperImpl {
+ fn step<'a>(&self, iter: &mut HeapPStrIter<'a>) -> Option<PStrIteratee>;
+ fn is_cyclic(&self) -> bool;
+}
+
+struct PreCycleDiscoverStepper;
+
+impl StepperImpl for PreCycleDiscoverStepper {
+ fn step<'a>(&self, iter: &mut HeapPStrIter<'a>) -> Option<PStrIteratee> {
+ iter.pre_cycle_discovery_stepper()
+ }
+
+ fn is_cyclic(&self) -> bool {
+ false
+ }
+}
+
+struct PostCycleDiscoverStepper;
+
+impl StepperImpl for PostCycleDiscoverStepper {
+ fn step<'a>(&self, iter: &mut HeapPStrIter<'a>) -> Option<PStrIteratee> {
+ iter.post_cycle_discovery_stepper()
+ }
+
+ fn is_cyclic(&self) -> bool {
+ true
+ }
+}
+
#[derive(Clone, Copy)]
pub struct HeapPStrIter<'a> {
pub heap: &'a Heap,
// pub focus: HeapCellValue,
orig_focus: usize,
brent_st: BrentAlgState,
- stepper: fn(&mut HeapPStrIter<'a>) -> Option<PStrIteratee>,
+ stepper: &'static dyn StepperImpl,
}
struct PStrIterStep {
heap,
orig_focus,
brent_st: BrentAlgState::new(orig_focus),
- stepper: HeapPStrIter::pre_cycle_discovery_stepper,
+ stepper: &PreCycleDiscoverStepper,
}
}
debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic { .. }));
self.walk_hare_to_cycle_end();
- self.stepper = HeapPStrIter::post_cycle_discovery_stepper;
+ self.stepper = &PostCycleDiscoverStepper;
}
None => {
// self.focus = self.heap[next_hare];
}
pub(crate) fn is_cyclic(&self) -> bool {
- self.stepper as usize == Self::post_cycle_discovery_stepper as usize
+ self.stepper.is_cyclic()
}
}
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
- (self.stepper)(self)
+ self.stepper.step(self)
}
}
#[inline(always)]
pub(crate) fn is_sto_enabled(&mut self) {
- if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
- self.machine_st
- .unify_atom(atom!("true"), self.machine_st.registers[1]);
- } else if self.machine_st.unify_fn as usize
- == MachineState::unify_with_occurs_check_with_error as usize
- {
- self.machine_st
- .unify_atom(atom!("error"), self.machine_st.registers[1]);
- } else {
- self.machine_st
- .unify_atom(atom!("false"), self.machine_st.registers[1]);
- }
+ self.machine_st.unify_atom(
+ self.machine_st.occurs_check.flag_value(),
+ self.machine_st.registers[1],
+ );
}
#[inline(always)]
pub(crate) fn set_sto_as_unify(&mut self) {
- self.machine_st.unify_fn = MachineState::unify_with_occurs_check;
- self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper;
+ self.machine_st.occurs_check = &Sto;
}
#[inline(always)]
pub(crate) fn set_nsto_as_unify(&mut self) {
- self.machine_st.unify_fn = MachineState::unify;
- self.machine_st.bind_fn = MachineState::bind;
+ self.machine_st.occurs_check = &Nsto;
}
#[inline(always)]
pub(crate) fn set_sto_with_error_as_unify(&mut self) {
- self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error;
- self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
+ self.machine_st.occurs_check = &StoError;
}
#[inline(always)]
macro_rules! unify_fn {
($machine_st:expr, $($value:expr),*) => {{
$($machine_st.pdl.push($value);)*
- ($machine_st.unify_fn)(&mut $machine_st)
+ $machine_st.occurs_check.unify(&mut $machine_st)
}};
}