From 0dec9883372e470c39ea91a1ed0f11fcb49afced Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 2 May 2018 21:24:43 -0600 Subject: [PATCH] add error handling appartus --- src/prolog/ast.rs | 24 +-- src/prolog/builtins.rs | 94 ++++++++++- src/prolog/io.rs | 34 ++-- src/prolog/machine/machine_errors.rs | 58 +++++++ src/prolog/machine/machine_state_impl.rs | 198 +++++++++++++---------- src/prolog/machine/mod.rs | 15 +- src/prolog/macros.rs | 6 + src/prolog/toplevel.rs | 2 +- src/tests.rs | 27 ++-- 9 files changed, 319 insertions(+), 139 deletions(-) create mode 100644 src/prolog/machine/machine_errors.rs diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index bc5e5620..ad20473f 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -224,7 +224,7 @@ pub trait SubModuleUser { } if !self.import_decl(name, arity, submodule) { - return EvalSession::from(EvalError::ModuleDoesNotContainExport); + return EvalSession::from(SessionError::ModuleDoesNotContainExport); } } @@ -234,7 +234,7 @@ pub trait SubModuleUser { fn use_module(&mut self, submodule: &Module) -> EvalSession { for (name, arity) in submodule.module_decl.exports.iter().cloned() { if !self.import_decl(name, arity, submodule) { - return EvalSession::from(EvalError::ModuleDoesNotContainExport); + return EvalSession::from(SessionError::ModuleDoesNotContainExport); } } @@ -375,7 +375,7 @@ pub struct TempVarData { pub type HeapVarDict = HashMap, Addr>; pub type AllocVarDict = HashMap, VarData>; -pub enum EvalError { +pub enum SessionError { ImpermissibleEntry(String), ModuleDoesNotContainExport, ModuleNotFound, @@ -388,46 +388,46 @@ pub enum EvalError { pub enum EvalSession { EntrySuccess, - Error(EvalError), + Error(SessionError), InitialQuerySuccess(AllocVarDict, HeapVarDict), SubsequentQuerySuccess, } -impl From for EvalSession { - fn from(err: EvalError) -> Self { +impl From for EvalSession { + fn from(err: SessionError) -> Self { EvalSession::Error(err) } } -impl From for EvalError { +impl From for SessionError { fn from(err: ParserError) -> Self { - EvalError::ParserError(err) + SessionError::ParserError(err) } } impl From for EvalSession { fn from(err: ParserError) -> Self { - EvalSession::from(EvalError::ParserError(err)) + EvalSession::from(SessionError::ParserError(err)) } } pub struct OpDecl(pub usize, pub Specifier, pub ClauseName); impl OpDecl { - pub fn submit(&self, module: ClauseName, op_dir: &mut OpDir) -> Result<(), EvalError> + pub fn submit(&self, module: ClauseName, op_dir: &mut OpDir) -> Result<(), SessionError> { let (prec, spec, name) = (self.0, self.1, self.2.clone()); if is_infix!(spec) { match op_dir.get(&(name.clone(), Fixity::Post)) { - Some(_) => return Err(EvalError::OpIsInfixAndPostFix), + Some(_) => return Err(SessionError::OpIsInfixAndPostFix), _ => {} }; } if is_postfix!(spec) { match op_dir.get(&(name.clone(), Fixity::In)) { - Some(_) => return Err(EvalError::OpIsInfixAndPostFix), + Some(_) => return Err(SessionError::OpIsInfixAndPostFix), _ => {} }; } diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 2f5fbc9c..2805148e 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -4,6 +4,92 @@ use prolog::num::bigint::{BigInt}; use std::collections::HashMap; use std::rc::Rc; +// from 7.12.2 b) of 13211-1:1995 +#[derive(Clone, Copy)] +pub enum ValidType { + Atom, + Atomic, + Byte, + Callable, + Character, + Compound, + Evaluable, + InByte, + InCharacter, + Integer, + List, + Number, + PredicateIndicator, + Variable +} + +impl ValidType { + pub fn as_str(self) -> &'static str { + match self { + ValidType::Atom => "atom", + ValidType::Atomic => "atomic", + ValidType::Byte => "byte", + ValidType::Callable => "callable", + ValidType::Character => "character", + ValidType::Compound => "compound", + ValidType::Evaluable => "evaluable", + ValidType::InByte => "in_byte", + ValidType::InCharacter => "in_character", + ValidType::Integer => "integer", + ValidType::List => "list", + ValidType::Number => "number", + ValidType::PredicateIndicator => "predicate_indicator", + ValidType::Variable => "variable" + } + } +} + +// from 7.12.2 f) of 13211-1:1995 +#[derive(Clone, Copy)] +pub enum RepFlag { + Character, + CharacterCode, + InCharacterCode, + MaxArity, + MaxInteger, + MinInteger +} + +impl RepFlag { + pub fn as_str(self) -> &'static str { + match self { + RepFlag::Character => "character", + RepFlag::CharacterCode => "character_code", + RepFlag::InCharacterCode => "in_character_code", + RepFlag::MaxArity => "max_arity", + RepFlag::MaxInteger => "max_integer", + RepFlag::MinInteger => "min_integer" + } + } +} + +// from 7.12.2 g) of 13211-1:1995 +#[derive(Clone, Copy)] +pub enum EvalError { + FloatOverflow, + IntOverflow, + Undefined, + Underflow, + ZeroDivisor +} + +impl EvalError { + pub fn as_str(self) -> &'static str { + match self { + EvalError::FloatOverflow => "float_overflow", + EvalError::IntOverflow => "int_overflow", + EvalError::Undefined => "undefined", + EvalError::Underflow => "underflow", + EvalError::ZeroDivisor => "zero_divisor" + } + } +} + fn get_builtins() -> Code { vec![internal_call_n!(), // callN/N, 0. is_atomic!(temp_v!(1)), // atomic/1, 1. @@ -234,8 +320,12 @@ fn get_builtins() -> Code { goto_execute!(165, 3), // goto get_arg/3, 185. trust_me!(), query![get_var_in_query!(temp_v!(4), 1), - put_structure!("type_error", 1, temp_v!(1), None), - set_constant!(atom!("integer_expected"))], + put_structure!("type_error", 2, temp_v!(2), None), + set_constant!(atom!(ValidType::Integer.as_str())), + set_value!(temp_v!(4)), + put_structure!("error", 2, temp_v!(1), None), + set_value!(temp_v!(2)), + set_void!(1)], goto_execute!(59, 1), // goto throw/1. try_me_else!(5), // arg_/5, 189. fact![get_value!(temp_v!(1), 2), diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 98e6182b..e51635d3 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -259,18 +259,18 @@ impl fmt::Display for IndexingInstruction { } } -impl fmt::Display for EvalError { +impl fmt::Display for SessionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &EvalError::ModuleNotFound => write!(f, "module not found."), - &EvalError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."), - &EvalError::QueryFailure => write!(f, "false."), - &EvalError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)), - &EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite {}.", msg), - &EvalError::OpIsInfixAndPostFix => + &SessionError::ModuleNotFound => write!(f, "module not found."), + &SessionError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."), + &SessionError::QueryFailure => write!(f, "false."), + &SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)), + &SessionError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite {}.", msg), + &SessionError::OpIsInfixAndPostFix => write!(f, "cannot define an op to be both postfix and infix."), - &EvalError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."), - &EvalError::ParserError(ref e) => write!(f, "{:?}", e) + &SessionError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."), + &SessionError::ParserError(ref e) => write!(f, "{:?}", e) } } } @@ -574,7 +574,7 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec) -> EvalSe let name = try_eval_session!(if let Some(name) = tl.name() { Ok(name) } else { - Err(EvalError::NamelessEntry) + Err(SessionError::NamelessEntry) }); let mut code = try_eval_session!(compile_relation(&tl)); @@ -588,7 +588,7 @@ fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec) -> EvalSe if !code.is_empty() { wam.add_user_code(name, tl.arity(), code, tl.as_predicate().ok().unwrap()) } else { - EvalSession::from(EvalError::ImpermissibleEntry(String::from("no code generated."))) + EvalSession::from(SessionError::ImpermissibleEntry(String::from("no code generated."))) } } } @@ -650,7 +650,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession continue; } } else { - return EvalSession::from(EvalError::ModuleNotFound); + return EvalSession::from(SessionError::ModuleNotFound); } wam.use_module_in_toplevel(name); @@ -666,7 +666,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession continue; } } else { - return EvalSession::from(EvalError::ModuleNotFound); + return EvalSession::from(SessionError::ModuleNotFound); } wam.use_qualified_module_in_toplevel(name, exports); @@ -681,7 +681,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession let name = try_eval_session!(if let Some(name) = decl.name() { Ok(name) } else { - Err(EvalError::NamelessEntry) + Err(SessionError::NamelessEntry) }); let module_name = get_module_name(&module); @@ -734,7 +734,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) { } loop { - let mut result = EvalSession::from(EvalError::QueryFailure); + let mut result = EvalSession::from(SessionError::QueryFailure); let mut output = PrinterOutputter::new(); let bindings = wam.heap_view(&heap_locs, output).result(); @@ -763,14 +763,14 @@ pub fn print(wam: &mut Machine, result: EvalSession) { } } - if let &EvalSession::Error(EvalError::QueryFailure) = &result + if let &EvalSession::Error(SessionError::QueryFailure) = &result { write!(stdout, "false.\n\r").unwrap(); stdout.flush().unwrap(); return; } - if let &EvalSession::Error(EvalError::QueryFailureWithException(ref e)) = &result + if let &EvalSession::Error(SessionError::QueryFailureWithException(ref e)) = &result { write!(stdout, "{}\n\r", error_string(e)).unwrap(); stdout.flush().unwrap(); diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs new file mode 100644 index 00000000..08444bda --- /dev/null +++ b/src/prolog/machine/machine_errors.rs @@ -0,0 +1,58 @@ +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; + +impl MachineState { + 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(); + } +} diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 5b6d11d6..12aa099f 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1,8 +1,10 @@ use prolog::and_stack::*; use prolog::ast::*; +use prolog::builtins::*; use prolog::copier::*; use prolog::heap_iter::*; use prolog::heap_print::*; +use prolog::machine::machine_errors::*; use prolog::machine::machine_state::*; use prolog::num::{Integer, Signed, ToPrimitive, Zero}; use prolog::num::bigint::{BigInt, BigUint}; @@ -29,7 +31,7 @@ macro_rules! try_or_fail { // used by '$skip_max_list'. enum CycleSearchResult { EmptyList, - NotList, + 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). @@ -269,7 +271,7 @@ impl MachineState { }; } - fn get_number(&self, at: &ArithmeticTerm) -> Result> { + fn get_number(&self, at: &ArithmeticTerm) -> Result { match at { &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r), &ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()), @@ -277,7 +279,7 @@ impl MachineState { } } - fn get_rational(&self, at: &ArithmeticTerm) -> Result>, Vec> { + fn get_rational(&self, at: &ArithmeticTerm) -> Result>, MachineError> { let n = self.get_number(at)?; match n { @@ -286,7 +288,7 @@ impl MachineState { if let Some(r) = Ratio::from_float(fl.into_inner()) { Ok(Rc::new(r)) } else { - Err(functor!("instantiation_error", 1, [heap_atom!("(is)/2")])) + Err(self.error_form(self.instantiation_error())) }, Number::Integer(bi) => Ok(Rc::new(Ratio::from_integer((*bi).clone()))) @@ -305,9 +307,8 @@ impl MachineState { Rc::new(BigInt::from_signed_bytes_le(&f(&u_n1, &u_n2).to_bytes_le())) } - pub(super) fn arith_eval_by_metacall(&self, r: RegType) -> Result> + pub(super) fn arith_eval_by_metacall(&self, r: RegType) -> Result { - let instantiation_err = functor!("instantiation_error", 1, [heap_atom!("(is)/2")]); let a = self[r].clone(); let mut interms: Vec = Vec::with_capacity(64); @@ -338,7 +339,7 @@ impl MachineState { "xor" => interms.push(Number::Integer(self.xor(a1, a2)?)), "mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)), "rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)), - _ => return Err(instantiation_err) + _ => return Err(self.error_form(self.instantiation_error())) } }, HeapCellValue::NamedStr(1, name, Some(Fixity::Pre)) => { @@ -346,13 +347,13 @@ impl MachineState { match name.as_str() { "-" => interms.push(- a1), - _ => return Err(instantiation_err) + _ => return Err(self.error_form(self.instantiation_error())) } }, HeapCellValue::Addr(Addr::Con(Constant::Number(n))) => interms.push(n), _ => - return Err(instantiation_err) + return Err(self.error_form(self.instantiation_error())) } }; @@ -360,52 +361,61 @@ impl MachineState { } fn rdiv(&self, r1: Rc>, r2: Rc>) - -> Result>, Vec> + -> Result>, MachineError> { if *r2 == Ratio::zero() { - Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) + Err(self.error_form(self.evaluation_error(EvalError::ZeroDivisor))) } else { Ok(Rc::new(&*r1 / &*r2)) } } - fn fidiv(&self, n1: Number, n2: Number) -> Result, Vec> + fn fidiv(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) + Err(self.error_form(self.evaluation_error(EvalError::ZeroDivisor))) } else { Ok(Rc::new(n1.div_floor(&n2))) }, - _ => Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn idiv(&self, n1: Number, n2: Number) -> Result, Vec> + fn idiv(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) + Err(self.error_form(self.evaluation_error(EvalError::ZeroDivisor))) } else { Ok(Rc::new(&*n1 / &*n2)) }, - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn div(&self, n1: Number, n2: Number) -> Result> + fn div(&self, n1: Number, n2: Number) -> Result { if n2.is_zero() { - Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) + Err(self.error_form(self.evaluation_error(EvalError::ZeroDivisor))) } else { Ok(n1 / n2) } } - fn shr(&self, n1: Number, n2: Number) -> Result, Vec> + fn shr(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => @@ -413,12 +423,16 @@ impl MachineState { Some(n2) => Ok(Rc::new(&*n1 >> n2)), _ => Ok(Rc::new(&*n1 >> usize::max_value())) }, - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn shl(&self, n1: Number, n2: Number) -> Result, Vec> + fn shl(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => @@ -426,66 +440,90 @@ impl MachineState { Some(n2) => Ok(Rc::new(&*n1 << n2)), _ => Ok(Rc::new(&*n1 << usize::max_value())) }, - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn xor(&self, n1: Number, n2: Number) -> Result, Vec> + fn xor(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 ^ u_n2)), - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn and(&self, n1: Number, n2: Number) -> Result, Vec> + fn and(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn modulus(&self, n1: Number, n2: Number) -> Result, Vec> + fn modulus(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) + Err(self.error_form(self.evaluation_error(EvalError::ZeroDivisor))) } else { Ok(Rc::new(n1.mod_floor(&n2))) }, - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn remainder(&self, n1: Number, n2: Number) -> Result, Vec> + fn remainder(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => if *n2 == BigInt::zero() { - Err(functor!("evaluation_error", 1, [heap_atom!("zero_divisor")])) + Err(self.error_form(self.evaluation_error(EvalError::ZeroDivisor))) } else { Ok(Rc::new(&*n1 % &*n2)) }, - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } - fn or(&self, n1: Number, n2: Number) -> Result, Vec> + fn or(&self, n1: Number, n2: Number) -> Result, MachineError> { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => - Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), - _ => - Err(functor!("evaluation_error", 1, [heap_atom!("expected_integer_args")])) + Ok(self.signed_bitwise_op(&*n1, &*n2, |u_n1, u_n2| u_n1 & u_n2)), + (Number::Integer(_), n2) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n2))))), + (n1, _) => + Err(self.error_form(self.type_error(ValidType::Integer, + Addr::Con(Constant::Number(n1))))) } } @@ -941,28 +979,6 @@ impl MachineState { self.fail = true; } - fn throw_exception(&mut self, hcv: Vec) { - let h = self.heap.h; - - self.ball.0 = 0; - self.ball.1.truncate(0); - - self.registers[1] = Addr::HeapCell(h); - - self.heap.append(hcv); - self.goto_throw(); - } - - pub(super) fn existence_error(&self, name: ClauseName, arity: usize) -> Vec { - 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 setup_call_n(&mut self, arity: usize) -> Option { let addr = self.store(self.deref(self.registers[arity].clone())); @@ -973,8 +989,11 @@ impl MachineState { if let HeapCellValue::NamedStr(narity, name, _) = result { if narity + arity > 63 { - self.throw_exception(functor!("representation_error", 1, - [heap_atom!("exceeds_max_arity")])); + let representation_error = + self.error_form(self.representation_error(RepFlag::MaxArity)); + + self.throw_exception(representation_error); + return None; } @@ -994,13 +1013,15 @@ impl MachineState { }, Addr::Con(Constant::Atom(name)) => (name, 0), Addr::HeapCell(_) | Addr::StackCell(_, _) => { - self.throw_exception(functor!("instantiation_error")); + let instantiation_error = self.error_form(self.instantiation_error()); + self.throw_exception(instantiation_error); + return None; }, _ => { - self.throw_exception(functor!("type_error", 2, - [heap_atom!("callable"), - HeapCellValue::Addr(addr)])); + let type_error = self.error_form(self.type_error(ValidType::Callable, addr)); + self.throw_exception(type_error); + return None; } }; @@ -1054,7 +1075,7 @@ impl MachineState { fail } - fn try_get_arg(&mut self) -> Result<(), Vec> + fn try_get_arg(&mut self) -> Result<(), MachineError> { let a1 = self.store(self.deref(self[temp_v!(1)].clone())); @@ -1076,7 +1097,7 @@ impl MachineState { _ => self.fail = true }; } else { - return Err(functor!("type_error", 1, [heap_atom!("compound_expected")])) + return Err(self.error_form(self.type_error(ValidType::Compound, a2))); } } @@ -1447,7 +1468,7 @@ impl MachineState { self.p += 1; - match (a1, a2) { + match (a1, a2.clone()) { (Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Number(Number::Integer(n)))) => match call_policy.downcast_mut::().ok() { @@ -1458,7 +1479,10 @@ impl MachineState { None => panic!("install_inference_counter: should have installed \\ CallWithInferenceLimitCallPolicy.") }, - _ => self.throw_exception(functor!("type_error", 1, [heap_atom!("integer_expected")])) + _ => { + let type_error = self.error_form(self.type_error(ValidType::Integer, a2)); + self.throw_exception(type_error) + } }; }, &BuiltInInstruction::RemoveCallPolicyCheck => { @@ -1582,7 +1606,7 @@ impl MachineState { }; } - pub(super) fn try_functor(&mut self) -> Result<(), Vec> { + pub(super) fn try_functor(&mut self) -> Result<(), MachineError> { let a1 = self.store(self.deref(self[temp_v!(1)].clone())); match a1.clone() { @@ -1631,10 +1655,10 @@ impl MachineState { self.unify(a1, f_a); } else { - return Err(functor!("instantiation_error")); + return Err(self.error_form(self.instantiation_error())); } } else { - return Err(functor!("instantiation_error")); + return Err(self.error_form(self.instantiation_error())); } }, _ => { @@ -1681,7 +1705,7 @@ impl MachineState { head_addr } - pub(super) fn try_from_list(&self, r: RegType) -> Result, Vec> + pub(super) fn try_from_list(&self, r: RegType) -> Result, MachineError> { let a1 = self.store(self.deref(self[r].clone())); @@ -1707,20 +1731,20 @@ impl MachineState { HeapCellValue::Addr(Addr::Con(Constant::EmptyList)) => break, hcv => - return Err(functor!("type_error", 2, [heap_atom!("list"), hcv])) + return Err(self.type_error(ValidType::List, hcv.as_addr(l))) }; } Ok(result) }, Addr::HeapCell(_) | Addr::StackCell(..) => - Err(functor!("instantiation_error")), + Err(self.error_form(self.instantiation_error())), addr => - Err(functor!("type_error", 2, [heap_atom!("list"), HeapCellValue::Addr(addr)])) + Err(self.error_form(self.type_error(ValidType::List, addr))) } } - pub(super) fn project_onto_key(&self, a: Addr) -> Result> { + pub(super) fn project_onto_key(&self, a: Addr) -> Result { match self.store(self.deref(a)) { Addr::Str(s) => match self.heap[s].clone() { @@ -1730,7 +1754,7 @@ impl MachineState { _ => panic!("Addr::Str doesn't point to NamedStr.") }, - a => Err(functor!("type_error", 2, [heap_atom!("callable"), HeapCellValue::Addr(a)])) + a => Err(self.error_form(self.type_error(ValidType::Callable, a))) } } @@ -1783,7 +1807,7 @@ impl MachineState { self.unify(addr, xs); } } - + pub(super) fn skip_max_list(&mut self) { let max = self.store(self.deref(self[temp_v!(2)].clone())); diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index eeb9532d..ad07beb1 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -3,6 +3,7 @@ use prolog::builtins::*; use prolog::heap_print::*; use prolog::tabled_rc::*; +mod machine_errors; pub(crate) mod machine_state; #[macro_use] mod machine_state_impl; @@ -150,7 +151,7 @@ impl Machine { indices.use_qualified_module(module, &exports) }, - None => EvalSession::from(EvalError::ModuleNotFound) + None => EvalSession::from(SessionError::ModuleNotFound) } } @@ -164,7 +165,7 @@ impl Machine { indices.use_module(module) }, - None => EvalSession::from(EvalError::ModuleNotFound) + None => EvalSession::from(SessionError::ModuleNotFound) } } @@ -191,7 +192,7 @@ impl Machine { { match self.code_dir.get(&(name.clone(), arity)) { Some(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") => - return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", + return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}", name, arity))), _ => {} @@ -380,9 +381,9 @@ impl Machine { PrinterOutputter::new()) .result(); - EvalSession::from(EvalError::QueryFailureWithException(msg)) + EvalSession::from(SessionError::QueryFailureWithException(msg)) } else { - EvalSession::from(EvalError::QueryFailure) + EvalSession::from(SessionError::QueryFailure) } } @@ -407,7 +408,7 @@ impl Machine { self.ms.p = self.ms.or_stack[b].bp.clone(); if let CodePtr::TopLevel(_, 0) = self.ms.p { - return EvalSession::from(EvalError::QueryFailure); + return EvalSession::from(SessionError::QueryFailure); } self.run_query(alloc_l, heap_l); @@ -418,7 +419,7 @@ impl Machine { EvalSession::SubsequentQuerySuccess } } else { - EvalSession::from(EvalError::QueryFailure) + EvalSession::from(SessionError::QueryFailure) } } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 2cd018bc..aff35e35 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -119,6 +119,12 @@ macro_rules! get_value { ) } +macro_rules! set_void { + ($n:expr) => ( + QueryInstruction::SetVoid($n) + ) +} + macro_rules! set_value { ($r:expr) => ( QueryInstruction::SetValue($r) diff --git a/src/prolog/toplevel.rs b/src/prolog/toplevel.rs index dad3e158..10cab7db 100644 --- a/src/prolog/toplevel.rs +++ b/src/prolog/toplevel.rs @@ -568,7 +568,7 @@ impl TopLevelWorker { TopLevelWorker { parser: Parser::new(inner, atom_tbl) } } - pub fn parse_batch(&mut self, op_dir: &mut OpDir) -> Result, EvalError> + pub fn parse_batch(&mut self, op_dir: &mut OpDir) -> Result, SessionError> { let mut preds = vec![]; let mut mod_name = clause_name!("user"); diff --git a/src/tests.rs b/src/tests.rs index 4066300e..ad0d5e74 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1067,17 +1067,17 @@ fn test_queries_on_arithmetic() submit(&mut wam, "f(X) :- X is 5 // 0."); - assert_prolog_success!(&mut wam, "?- catch(f(X), evaluation_error(E), true), E = zero_divisor.", + assert_prolog_success!(&mut wam, "?- catch(f(X), error(evaluation_error(E), _), true), E = zero_divisor.", [["E = zero_divisor", "X = _1"]]); submit(&mut wam, "f(X) :- X is (5 rdiv 1) / 0."); - assert_prolog_success!(&mut wam, "?- catch(f(X), evaluation_error(E), true), E = zero_divisor.", + assert_prolog_success!(&mut wam, "?- catch(f(X), error(evaluation_error(E), _), true), E = zero_divisor.", [["E = zero_divisor", "X = _1"]]); submit(&mut wam, "f(X) :- X is 5.0 / 0."); - assert_prolog_success!(&mut wam, "?- catch(f(X), evaluation_error(E), true), E = zero_divisor.", + assert_prolog_success!(&mut wam, "?- catch(f(X), error(evaluation_error(E), _), true), E = zero_divisor.", [["E = zero_divisor", "X = _1"]]); assert_prolog_success!(&mut wam, "?- X is ((3 + 4) // 2) + 2 - 1 // 1, Y is 2+2, Z is X+Y.", @@ -1108,7 +1108,7 @@ fn test_queries_on_arithmetic() assert_prolog_success!(&mut wam, "?- X is 3 + 3, call(<, 3, X).", [["X = 6"]]); assert_prolog_success!(&mut wam, "?- X is 3 + 3, X =:= 3 + 3.", [["X = 6"]]); - assert_prolog_success!(&mut wam, "?- catch(call(is, X, 3 // 0), E, true).", + assert_prolog_success!(&mut wam, "?- catch(call(is, X, 3 // 0), error(E, _), true).", [["X = _5", "E = evaluation_error(zero_divisor)"]]); assert_prolog_success!(&mut wam, "?- catch(call(is, X, 3 // 3), _, true).", [["X = 1"]]); @@ -1134,7 +1134,7 @@ fn test_queries_on_conditionals() ; A = \"not 2 or 3\" )."); - assert_prolog_success!(&mut wam, "?- catch(test(A), instantiation_error(_), true)."); + assert_prolog_success!(&mut wam, "?- catch(test(A), error(instantiation_error, _), true)."); assert_prolog_success!(&mut wam, "?- A = 2, test(A).", [["A = 2"]]); assert_prolog_success!(&mut wam, "?- A = 3, test(A), B = 3, test(B).", [["A = 3", "B = 3"]]); @@ -1227,9 +1227,10 @@ fn test_queries_on_builtins() assert_prolog_success!(&mut wam, "?- arg(3, f(a,b,c,d), Arg).", [["Arg = c"]]); assert_prolog_success!(&mut wam, "?- arg(4, f(a,b,c,d), Arg).", [["Arg = d"]]); - assert_prolog_success!(&mut wam, "?- catch(arg(N, f, Arg), type_error(E), true).", - [["E = compound_expected", "Arg = _3", "N = _1"]]); - assert_prolog_success!(&mut wam, "?- catch(arg(N, _, Arg), E, true).", + assert_prolog_success!(&mut wam, "?- catch(arg(N, f, Arg), error(type_error(E, _), _), true).", + [["E = compound", "Arg = _3", "N = _1"]]); + + assert_prolog_success!(&mut wam, "?- catch(arg(N, _, Arg), error(E, _), true).", [["E = instantiation_error", "Arg = _3", "N = _1"]]); assert_prolog_success!(&mut wam, "?- arg(N, f(X, Y, Z), arg_val).", @@ -1262,13 +1263,13 @@ fn test_queries_on_builtins() assert_prolog_success!(&mut wam, "?- functor(Func, f, 3).", [["Func = f(_2, _3, _4)"]]); assert_prolog_success!(&mut wam, "?- functor(Func, f, 4).", [["Func = f(_2, _3, _4, _5)"]]); - assert_prolog_success!(&mut wam, "?- catch(functor(F, \"sdf\", 3), E, true).", + assert_prolog_success!(&mut wam, "?- catch(functor(F, \"sdf\", 3), error(E, _), true).", [["E = instantiation_error", "F = _1"]]); - assert_prolog_success!(&mut wam, "?- catch(functor(Func, F, 3), E, true).", + assert_prolog_success!(&mut wam, "?- catch(functor(Func, F, 3), error(E, _), true).", [["E = instantiation_error", "Func = _1", "F = _2"]]); - assert_prolog_success!(&mut wam, "?- catch(functor(Func, f, N), E, true).", + assert_prolog_success!(&mut wam, "?- catch(functor(Func, f, N), error(E, _), true).", [["E = instantiation_error", "Func = _1", "N = _3"]]); - assert_prolog_failure!(&mut wam, "?- catch(functor(Func, f, N), E, false)."); + assert_prolog_failure!(&mut wam, "?- catch(functor(Func, f, N), error(E, _), false)."); assert_prolog_success!(&mut wam, "?- X is 3, call(integer, X)."); assert_prolog_failure!(&mut wam, "?- X is 3 + 3.5, call(integer, X)."); @@ -1278,7 +1279,7 @@ fn test_queries_on_builtins() assert_prolog_success!(&mut wam, "?- Func =.. [atom].", [["Func = atom"]]); assert_prolog_success!(&mut wam, "?- Func =.. [\"sdf\"].", [["Func = \"sdf\""]]); assert_prolog_success!(&mut wam, "?- Func =.. [1].", [["Func = 1"]]); - assert_prolog_success!(&mut wam, "?- catch(Func =.. [1,2], instantiation_error, true)."); + assert_prolog_success!(&mut wam, "?- catch(Func =.. [1,2], error(instantiation_error, _), true)."); assert_prolog_success!(&mut wam, "?- f(1,2,3) =.. List.", [["List = [f, 1, 2, 3]"]]); assert_prolog_success!(&mut wam, "?- f(1,2,3) =.. [f,1,2,3]."); assert_prolog_failure!(&mut wam, "?- f(1,2,3) =.. [f,1]."); -- 2.54.0