From fe481fedce654408f3d735e0297189d7487b2c09 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 8 Apr 2018 15:17:58 -0600 Subject: [PATCH] throw exceptions when calling non-existent predicates. broken. --- src/prolog/ast.rs | 23 ++++---- src/prolog/io.rs | 16 ++++- src/prolog/machine/machine_state.rs | 74 ++++++++++++++---------- src/prolog/machine/machine_state_impl.rs | 4 +- src/prolog/machine/mod.rs | 6 +- src/prolog/macros.rs | 15 +++++ 6 files changed, 90 insertions(+), 48 deletions(-) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 47fbf49c..fcb3356e 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -103,7 +103,7 @@ impl GenContext { pub struct Predicate(pub Vec); -impl Predicate { +impl Predicate { pub fn clauses(self) -> Vec { self.0 } @@ -1400,18 +1400,23 @@ impl HeapCellValue { } } +#[derive(Clone, Copy, PartialEq)] +pub enum IndexPtr { + Undefined, Index(usize) +} + #[derive(Clone)] -pub struct CodeIndex(pub Rc>, pub ClauseName); +pub struct CodeIndex(pub Rc>, pub ClauseName); -impl CodeIndex { - pub fn is_undefined(&self) -> bool { - self.0.get() == 0 && self.1 == clause_name!("") +impl Default for CodeIndex { + fn default() -> Self { + CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined)), clause_name!("")) } } impl From<(usize, ClauseName)> for CodeIndex { fn from(value: (usize, ClauseName)) -> Self { - CodeIndex(Rc::new(Cell::new(value.0)), value.1) + CodeIndex(Rc::new(Cell::new(IndexPtr::Index(value.0))), value.1) } } @@ -1444,12 +1449,6 @@ impl PartialOrd for CodePtr { } } -impl Default for CodeIndex { - fn default() -> Self { - CodeIndex(Rc::new(Cell::new(0)), clause_name!("")) - } -} - impl Default for CodePtr { fn default() -> Self { CodePtr::TopLevel(0, 0) diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 690b09b5..010306f0 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -13,6 +13,16 @@ use termion::event::Key; use std::io::{Write, stdin, stdout}; use std::fmt; + +impl fmt::Display for IndexPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &IndexPtr::Undefined => write!(f, "undefined"), + &IndexPtr::Index(i) => write!(f, "{}", i) + } + } +} + impl fmt::Display for ClauseName { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.as_str()) @@ -461,10 +471,10 @@ impl TLInfo for DeclInfo { { let (name, arity) = (self.name.clone(), self.arity); - if entry.0.get() == 0 { + if entry.0.get() == IndexPtr::Undefined { if &name == n1 && arity == a1 { // *entry = default(); // implement logical view update semantics. - entry.0.set(code_size); + entry.0.set(IndexPtr::Index(code_size)); } } @@ -669,7 +679,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession code.extend(decl_code.into_iter()); - let index = CodeIndex::from((p, get_module_name(&module))); + let index = CodeIndex::default(); code_dir.insert((decl_info.name.clone(), decl_info.arity), index); } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index ab3f4c78..cecaf6fd 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -210,46 +210,62 @@ pub struct MachineState { pub(crate) type CallResult = Result<(), Vec>; +fn predicate_existence_error(name: ClauseName, arity: usize) -> Vec +{ + let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name))); + + let mut error = functor!("existence_error", 2, [heap_atom!("procedure"), heap_str!(4)]); + error.append(&mut functor!("/", 2, [name, heap_integer!(arity)], Fixity::In)); + + error +} + pub(crate) trait CallPolicy: Any { - fn context_call(&mut self, machine_st: &mut MachineState, arity: usize, idx: CodeIndex, lco: bool) + fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, + arity: usize, idx: CodeIndex, lco: bool) -> CallResult { if lco { - self.try_execute(machine_st, arity, idx) + self.try_execute(machine_st, name, arity, idx) } else { - self.try_call(machine_st, arity, idx) + self.try_call(machine_st, name, arity, idx) } } - fn try_call(&mut self, machine_st: &mut MachineState, arity: usize, idx: CodeIndex) -> CallResult - { - if idx.is_undefined() { - machine_st.fail = true; - } else { - let compiled_tl_index = idx.0.get(); - let module_name = idx.1; - - machine_st.cp = machine_st.p.clone() + 1; - machine_st.num_of_args = arity; - machine_st.b0 = machine_st.b; - machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name); + fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName, + arity: usize, idx: CodeIndex) + -> CallResult + { + match idx.0.get() { + IndexPtr::Undefined => + return Err(predicate_existence_error(name, arity)), + IndexPtr::Index(compiled_tl_index) => { + let module_name = idx.1; + + machine_st.cp = machine_st.p.clone() + 1; + machine_st.num_of_args = arity; + machine_st.b0 = machine_st.b; + machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name); + } } Ok(()) } - fn try_execute<'a>(&mut self, machine_st: &mut MachineState, arity: usize, idx: CodeIndex) + fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName, + arity: usize, idx: CodeIndex) -> CallResult - { - if idx.is_undefined() { - machine_st.fail = true; - } else { - let compiled_tl_index = idx.0.get(); - let module_name = idx.1; + { + match idx.0.get() { + IndexPtr::Undefined => + return Err(predicate_existence_error(name, arity)), + IndexPtr::Index(compiled_tl_index) => { + let module_name = idx.1; - machine_st.num_of_args = arity; - machine_st.b0 = machine_st.b; - machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name); + machine_st.num_of_args = arity; + machine_st.b0 = machine_st.b; + machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name); + } } Ok(()) @@ -412,8 +428,8 @@ pub(crate) trait CallPolicy: Any { }, &ClauseType::CallN => { if let Some((name, arity)) = machine_st.setup_call_n(arity) { - if let Some(idx) = code_dirs.get(name, arity, &machine_st.p.clone()) { - return self.context_call(machine_st, arity, idx, lco); + if let Some(idx) = code_dirs.get(name.clone(), arity, &machine_st.p.clone()) { + return self.context_call(machine_st, name, arity, idx, lco); } else { machine_st.fail = true; } @@ -519,8 +535,8 @@ pub(crate) trait CallPolicy: Any { machine_st.goto_throw(); Ok(()) }, - &ClauseType::Named(_, ref idx) | &ClauseType::Op(_, _, ref idx) => - self.context_call(machine_st, arity, idx.clone(), lco), + &ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) => + self.context_call(machine_st, name.clone(), arity, idx.clone(), lco), &ClauseType::CallWithInferenceLimit => { machine_st.goto_ptr(CodePtr::DirEntry(409, clause_name!("builtin")), 3, lco); Ok(()) diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index cbbbe9ee..da5aba13 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -909,8 +909,8 @@ impl MachineState { self.registers[arity - 1] = pred; if let Some((name, arity)) = self.setup_call_n(arity - 1) { - if let Some(idx) = code_dirs.get(name, arity, &self.p.clone()) { - try_or_fail!(self, call_policy.try_execute(self, arity, idx)); + if let Some(idx) = code_dirs.get(name.clone(), arity, &self.p.clone()) { + try_or_fail!(self, call_policy.try_execute(self, name, arity, idx)); return; } } diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index c06ecc3a..10ed2074 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -180,7 +180,9 @@ impl Machine { { match self.code_dir.get(&(name.clone(), arity)) { Some(&CodeIndex (_, ref mod_name)) if mod_name == &clause_name!("builtin") => - return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))), + return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", + name, + arity))), _ => {} }; @@ -192,7 +194,7 @@ impl Machine { let entry = self.code_dir.entry((name, arity)) .or_insert(CodeIndex::from((offset, clause_name!("user")))); - entry.0.set(offset); + entry.0.set(IndexPtr::Index(offset)); entry.1 = clause_name!("user"); EvalSession::EntrySuccess diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index c48418ea..05a5fff9 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -55,6 +55,18 @@ macro_rules! query { ) } +macro_rules! heap_str { + ($s:expr) => ( + HeapCellValue::Addr(Addr::Str($s)) + ) +} + +macro_rules! heap_integer { + ($i:expr) => ( + HeapCellValue::Addr(Addr::Con(integer!($i))) + ) +} + macro_rules! heap_atom { ($name:expr) => ( HeapCellValue::Addr(Addr::Con(atom!($name))) @@ -70,6 +82,9 @@ macro_rules! functor { ); ($name:expr, $len:expr, [$($args:expr),*]) => ( vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ] + ); + ($name:expr, $len:expr, [$($args:expr),*], $fix: expr) => ( + vec![ HeapCellValue::NamedStr($len, clause_name!($name), Some($fix)), $($args),* ] ) } -- 2.54.0