throw exceptions when calling non-existent predicates. broken.
This commit is contained in:
@@ -103,7 +103,7 @@ impl GenContext {
|
|||||||
|
|
||||||
pub struct Predicate(pub Vec<PredicateClause>);
|
pub struct Predicate(pub Vec<PredicateClause>);
|
||||||
|
|
||||||
impl Predicate {
|
impl Predicate {
|
||||||
pub fn clauses(self) -> Vec<PredicateClause> {
|
pub fn clauses(self) -> Vec<PredicateClause> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
@@ -1400,18 +1400,23 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub struct CodeIndex(pub Rc<Cell<usize>>, pub ClauseName);
|
pub enum IndexPtr {
|
||||||
|
Undefined, Index(usize)
|
||||||
|
}
|
||||||
|
|
||||||
impl CodeIndex {
|
#[derive(Clone)]
|
||||||
pub fn is_undefined(&self) -> bool {
|
pub struct CodeIndex(pub Rc<Cell<IndexPtr>>, pub ClauseName);
|
||||||
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 {
|
impl From<(usize, ClauseName)> for CodeIndex {
|
||||||
fn from(value: (usize, ClauseName)) -> Self {
|
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<CodePtr> for CodePtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CodeIndex {
|
|
||||||
fn default() -> Self {
|
|
||||||
CodeIndex(Rc::new(Cell::new(0)), clause_name!(""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CodePtr {
|
impl Default for CodePtr {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CodePtr::TopLevel(0, 0)
|
CodePtr::TopLevel(0, 0)
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ use termion::event::Key;
|
|||||||
use std::io::{Write, stdin, stdout};
|
use std::io::{Write, stdin, stdout};
|
||||||
use std::fmt;
|
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 {
|
impl fmt::Display for ClauseName {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.as_str())
|
write!(f, "{}", self.as_str())
|
||||||
@@ -461,10 +471,10 @@ impl TLInfo for DeclInfo {
|
|||||||
{
|
{
|
||||||
let (name, arity) = (self.name.clone(), self.arity);
|
let (name, arity) = (self.name.clone(), self.arity);
|
||||||
|
|
||||||
if entry.0.get() == 0 {
|
if entry.0.get() == IndexPtr::Undefined {
|
||||||
if &name == n1 && arity == a1 {
|
if &name == n1 && arity == a1 {
|
||||||
// *entry = default(); // implement logical view update semantics.
|
// *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());
|
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);
|
code_dir.insert((decl_info.name.clone(), decl_info.arity), index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,46 +210,62 @@ pub struct MachineState {
|
|||||||
|
|
||||||
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
||||||
|
|
||||||
|
fn predicate_existence_error(name: ClauseName, arity: usize) -> Vec<HeapCellValue>
|
||||||
|
{
|
||||||
|
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 {
|
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
|
-> CallResult
|
||||||
{
|
{
|
||||||
if lco {
|
if lco {
|
||||||
self.try_execute(machine_st, arity, idx)
|
self.try_execute(machine_st, name, arity, idx)
|
||||||
} else {
|
} 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
|
fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName,
|
||||||
{
|
arity: usize, idx: CodeIndex)
|
||||||
if idx.is_undefined() {
|
-> CallResult
|
||||||
machine_st.fail = true;
|
{
|
||||||
} else {
|
match idx.0.get() {
|
||||||
let compiled_tl_index = idx.0.get();
|
IndexPtr::Undefined =>
|
||||||
let module_name = idx.1;
|
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.cp = machine_st.p.clone() + 1;
|
||||||
machine_st.num_of_args = arity;
|
machine_st.num_of_args = arity;
|
||||||
machine_st.b0 = machine_st.b;
|
machine_st.b0 = machine_st.b;
|
||||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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
|
-> CallResult
|
||||||
{
|
{
|
||||||
if idx.is_undefined() {
|
match idx.0.get() {
|
||||||
machine_st.fail = true;
|
IndexPtr::Undefined =>
|
||||||
} else {
|
return Err(predicate_existence_error(name, arity)),
|
||||||
let compiled_tl_index = idx.0.get();
|
IndexPtr::Index(compiled_tl_index) => {
|
||||||
let module_name = idx.1;
|
let module_name = idx.1;
|
||||||
|
|
||||||
machine_st.num_of_args = arity;
|
machine_st.num_of_args = arity;
|
||||||
machine_st.b0 = machine_st.b;
|
machine_st.b0 = machine_st.b;
|
||||||
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
machine_st.p = CodePtr::DirEntry(compiled_tl_index, module_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -412,8 +428,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
},
|
},
|
||||||
&ClauseType::CallN => {
|
&ClauseType::CallN => {
|
||||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||||
if let Some(idx) = code_dirs.get(name, arity, &machine_st.p.clone()) {
|
if let Some(idx) = code_dirs.get(name.clone(), arity, &machine_st.p.clone()) {
|
||||||
return self.context_call(machine_st, arity, idx, lco);
|
return self.context_call(machine_st, name, arity, idx, lco);
|
||||||
} else {
|
} else {
|
||||||
machine_st.fail = true;
|
machine_st.fail = true;
|
||||||
}
|
}
|
||||||
@@ -519,8 +535,8 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
machine_st.goto_throw();
|
machine_st.goto_throw();
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
&ClauseType::Named(_, ref idx) | &ClauseType::Op(_, _, ref idx) =>
|
&ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) =>
|
||||||
self.context_call(machine_st, arity, idx.clone(), lco),
|
self.context_call(machine_st, name.clone(), arity, idx.clone(), lco),
|
||||||
&ClauseType::CallWithInferenceLimit => {
|
&ClauseType::CallWithInferenceLimit => {
|
||||||
machine_st.goto_ptr(CodePtr::DirEntry(409, clause_name!("builtin")), 3, lco);
|
machine_st.goto_ptr(CodePtr::DirEntry(409, clause_name!("builtin")), 3, lco);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -909,8 +909,8 @@ impl MachineState {
|
|||||||
self.registers[arity - 1] = pred;
|
self.registers[arity - 1] = pred;
|
||||||
|
|
||||||
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
|
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
|
||||||
if let Some(idx) = code_dirs.get(name, arity, &self.p.clone()) {
|
if let Some(idx) = code_dirs.get(name.clone(), arity, &self.p.clone()) {
|
||||||
try_or_fail!(self, call_policy.try_execute(self, arity, idx));
|
try_or_fail!(self, call_policy.try_execute(self, name, arity, idx));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,9 @@ impl Machine {
|
|||||||
{
|
{
|
||||||
match self.code_dir.get(&(name.clone(), arity)) {
|
match self.code_dir.get(&(name.clone(), arity)) {
|
||||||
Some(&CodeIndex (_, ref mod_name)) if mod_name == &clause_name!("builtin") =>
|
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))
|
let entry = self.code_dir.entry((name, arity))
|
||||||
.or_insert(CodeIndex::from((offset, clause_name!("user"))));
|
.or_insert(CodeIndex::from((offset, clause_name!("user"))));
|
||||||
|
|
||||||
entry.0.set(offset);
|
entry.0.set(IndexPtr::Index(offset));
|
||||||
entry.1 = clause_name!("user");
|
entry.1 = clause_name!("user");
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
EvalSession::EntrySuccess
|
||||||
|
|||||||
@@ -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 {
|
macro_rules! heap_atom {
|
||||||
($name:expr) => (
|
($name:expr) => (
|
||||||
HeapCellValue::Addr(Addr::Con(atom!($name)))
|
HeapCellValue::Addr(Addr::Con(atom!($name)))
|
||||||
@@ -70,6 +82,9 @@ macro_rules! functor {
|
|||||||
);
|
);
|
||||||
($name:expr, $len:expr, [$($args:expr),*]) => (
|
($name:expr, $len:expr, [$($args:expr),*]) => (
|
||||||
vec![ HeapCellValue::NamedStr($len, clause_name!($name), None), $($args),* ]
|
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),* ]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user