128 lines
4.7 KiB
Rust
128 lines
4.7 KiB
Rust
use prolog::ast::*;
|
|
use prolog::builtins::*;
|
|
use prolog::machine::machine_state::*;
|
|
use prolog::num::bigint::BigInt;
|
|
|
|
use std::rc::Rc;
|
|
|
|
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 {
|
|
// 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 {
|
|
functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())])
|
|
}
|
|
|
|
pub(super) fn type_error(&self, valid_type: ValidType, culprit: Addr) -> MachineError {
|
|
functor!("type_error", 2, [heap_atom!(valid_type.as_str()), HeapCellValue::Addr(culprit)])
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
pub(super) fn instantiation_error(&self) -> MachineError {
|
|
functor!("instantiation_error")
|
|
}
|
|
|
|
pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError {
|
|
functor!("representation_error", 1, [heap_atom!(flag.as_str())])
|
|
}
|
|
|
|
pub(super) fn error_form(&self, mut err: MachineError) -> 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);
|
|
error_form
|
|
}
|
|
|
|
pub(super) fn throw_exception(&mut self, err: MachineError) {
|
|
let h = self.heap.h;
|
|
|
|
self.ball.0 = 0;
|
|
self.ball.1.truncate(0);
|
|
|
|
self.heap.append(err);
|
|
|
|
self.registers[1] = Addr::HeapCell(h);
|
|
self.goto_throw();
|
|
}
|
|
}
|