properly handle undefined predicates declared dynamic

This commit is contained in:
Mark Thom
2019-10-02 22:01:32 -06:00
parent 04bc8ec084
commit 516c66a47d
6 changed files with 68 additions and 41 deletions

View File

@@ -325,13 +325,13 @@ fn compile_into_module_impl<R: Read>(
let module_code = let module_code =
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?; compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?;
let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len()); let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len(), module_name.clone());
clause_code_generator.generate_clause_code(results.dynamic_clause_map, wam)?; clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
update_module_indices(wam, module_name, indices); update_module_indices(wam, module_name, indices);
wam.code_repo.code.extend(module_code.into_iter()); wam.code_repo.code.extend(module_code.into_iter());
clause_code_generator.add_clause_code(wam); clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
Ok(compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo)) Ok(compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo))
} }
@@ -347,22 +347,24 @@ pub struct GatherResult {
pub struct ClauseCodeGenerator { pub struct ClauseCodeGenerator {
len_offset: usize, len_offset: usize,
code: Code, code: Code,
module_name: ClauseName,
pi_to_loc: IndexMap<PredicateKey, usize>, pi_to_loc: IndexMap<PredicateKey, usize>,
} }
impl ClauseCodeGenerator { impl ClauseCodeGenerator {
#[inline] #[inline]
fn new(len_offset: usize) -> Self { fn new(len_offset: usize, module_name: ClauseName) -> Self {
ClauseCodeGenerator { ClauseCodeGenerator {
len_offset, len_offset,
code: vec![], code: vec![],
module_name,
pi_to_loc: IndexMap::new(), pi_to_loc: IndexMap::new(),
} }
} }
fn generate_clause_code( fn generate_clause_code(
&mut self, &mut self,
dynamic_clause_map: DynamicClauseMap, dynamic_clause_map: &DynamicClauseMap,
wam: &Machine, wam: &Machine,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
for ((name, arity), heads_and_tails) in dynamic_clause_map { for ((name, arity), heads_and_tails) in dynamic_clause_map {
@@ -372,12 +374,12 @@ impl ClauseCodeGenerator {
let predicate = Predicate( let predicate = Predicate(
heads_and_tails heads_and_tails
.into_iter() .iter()
.map(|(head, tail)| { .map(|(head, tail)| {
let clause = Term::Clause( let clause = Term::Clause(
Cell::default(), Cell::default(),
clause_name!("clause"), clause_name!("clause"),
vec![Box::new(head), Box::new(tail)], vec![Box::new(head.clone()), Box::new(tail.clone())],
None, None,
); );
PredicateClause::Fact(clause) PredicateClause::Fact(clause)
@@ -391,16 +393,24 @@ impl ClauseCodeGenerator {
compile_appendix(&mut decl_code, &VecDeque::new(), false, wam.machine_flags())?; compile_appendix(&mut decl_code, &VecDeque::new(), false, wam.machine_flags())?;
self.pi_to_loc.insert((name, arity), p); self.pi_to_loc.insert((name.clone(), *arity), p);
self.code.extend(decl_code.into_iter()); self.code.extend(decl_code.into_iter());
} }
Ok(()) Ok(())
} }
fn add_clause_code(self, wam: &mut Machine) { fn add_clause_code(self, wam: &mut Machine, dynamic_code_dir: DynamicClauseMap)
{
wam.code_repo.code.extend(self.code.into_iter()); wam.code_repo.code.extend(self.code.into_iter());
for ((name, arity), _) in dynamic_code_dir {
wam.indices.dynamic_code_dir.insert((name.owning_module(), name.clone(), arity),
DynamicPredicateInfo::default());
wam.indices.code_dir.entry((name, arity))
.or_insert(CodeIndex::dynamic_undefined(self.module_name.clone()));
}
for ((name, arity), p) in self.pi_to_loc { for ((name, arity), p) in self.pi_to_loc {
let entry = wam let entry = wam
.indices .indices
@@ -457,11 +467,11 @@ fn add_non_module_code(
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
wam.check_toplevel_code(&indices)?; wam.check_toplevel_code(&indices)?;
let mut clause_code_generator = ClauseCodeGenerator::new(code.len()); let mut clause_code_generator = ClauseCodeGenerator::new(code.len(), clause_name!("user"));
clause_code_generator.generate_clause_code(dynamic_clause_map, wam)?; clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
add_toplevel_code(wam, code, indices); add_toplevel_code(wam, code, indices);
clause_code_generator.add_clause_code(wam); clause_code_generator.add_clause_code(wam, dynamic_clause_map);
Ok(()) Ok(())
} }
@@ -818,6 +828,9 @@ impl ListingCompiler {
.dynamic_clause_map .dynamic_clause_map
.entry((name.clone(), arity)) .entry((name.clone(), arity))
.or_insert(vec![]); .or_insert(vec![]);
indices.code_dir.insert((name.clone(), arity),
CodeIndex::dynamic_undefined(self.get_module_name()));
} }
&Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker &Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker
.term_stream .term_stream
@@ -929,17 +942,18 @@ fn compile_work_impl(
if let Some(module) = compiler.module.take() { if let Some(module) = compiler.module.take() {
let mut clause_code_generator = let mut clause_code_generator =
ClauseCodeGenerator::new(module_code.len() + toplvl_code.len()); ClauseCodeGenerator::new(module_code.len() + toplvl_code.len(),
module.module_decl.name.clone());
try_eval_session!(wam.check_toplevel_code(&results.toplevel_indices)); try_eval_session!(wam.check_toplevel_code(&results.toplevel_indices));
try_eval_session!( try_eval_session!(
clause_code_generator.generate_clause_code(results.dynamic_clause_map, wam) clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)
); );
add_module_code(wam, module, module_code, indices); add_module_code(wam, module, module_code, indices);
add_toplevel_code(wam, toplvl_code, results.toplevel_indices); add_toplevel_code(wam, toplvl_code, results.toplevel_indices);
clause_code_generator.add_clause_code(wam); clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
} else { } else {
try_eval_session!(add_non_module_code( try_eval_session!(add_non_module_code(
wam, wam,

View File

@@ -78,7 +78,7 @@ impl Machine {
let (name, arity) = self.get_predicate_key(name, arity); let (name, arity) = self.get_predicate_key(name, arity);
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) { if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
set_code_index!(idx, IndexPtr::Undefined, clause_name!("user")); set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
} }
self.indices.remove_code_index((name.clone(), arity)); self.indices.remove_code_index((name.clone(), arity));
@@ -106,7 +106,7 @@ impl Machine {
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) { if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
if idx.module_name() == module_name { if idx.module_name() == module_name {
set_code_index!(idx, IndexPtr::Undefined, clause_name!("user")); set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
} }
} }
@@ -208,11 +208,6 @@ impl Machine {
let mut addrs = VecDeque::from(addrs); let mut addrs = VecDeque::from(addrs);
addrs.remove(index); addrs.remove(index);
if addrs.is_empty() {
self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(5));
return;
}
self.print_new_dynamic_clause(addrs, name.clone(), arity) self.print_new_dynamic_clause(addrs, name.clone(), arity)
} }
Err(err) => return self.machine_st.throw_exception(err), Err(err) => return self.machine_st.throw_exception(err),
@@ -242,11 +237,6 @@ impl Machine {
let mut addrs = VecDeque::from(addrs); let mut addrs = VecDeque::from(addrs);
addrs.remove(index); addrs.remove(index);
if addrs.is_empty() {
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2));
return;
}
self.print_new_dynamic_clause(addrs, name.clone(), arity) self.print_new_dynamic_clause(addrs, name.clone(), arity)
} }
Err(err) => return self.machine_st.throw_exception(err), Err(err) => return self.machine_st.throw_exception(err),

View File

@@ -206,6 +206,7 @@ impl HeapCellValue {
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum IndexPtr { pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
Undefined, Undefined,
Index(usize), Index(usize),
} }
@@ -218,13 +219,20 @@ impl CodeIndex {
pub fn is_undefined(&self) -> bool { pub fn is_undefined(&self) -> bool {
let index_ptr = &self.0.borrow().0; let index_ptr = &self.0.borrow().0;
if let &IndexPtr::Undefined = index_ptr { match index_ptr {
true &IndexPtr::Undefined | &IndexPtr::DynamicUndefined => true,
} else { _ => false
false
} }
} }
#[inline]
pub fn dynamic_undefined(module_name: ClauseName) -> Self {
CodeIndex(Rc::new(RefCell::new((
IndexPtr::DynamicUndefined,
module_name
))))
}
#[inline] #[inline]
pub fn module_name(&self) -> ClauseName { pub fn module_name(&self) -> ClauseName {
self.0.borrow().1.clone() self.0.borrow().1.clone()

View File

@@ -325,14 +325,21 @@ impl MachineState {
let (name, arity) = key; let (name, arity) = key;
if let Some(ref idx) = indices.get_code_index((name.clone(), arity), module_name.clone()) { if let Some(ref idx) = indices.get_code_index((name.clone(), arity), module_name.clone()) {
if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 { match idx.0.borrow().0 {
if last_call { IndexPtr::Index(compiled_tl_index) => {
self.execute_at_index(arity, compiled_tl_index); if last_call {
} else { self.execute_at_index(arity, compiled_tl_index);
self.call_at_index(arity, compiled_tl_index); } else {
} self.call_at_index(arity, compiled_tl_index);
}
return Ok(()); return Ok(());
}
IndexPtr::DynamicUndefined => {
self.fail = true;
return Ok(());
}
_ => {}
} }
} }
@@ -586,7 +593,10 @@ pub(crate) trait CallPolicy: Any {
indices: &IndexStore, indices: &IndexStore,
) -> CallResult { ) -> CallResult {
match idx.0.borrow().0 { match idx.0.borrow().0 {
IndexPtr::Undefined => return try_in_situ(machine_st, name, arity, indices, false), IndexPtr::DynamicUndefined =>
machine_st.fail = true,
IndexPtr::Undefined =>
return try_in_situ(machine_st, name, arity, indices, false),
IndexPtr::Index(compiled_tl_index) => { IndexPtr::Index(compiled_tl_index) => {
machine_st.call_at_index(arity, compiled_tl_index) machine_st.call_at_index(arity, compiled_tl_index)
} }
@@ -604,7 +614,10 @@ pub(crate) trait CallPolicy: Any {
indices: &IndexStore, indices: &IndexStore,
) -> CallResult { ) -> CallResult {
match idx.0.borrow().0 { match idx.0.borrow().0 {
IndexPtr::Undefined => return try_in_situ(machine_st, name, arity, indices, true), IndexPtr::DynamicUndefined =>
machine_st.fail = true,
IndexPtr::Undefined =>
return try_in_situ(machine_st, name, arity, indices, true),
IndexPtr::Index(compiled_tl_index) => { IndexPtr::Index(compiled_tl_index) => {
machine_st.execute_at_index(arity, compiled_tl_index) machine_st.execute_at_index(arity, compiled_tl_index)
} }

View File

@@ -10,7 +10,8 @@ use std::collections::VecDeque;
// Module's and related types are defined in forms. // Module's and related types are defined in forms.
impl Module { impl Module {
pub fn new(module_decl: ModuleDecl, atom_tbl: TabledData<Atom>) -> Self { pub fn new(module_decl: ModuleDecl, atom_tbl: TabledData<Atom>) -> Self
{
Module { Module {
module_decl, module_decl,
atom_tbl, atom_tbl,

View File

@@ -48,6 +48,7 @@ impl fmt::Display for REPLCodePtr {
impl fmt::Display for IndexPtr { impl fmt::Display for IndexPtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
&IndexPtr::Undefined => write!(f, "undefined"), &IndexPtr::Undefined => write!(f, "undefined"),
&IndexPtr::Index(i) => write!(f, "{}", i), &IndexPtr::Index(i) => write!(f, "{}", i),
} }