]> Repositorios git - scryer-prolog.git/commitdiff
add error handling appartus
authorMark Thom <[email protected]>
Thu, 3 May 2018 03:24:43 +0000 (21:24 -0600)
committerMark Thom <[email protected]>
Thu, 3 May 2018 03:24:43 +0000 (21:24 -0600)
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/io.rs
src/prolog/machine/machine_errors.rs [new file with mode: 0644]
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/macros.rs
src/prolog/toplevel.rs
src/tests.rs

index bc5e5620d89f3b4199f4553127d221616ef495e1..ad20473f6681c2d7b1d54248610536b00e2f9815 100644 (file)
@@ -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<Rc<Var>, Addr>;
 pub type AllocVarDict = HashMap<Rc<Var>, 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<EvalError> for EvalSession {
-    fn from(err: EvalError) -> Self {
+impl From<SessionError> for EvalSession {
+    fn from(err: SessionError) -> Self {
         EvalSession::Error(err)
     }
 }
 
-impl From<ParserError> for EvalError {
+impl From<ParserError> for SessionError {
     fn from(err: ParserError) -> Self {
-        EvalError::ParserError(err)
+        SessionError::ParserError(err)
     }
 }
 
 impl From<ParserError> 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),
                 _ => {}
             };
         }
index 2f5fbc9c1498e046bd9f8afc2971071e1a80045e..2805148e6d8d457904d0610ed0ad90fe9638073d 100644 (file)
@@ -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),
index 98e6182be47bbe31d49f95bccbfb8873cbbb7d08..e51635d35cf2c6b55d73cfe1586e478361cc568b 100644 (file)
@@ -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<TopLevel>) -> 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<TopLevel>) -> 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 (file)
index 0000000..08444bd
--- /dev/null
@@ -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<HeapCellValue>;
+
+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();
+    }    
+} 
index 5b6d11d663b9b0acce756e505ff4b6f7c924ff00..12aa099fc1a251ffb9bfae5bd569e5245b1e5fcc 100644 (file)
@@ -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<Number, Vec<HeapCellValue>> {
+    fn get_number(&self, at: &ArithmeticTerm) -> Result<Number, MachineError> {
         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<Rc<Ratio<BigInt>>, Vec<HeapCellValue>> {
+    fn get_rational(&self, at: &ArithmeticTerm) -> Result<Rc<Ratio<BigInt>>, 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<Number, Vec<HeapCellValue>>
+    pub(super) fn arith_eval_by_metacall(&self, r: RegType) -> Result<Number, MachineError>
     {
-        let instantiation_err = functor!("instantiation_error", 1, [heap_atom!("(is)/2")]);
         let a = self[r].clone();
 
         let mut interms: Vec<Number> = 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<Ratio<BigInt>>, r2: Rc<Ratio<BigInt>>)
-            -> Result<Rc<Ratio<BigInt>>, Vec<HeapCellValue>>
+            -> Result<Rc<Ratio<BigInt>>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn fidiv(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn idiv(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Number, Vec<HeapCellValue>>
+    fn div(&self, n1: Number, n2: Number) -> Result<Number, MachineError>
     {
         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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn shr(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn shl(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn xor(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn and(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn modulus(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn remainder(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<Rc<BigInt>, Vec<HeapCellValue>>
+    fn or(&self, n1: Number, n2: Number) -> Result<Rc<BigInt>, 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<HeapCellValue>) {
-        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<HeapCellValue> {
-        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<PredicateKey>
     {
         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<HeapCellValue>>
+    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::<CallWithInferenceLimitCallPolicy>().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<HeapCellValue>> {
+    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<Addr>, Vec<HeapCellValue>>
+    pub(super) fn try_from_list(&self, r: RegType) -> Result<Vec<Addr>, 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<Addr, Vec<HeapCellValue>> {
+    pub(super) fn project_onto_key(&self, a: Addr) -> Result<Addr, MachineError> {
         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()));
 
index eeb9532d9c89c23a8794f0d158f0986c4ffe48d4..ad07beb138f766a67a0894f9333f1f267abe8e99 100644 (file)
@@ -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)
         }
     }
 
index 2cd018bcb24c98c373bc8b206f7ce81e81ca20b5..aff35e3591934a4858c2403c310af2e06b196343 100644 (file)
@@ -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)
index dad3e1586b11d4a1aafdffd693c8466e50156514..10cab7dbf19353df5efdd7b7a0852c4d976c4481 100644 (file)
@@ -568,7 +568,7 @@ impl<R: Read> TopLevelWorker<R> {
         TopLevelWorker { parser: Parser::new(inner, atom_tbl) }
     }
 
-    pub fn parse_batch(&mut self, op_dir: &mut OpDir) -> Result<Vec<TopLevelPacket>, EvalError>
+    pub fn parse_batch(&mut self, op_dir: &mut OpDir) -> Result<Vec<TopLevelPacket>, SessionError>
     {
         let mut preds = vec![];
         let mut mod_name = clause_name!("user");
index 4066300ed67444e9347bc649010ebad241786ab2..ad0d5e74e72d1b71fcd057dba6d07ccf4c521257 100644 (file)
@@ -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].");