From a1bfcf4c9d64a8c28d923b18bd576cb8f58aa3d1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 7 May 2018 22:24:59 -0600 Subject: [PATCH] add system call preliminaries --- src/prolog/machine/system_calls.rs | 162 +++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/prolog/machine/system_calls.rs diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs new file mode 100644 index 00000000..7f0238b2 --- /dev/null +++ b/src/prolog/machine/system_calls.rs @@ -0,0 +1,162 @@ +use prolog::ast::*; +use prolog::machine::machine_errors::*; +use prolog::machine::machine_state::*; +use prolog::num::{ToPrimitive, Zero}; +use prolog::num::bigint::BigInt; + +use std::rc::Rc; + +struct BrentAlgState { + hare: usize, + tortoise: usize, + power: usize, + steps: usize +} + +impl BrentAlgState { + fn new(hare: usize) -> Self { + BrentAlgState { hare, tortoise: hare, power: 2, steps: 1 } + } +} + +impl MachineState { + // a step in Brent's algorithm. + fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option + { + match self.heap[brent_st.hare].clone() { + HeapCellValue::Addr(Addr::Lis(l)) => { + brent_st.hare = l + 1; + brent_st.steps += 1; + + if brent_st.tortoise == brent_st.hare { + return Some(CycleSearchResult::NotList); + } else if brent_st.steps == brent_st.power { + brent_st.tortoise = brent_st.hare; + brent_st.power <<= 1; + } + + None + }, + HeapCellValue::NamedStr(..) => + Some(CycleSearchResult::NotList), + HeapCellValue::Addr(addr) => + match self.store(self.deref(addr)) { + Addr::Con(Constant::EmptyList) => + Some(CycleSearchResult::ProperList(brent_st.steps)), + Addr::HeapCell(_) | Addr::StackCell(..) => + Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)), + _ => + Some(CycleSearchResult::NotList) + } + } + } + + pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult + { + let addr = self.store(self.deref(addr)); + + let mut hare = match addr { + Addr::Lis(offset) if max_steps > 0 => offset + 1, + Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset), + Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, + _ => return CycleSearchResult::NotList + }; + + let mut brent_st = BrentAlgState::new(hare); + + loop { + if brent_st.steps == max_steps { + return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare); + } + + if let Some(result) = self.brents_alg_step(&mut brent_st) { + return result; + } + } + } + + pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult + { + let addr = self.store(self.deref(addr)); + + let mut hare = match addr { + Addr::Lis(offset) => offset + 1, + Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, + _ => return CycleSearchResult::NotList + }; + + let mut brent_st = BrentAlgState::new(hare); + + loop { + if let Some(result) = self.brents_alg_step(&mut brent_st) { + return result; + } + } + } + + fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) { + let target_n = self[temp_v!(1)].clone(); + self.unify(Addr::Con(integer!(n)), target_n); + + if !self.fail { + let xs = self[temp_v!(4)].clone(); + self.unify(addr, xs); + } + } + + pub(super) fn skip_max_list(&mut self) -> Result<(), MachineError> { + let max_steps = self.arith_eval_by_metacall(temp_v!(2))?; + + match max_steps { + Number::Integer(ref max_steps) + if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) => { + let n = self.store(self.deref(self[temp_v!(1)].clone())); + + match n { + Addr::Con(Constant::Number(Number::Integer(ref n))) if n.is_zero() => { + let xs0 = self[temp_v!(3)].clone(); + let xs = self[temp_v!(4)].clone(); + + self.unify(xs0, xs); + }, + _ => { + let search_result = if let Some(max_steps) = max_steps.to_isize() { + if max_steps == -1 { + self.detect_cycles(self[temp_v!(3)].clone()) + } else { + self.detect_cycles_with_max(max_steps as usize, + self[temp_v!(3)].clone()) + } + } else { + self.detect_cycles(self[temp_v!(3)].clone()) + }; + + match search_result { + CycleSearchResult::UntouchedList(l) => + self.finalize_skip_max_list(0, Addr::Lis(l)), + CycleSearchResult::EmptyList => + self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)), + CycleSearchResult::PartialList(n, hc) => + self.finalize_skip_max_list(n, Addr::HeapCell(hc)), + CycleSearchResult::ProperList(n) => + self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)), + CycleSearchResult::NotList => { + let xs0 = self[temp_v!(3)].clone(); + self.finalize_skip_max_list(0, xs0); + } + } + } + } + }, + _ => self.fail = true + }; + + Ok(()) + } + + pub(super) fn execute_system(&mut self, ct: &SystemClauseType) -> Result<(), MachineError> { + match ct { + &SystemClauseType::SkipMaxList => self.skip_max_list() + } + } +} -- 2.54.0