fix errors emitted by sort and keysort, add tests, add support for Max = -1 to '$skip_max_list'
This commit is contained in:
@@ -6,6 +6,7 @@ use prolog::num::bigint::BigInt;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(super) type MachineError = Vec<HeapCellValue>;
|
||||
pub(super) type MachineStub = Vec<HeapCellValue>;
|
||||
|
||||
// used by '$skip_max_list'.
|
||||
pub(super) enum CycleSearchResult {
|
||||
@@ -19,28 +20,31 @@ pub(super) enum CycleSearchResult {
|
||||
impl MachineState {
|
||||
// see 8.4.3 of Draft Technical Corrigendum 2.
|
||||
pub(super) fn check_sort_errors(&self) -> Result<(), MachineError> {
|
||||
let stub = self.functor_stub(clause_name!("sort"), 2);
|
||||
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()) {
|
||||
match self.detect_cycles(list.clone()) {
|
||||
CycleSearchResult::PartialList(..) =>
|
||||
Err(self.error_form(self.instantiation_error())),
|
||||
Err(self.error_form(self.instantiation_error(), stub.clone())),
|
||||
CycleSearchResult::NotList =>
|
||||
Err(self.error_form(self.type_error(ValidType::List, list))),
|
||||
Err(self.error_form(self.type_error(ValidType::List, list), stub.clone())),
|
||||
_ => Ok(())
|
||||
}?;
|
||||
|
||||
match self.detect_cycles(usize::max_value(), sorted.clone()) {
|
||||
match self.detect_cycles(sorted.clone()) {
|
||||
CycleSearchResult::NotList if !sorted.is_ref() =>
|
||||
Err(self.error_form(self.type_error(ValidType::List, sorted))),
|
||||
Err(self.error_form(self.type_error(ValidType::List, sorted), stub)),
|
||||
_ => Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_list_pairs(&self, list: Addr) -> Result<(), MachineError> {
|
||||
match self.detect_cycles(usize::max_value(), list.clone()) {
|
||||
let stub = self.functor_stub(clause_name!("keysort"), 2);
|
||||
|
||||
match self.detect_cycles(list.clone()) {
|
||||
CycleSearchResult::NotList if !list.is_ref() =>
|
||||
Err(self.error_form(self.type_error(ValidType::List, list))),
|
||||
Err(self.error_form(self.type_error(ValidType::List, list), stub)),
|
||||
_ => {
|
||||
let mut addr = list;
|
||||
|
||||
@@ -55,7 +59,8 @@ impl MachineState {
|
||||
HeapCellValue::Addr(Addr::HeapCell(_)) => break,
|
||||
HeapCellValue::Addr(Addr::StackCell(..)) => break,
|
||||
_ => return Err(self.error_form(self.type_error(ValidType::Pair,
|
||||
Addr::HeapCell(l))))
|
||||
Addr::HeapCell(l)),
|
||||
stub))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,20 +74,26 @@ impl MachineState {
|
||||
|
||||
// see 8.4.4 of Draft Technical Corrigendum 2.
|
||||
pub(super) fn check_keysort_errors(&self) -> Result<(), MachineError> {
|
||||
let stub = self.functor_stub(clause_name!("keysort"), 2);
|
||||
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()) {
|
||||
match self.detect_cycles(pairs.clone()) {
|
||||
CycleSearchResult::PartialList(..) =>
|
||||
Err(self.error_form(self.instantiation_error())),
|
||||
Err(self.error_form(self.instantiation_error(), stub)),
|
||||
CycleSearchResult::NotList =>
|
||||
Err(self.error_form(self.type_error(ValidType::List, pairs))),
|
||||
Err(self.error_form(self.type_error(ValidType::List, pairs), stub)),
|
||||
_ => Ok(())
|
||||
}?;
|
||||
|
||||
self.check_for_list_pairs(sorted)
|
||||
}
|
||||
|
||||
pub(super) fn functor_stub(&self, name: ClauseName, arity: usize) -> MachineStub {
|
||||
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name)));
|
||||
functor!("/", 2, [name, heap_integer!(arity)], Fixity::In)
|
||||
}
|
||||
|
||||
pub(super) fn evaluation_error(&self, eval_error: EvalError) -> MachineError {
|
||||
functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())])
|
||||
}
|
||||
@@ -92,11 +103,10 @@ impl MachineState {
|
||||
}
|
||||
|
||||
pub(super) fn existence_error(&self, name: ClauseName, arity: usize) -> MachineError {
|
||||
let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name)));
|
||||
let h = self.heap.h;
|
||||
|
||||
let mut error = functor!("existence_error", 2, [heap_atom!("procedure"), heap_str!(3 + h)]);
|
||||
error.append(&mut functor!("/", 2, [name, heap_integer!(arity)], Fixity::In));
|
||||
error.append(&mut self.functor_stub(name, arity));
|
||||
|
||||
error
|
||||
}
|
||||
@@ -109,13 +119,16 @@ impl MachineState {
|
||||
functor!("representation_error", 1, [heap_atom!(flag.as_str())])
|
||||
}
|
||||
|
||||
pub(super) fn error_form(&self, mut err: MachineError) -> MachineError {
|
||||
pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineError {
|
||||
let h = self.heap.h;
|
||||
let mut error_form = functor!("error", 2,
|
||||
[HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 2))]);
|
||||
|
||||
error_form.append(&mut err);
|
||||
let mut error_form = vec![HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3 + err.len()))];
|
||||
|
||||
error_form.extend(err.into_iter());
|
||||
error_form.extend(src.into_iter());
|
||||
|
||||
error_form
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user