@@ -19,6 +19,7 @@ pub enum ValidType {
|
|||||||
Integer,
|
Integer,
|
||||||
List,
|
List,
|
||||||
Number,
|
Number,
|
||||||
|
Pair,
|
||||||
PredicateIndicator,
|
PredicateIndicator,
|
||||||
Variable
|
Variable
|
||||||
}
|
}
|
||||||
@@ -38,6 +39,7 @@ impl ValidType {
|
|||||||
ValidType::Integer => "integer",
|
ValidType::Integer => "integer",
|
||||||
ValidType::List => "list",
|
ValidType::List => "list",
|
||||||
ValidType::Number => "number",
|
ValidType::Number => "number",
|
||||||
|
ValidType::Pair => "pair",
|
||||||
ValidType::PredicateIndicator => "predicate_indicator",
|
ValidType::PredicateIndicator => "predicate_indicator",
|
||||||
ValidType::Variable => "variable"
|
ValidType::Variable => "variable"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,76 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
pub(super) type MachineError = Vec<HeapCellValue>;
|
pub(super) type MachineError = Vec<HeapCellValue>;
|
||||||
|
|
||||||
|
// used by '$skip_max_list'.
|
||||||
|
pub(super) enum CycleSearchResult {
|
||||||
|
EmptyList,
|
||||||
|
NotList,
|
||||||
|
PartialList(usize, usize), // the list length (up to max), and an offset into the heap.
|
||||||
|
ProperList(usize), // the list length.
|
||||||
|
UntouchedList(usize) // the address of an uniterated Addr::Lis(address).
|
||||||
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
|
// see 8.4.3 of Draft Technical Corrigendum 2.
|
||||||
|
pub(super) fn check_sort_errors(&self) -> Result<(), MachineError> {
|
||||||
|
let list = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
|
||||||
|
match self.detect_cycles(usize::max_value(), list.clone()) {
|
||||||
|
CycleSearchResult::PartialList(..) =>
|
||||||
|
Err(self.error_form(self.instantiation_error())),
|
||||||
|
CycleSearchResult::NotList =>
|
||||||
|
Err(self.error_form(self.type_error(ValidType::List, list))),
|
||||||
|
_ => Ok(())
|
||||||
|
}?;
|
||||||
|
|
||||||
|
match self.detect_cycles(usize::max_value(), sorted.clone()) {
|
||||||
|
CycleSearchResult::NotList if !sorted.is_ref() =>
|
||||||
|
Err(self.error_form(self.type_error(ValidType::List, sorted))),
|
||||||
|
_ => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see 8.4.4 of Draft Technical Corrigendum 2.
|
||||||
|
pub(super) fn check_keysort_errors(&self) -> Result<(), MachineError> {
|
||||||
|
let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
|
||||||
|
match self.detect_cycles(usize::max_value(), pairs.clone()) {
|
||||||
|
CycleSearchResult::PartialList(..) =>
|
||||||
|
Err(self.error_form(self.instantiation_error())),
|
||||||
|
CycleSearchResult::NotList =>
|
||||||
|
Err(self.error_form(self.type_error(ValidType::List, pairs))),
|
||||||
|
_ => Ok(())
|
||||||
|
}?;
|
||||||
|
|
||||||
|
match self.detect_cycles(usize::max_value(), sorted.clone()) {
|
||||||
|
CycleSearchResult::NotList if !sorted.is_ref() =>
|
||||||
|
Err(self.error_form(self.type_error(ValidType::List, sorted))),
|
||||||
|
_ => {
|
||||||
|
let mut addr = sorted;
|
||||||
|
|
||||||
|
while let Addr::Lis(mut l) = self.store(self.deref(addr)) {
|
||||||
|
loop {
|
||||||
|
match self.heap[l].clone() {
|
||||||
|
HeapCellValue::Addr(Addr::Str(new_l)) => l = new_l,
|
||||||
|
HeapCellValue::NamedStr(2, ref name, Some(Fixity::In))
|
||||||
|
if name.as_str() == "-" => break,
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(_)) => break,
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(..)) => break,
|
||||||
|
_ => return Err(self.error_form(self.type_error(ValidType::Pair,
|
||||||
|
Addr::HeapCell(l))))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = Addr::HeapCell(l + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn evaluation_error(&self, eval_error: EvalError) -> MachineError {
|
pub(super) fn evaluation_error(&self, eval_error: EvalError) -> MachineError {
|
||||||
functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())])
|
functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -486,6 +486,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
&ClauseType::Sort => {
|
&ClauseType::Sort => {
|
||||||
let mut list = machine_st.try_from_list(temp_v!(1))?;
|
let mut list = machine_st.try_from_list(temp_v!(1))?;
|
||||||
|
|
||||||
|
machine_st.check_sort_errors()?;
|
||||||
|
|
||||||
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2));
|
list.sort_unstable_by(|a1, a2| machine_st.compare_term_test(a1, a2));
|
||||||
machine_st.term_dedup(&mut list);
|
machine_st.term_dedup(&mut list);
|
||||||
|
|
||||||
@@ -500,6 +502,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
let mut list = machine_st.try_from_list(temp_v!(1))?;
|
let mut list = machine_st.try_from_list(temp_v!(1))?;
|
||||||
let mut key_pairs = Vec::new();
|
let mut key_pairs = Vec::new();
|
||||||
|
|
||||||
|
machine_st.check_keysort_errors()?;
|
||||||
|
|
||||||
for val in list {
|
for val in list {
|
||||||
let key = machine_st.project_onto_key(val.clone())?;
|
let key = machine_st.project_onto_key(val.clone())?;
|
||||||
key_pairs.push((key, val.clone()));
|
key_pairs.push((key, val.clone()));
|
||||||
|
|||||||
@@ -28,15 +28,6 @@ macro_rules! try_or_fail {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by '$skip_max_list'.
|
|
||||||
enum CycleSearchResult {
|
|
||||||
EmptyList,
|
|
||||||
NotList,
|
|
||||||
PartialList(usize, usize), // the list length (up to max), and an offset into the heap.
|
|
||||||
ProperList(usize), // the list length.
|
|
||||||
UntouchedList(usize) // the address of an uniterated Addr::Lis(address).
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(super) fn new(atom_tbl: TabledData<Atom>) -> MachineState {
|
pub(super) fn new(atom_tbl: TabledData<Atom>) -> MachineState {
|
||||||
MachineState {
|
MachineState {
|
||||||
@@ -1709,12 +1700,6 @@ impl MachineState {
|
|||||||
{
|
{
|
||||||
let a1 = self.store(self.deref(self[r].clone()));
|
let a1 = self.store(self.deref(self[r].clone()));
|
||||||
|
|
||||||
// detect cycles.
|
|
||||||
match self.detect_cycles(usize::max_value(), a1.clone()) {
|
|
||||||
CycleSearchResult::ProperList(_) => {},
|
|
||||||
_ => return Err(functor!("type_error", 2, [heap_atom!("list"), HeapCellValue::Addr(a1)]))
|
|
||||||
};
|
|
||||||
|
|
||||||
match a1.clone() {
|
match a1.clone() {
|
||||||
Addr::Lis(mut l) => {
|
Addr::Lis(mut l) => {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
@@ -1744,21 +1729,24 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide.
|
||||||
pub(super) fn project_onto_key(&self, a: Addr) -> Result<Addr, MachineError> {
|
pub(super) fn project_onto_key(&self, a: Addr) -> Result<Addr, MachineError> {
|
||||||
match self.store(self.deref(a)) {
|
match self.store(self.deref(a)) {
|
||||||
|
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||||
|
Err(self.error_form(self.instantiation_error())),
|
||||||
Addr::Str(s) =>
|
Addr::Str(s) =>
|
||||||
match self.heap[s].clone() {
|
match self.heap[s].clone() {
|
||||||
HeapCellValue::NamedStr(2, ref name, Some(Fixity::In))
|
HeapCellValue::NamedStr(2, ref name, Some(Fixity::In))
|
||||||
if *name == clause_name!("-") =>
|
if *name == clause_name!("-") =>
|
||||||
Ok(Addr::HeapCell(s+1)),
|
Ok(Addr::HeapCell(s+1)),
|
||||||
_ =>
|
_ => Err(self.error_form(self.type_error(ValidType::Pair,
|
||||||
panic!("Addr::Str doesn't point to NamedStr.")
|
self.heap[s].as_addr(s))))
|
||||||
},
|
},
|
||||||
a => Err(self.error_form(self.type_error(ValidType::Callable, a)))
|
a => Err(self.error_form(self.type_error(ValidType::Callable, a)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_cycles(&self, max_steps: usize, addr: Addr) -> CycleSearchResult
|
pub(super) fn detect_cycles(&self, max_steps: usize, addr: Addr) -> CycleSearchResult
|
||||||
{
|
{
|
||||||
let addr = self.store(self.deref(addr));
|
let addr = self.store(self.deref(addr));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user