give dynamic predicates a better respect for module bounds

This commit is contained in:
Mark Thom
2019-03-06 00:09:55 -07:00
parent 20e9042350
commit 6439d09733
7 changed files with 142 additions and 47 deletions

View File

@@ -158,6 +158,36 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession
} }
} }
pub(super)
fn compile_into_module<R: Read>(wam: &mut Machine, src: R, name: ClauseName) -> EvalSession
{
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
try_eval_session!(setup_indices(wam, name.owning_module(), &mut indices));
let mut compiler = ListingCompiler::new(&wam.code_repo);
let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
let module_code = try_eval_session!(compiler.generate_code(results.worker_results, wam,
&mut indices.code_dir, 0));
let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len());
try_eval_session!(clause_code_generator.generate_clause_code(results.dynamic_clause_map,
wam));
match wam.indices.modules.get_mut(&name.owning_module()) {
Some(module) => {
let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());
module.code_dir.extend(as_module_code_dir(code_dir));
},
_ => unreachable!()
};
wam.code_repo.code.extend(module_code.into_iter());
clause_code_generator.add_clause_code(wam);
EvalSession::EntrySuccess
}
pub struct GatherResult { pub struct GatherResult {
dynamic_clause_map: DynamicClauseMap, dynamic_clause_map: DynamicClauseMap,
pub(crate) worker_results: Vec<PredicateCompileQueue>, pub(crate) worker_results: Vec<PredicateCompileQueue>,
@@ -186,6 +216,15 @@ impl ClauseCodeGenerator {
continue; continue;
} }
if let Some(idx) = wam.indices.code_dir.get(&(name.clone(), arity)) {
if !idx.is_undefined() && name.owning_module() != idx.module_name() {
let err_str = format!("{}/{}", name.as_str(), arity);
let err_str = clause_name!(err_str, wam.indices.atom_tbl());
return Err(SessionError::CannotOverwriteDynamicClause(err_str));
}
}
let predicate = Predicate(heads_and_tails.into_iter().map(|(head, tail)| { let predicate = Predicate(heads_and_tails.into_iter().map(|(head, tail)| {
let clause = Term::Clause(Cell::default(), clause_name!("clause"), let clause = Term::Clause(Cell::default(), clause_name!("clause"),
vec![Box::new(head), Box::new(tail)], vec![Box::new(head), Box::new(tail)],
@@ -360,7 +399,7 @@ impl ListingCompiler {
pub(crate) pub(crate)
fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine, fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine,
code_dir: &mut CodeDir) code_dir: &mut CodeDir, code_offset: usize)
-> Result<Code, SessionError> -> Result<Code, SessionError>
{ {
let mut code = vec![]; let mut code = vec![];
@@ -369,7 +408,7 @@ impl ListingCompiler {
let (name, arity) = decl.predicate_indicator().ok_or(SessionError::NamelessEntry)?; let (name, arity) = decl.predicate_indicator().ok_or(SessionError::NamelessEntry)?;
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity)); let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
let p = code.len() + wam.code_size(); let p = code.len() + wam.code_size() + code_offset;
let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt, let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt,
wam.machine_flags())?; wam.machine_flags())?;
@@ -541,9 +580,10 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices)); let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
let module_code = try_eval_session!(compiler.generate_code(results.worker_results, wam, let module_code = try_eval_session!(compiler.generate_code(results.worker_results, wam,
&mut indices.code_dir)); &mut indices.code_dir, 0));
let toplvl_code = try_eval_session!(compiler.generate_code(results.toplevel_results, wam, let toplvl_code = try_eval_session!(compiler.generate_code(results.toplevel_results, wam,
&mut results.toplevel_indices.code_dir)); &mut results.toplevel_indices.code_dir,
module_code.len()));
if let Some(ref mut module) = &mut compiler.module { if let Some(ref mut module) = &mut compiler.module {
module.term_expansions = results.addition_results.take_term_expansions(); module.term_expansions = results.addition_results.take_term_expansions();
@@ -556,10 +596,15 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags)); try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
if let Some(module) = compiler.module.take() { if let Some(module) = compiler.module.take() {
try_eval_session!(add_non_module_code(wam, results.dynamic_clause_map, toplvl_code, let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len() + toplvl_code.len());
results.toplevel_indices));
try_eval_session!(clause_code_generator.generate_clause_code(results.dynamic_clause_map, wam));
try_eval_session!(wam.check_toplevel_code(&results.toplevel_indices));
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);
clause_code_generator.add_clause_code(wam);
} else { } else {
try_eval_session!(add_non_module_code(wam, results.dynamic_clause_map, module_code, try_eval_session!(add_non_module_code(wam, results.dynamic_clause_map, module_code,
indices)); indices));
@@ -574,12 +619,12 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
pub fn compile_special_form<R: Read>(wam: &mut Machine, src: R) -> Result<Code, SessionError> pub fn compile_special_form<R: Read>(wam: &mut Machine, src: R) -> Result<Code, SessionError>
{ {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
setup_indices(wam, &mut indices)?; setup_indices(wam, clause_name!("builtins"), &mut indices)?;
let mut compiler = ListingCompiler::new(&wam.code_repo); let mut compiler = ListingCompiler::new(&wam.code_repo);
let results = compiler.gather_items(wam, src, &mut indices)?; let results = compiler.gather_items(wam, src, &mut indices)?;
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir) compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)
} }
#[inline] #[inline]
@@ -596,12 +641,15 @@ pub fn compile_listing<R: Read>(wam: &mut Machine, src: R, indices: IndexStore)
} }
} }
fn setup_indices(wam: &mut Machine, indices: &mut IndexStore) -> Result<(), SessionError> { pub(super)
if let Some(builtins) = wam.indices.take_module(clause_name!("builtins")) { fn setup_indices(wam: &mut Machine, module: ClauseName, indices: &mut IndexStore)
-> Result<(), SessionError>
{
if let Some(module) = wam.indices.take_module(module) {
let flags = wam.machine_flags(); let flags = wam.machine_flags();
let result = indices.use_module(&mut wam.code_repo, flags, &builtins); let result = indices.use_module(&mut wam.code_repo, flags, &module);
wam.indices.insert_module(builtins); wam.indices.insert_module(module);
result result
} else { } else {
Err(SessionError::ModuleNotFound) Err(SessionError::ModuleNotFound)
@@ -610,6 +658,6 @@ fn setup_indices(wam: &mut Machine, indices: &mut IndexStore) -> Result<(), Sess
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession { pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
try_eval_session!(setup_indices(wam, &mut indices)); try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
compile_listing(wam, src, indices) compile_listing(wam, src, indices)
} }

View File

@@ -6,8 +6,27 @@ use prolog::machine::compile::*;
use prolog::machine::machine_errors::*; use prolog::machine::machine_errors::*;
use prolog::num::ToPrimitive; use prolog::num::ToPrimitive;
use std::io::Read;
impl Machine { impl Machine {
fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey { pub(super)
fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
match name {
&ClauseName::User(ref rc) => rc.table.clone(),
_ => self.indices.atom_tbl()
}
}
fn compile_into_machine<R: Read>(&mut self, src: R, name: ClauseName) -> EvalSession
{
match name.owning_module().as_str() {
"user" => compile_user_module(self, src),
_ => compile_into_module(self, src, name)
}
}
fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey
{
let name = self.machine_st[name].clone(); let name = self.machine_st[name].clone();
let arity = self.machine_st[arity].clone(); let arity = self.machine_st[arity].clone();
@@ -25,12 +44,10 @@ impl Machine {
(name, arity) (name, arity)
} }
fn print_new_dynamic_clause(&self, addrs: VecDeque<Addr>, name: RegType, arity: RegType) fn print_new_dynamic_clause(&self, addrs: VecDeque<Addr>, name: ClauseName, arity: usize)
-> String -> String
{ {
let mut output = PrinterOutputter::new(); let mut output = PrinterOutputter::new();
let (name, arity) = self.get_predicate_key(name, arity);
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str()); output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
for addr in addrs { for addr in addrs {
@@ -56,11 +73,12 @@ impl Machine {
self.indices.dynamic_code_dir.remove(&(name, arity)); self.indices.dynamic_code_dir.remove(&(name, arity));
} }
fn handle_eval_result_from_dynamic_compile(&mut self, pred_str: String, src: ClauseName) fn handle_eval_result_from_dynamic_compile(&mut self, pred_str: String, name: ClauseName,
src: ClauseName)
{ {
let machine_st = mem::replace(&mut self.machine_st, MachineState::new()); let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
let result = compile_user_module(self, pred_str.as_bytes());
let result = self.compile_into_machine(pred_str.as_bytes(), name);
self.machine_st = machine_st; self.machine_st = machine_st;
if let EvalSession::Error(err) = result { if let EvalSession::Error(err) = result {
@@ -75,6 +93,8 @@ impl Machine {
fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace) fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace)
{ {
let (name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
let stub = MachineError::functor_stub(place.predicate_name(), 1); let stub = MachineError::functor_stub(place.predicate_name(), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) { let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
Ok(addrs) => { Ok(addrs) => {
@@ -82,16 +102,17 @@ impl Machine {
let added_clause = self.machine_st[temp_v!(1)].clone(); let added_clause = self.machine_st[temp_v!(1)].clone();
place.push_to_queue(&mut addrs, added_clause); place.push_to_queue(&mut addrs, added_clause);
self.print_new_dynamic_clause(addrs, temp_v!(3), temp_v!(4)) self.print_new_dynamic_clause(addrs, name.clone(), arity)
}, },
Err(err) => Err(err) =>
return self.machine_st.throw_exception(err) return self.machine_st.throw_exception(err)
}; };
self.handle_eval_result_from_dynamic_compile(pred_str, place.predicate_name()); self.handle_eval_result_from_dynamic_compile(pred_str, name, place.predicate_name());
} }
fn retract_from_dynamic_predicate(&mut self) { fn retract_from_dynamic_predicate(&mut self)
{
let index = self.machine_st[temp_v!(3)].clone(); let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) { let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(), Addr::Con(Constant::Number(Number::Integer(n))) => n.to_usize().unwrap(),
@@ -99,6 +120,8 @@ impl Machine {
}; };
let stub = MachineError::functor_stub(clause_name!("retract"), 1); let stub = MachineError::functor_stub(clause_name!("retract"), 1);
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) { let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
Ok(addrs) => { Ok(addrs) => {
let mut addrs = VecDeque::from(addrs); let mut addrs = VecDeque::from(addrs);
@@ -109,13 +132,13 @@ impl Machine {
return; return;
} }
self.print_new_dynamic_clause(addrs, temp_v!(1), temp_v!(2)) self.print_new_dynamic_clause(addrs, name.clone(), arity)
}, },
Err(err) => Err(err) =>
return self.machine_st.throw_exception(err) return self.machine_st.throw_exception(err)
}; };
self.handle_eval_result_from_dynamic_compile(pred_str, clause_name!("retract")); self.handle_eval_result_from_dynamic_compile(pred_str, name, clause_name!("retract"));
} }
pub(super) pub(super)

View File

@@ -369,6 +369,7 @@ impl MachineState {
pub enum SessionError { pub enum SessionError {
CannotOverwriteBuiltIn(ClauseName), CannotOverwriteBuiltIn(ClauseName),
CannotOverwriteDynamicClause(ClauseName),
CannotOverwriteImport(ClauseName), CannotOverwriteImport(ClauseName),
ModuleDoesNotContainExport, ModuleDoesNotContainExport,
ModuleNotFound, ModuleNotFound,

View File

@@ -389,16 +389,27 @@ pub struct IndexStore {
} }
impl IndexStore { impl IndexStore {
pub fn predicate_exists(&self, name: ClauseName, arity: usize, pub fn predicate_exists(&self, name: ClauseName, module: ClauseName, arity: usize,
op_spec: Option<(usize, Specifier)>) op_spec: Option<(usize, Specifier)>)
-> bool -> bool
{ {
match ClauseType::from(name, arity, op_spec) { match self.modules.get(&module) {
ClauseType::Named(name, arity, _) => Some(module) =>
self.code_dir.contains_key(&(name, arity)), match ClauseType::from(name, arity, op_spec) {
ClauseType::Op(op_decl, ..) => ClauseType::Named(name, arity, _) =>
self.code_dir.contains_key(&(op_decl.name(), op_decl.arity())), module.code_dir.contains_key(&(name, arity)),
_ => true ClauseType::Op(op_decl, ..) =>
module.code_dir.contains_key(&(op_decl.name(), op_decl.arity())),
_ => true
},
None =>
match ClauseType::from(name, arity, op_spec) {
ClauseType::Named(name, arity, _) =>
self.code_dir.contains_key(&(name, arity)),
ClauseType::Op(op_decl, ..) =>
self.code_dir.contains_key(&(op_decl.name(), op_decl.arity())),
_ => true
}
} }
} }

View File

@@ -226,7 +226,7 @@ impl Machine {
// ensure we don't try to overwrite an existing predicate from a different module. // ensure we don't try to overwrite an existing predicate from a different module.
if !existing_idx.is_undefined() && !idx.is_undefined() { if !existing_idx.is_undefined() && !idx.is_undefined() {
// allow the overwriting of user-level predicates by all other predicates. // allow the overwriting of user-level predicates by all other predicates.
if existing_idx.module_name() == key.0.owning_module() { if existing_idx.module_name().as_str() == "user" {
continue; continue;
} }

View File

@@ -614,12 +614,16 @@ impl MachineState {
self.fail = match self.store(self.deref(head)) { self.fail = match self.store(self.deref(head)) {
Addr::Str(s) => Addr::Str(s) =>
match self.heap[s].clone() { match self.heap[s].clone() {
HeapCellValue::NamedStr(arity, name, op_spec) => HeapCellValue::NamedStr(arity, name, op_spec) => {
indices.predicate_exists(name, arity, op_spec), let module = name.owning_module();
indices.predicate_exists(name, module, arity, op_spec)
},
_ => unreachable!() _ => unreachable!()
}, },
Addr::Con(Constant::Atom(name, op_spec)) => Addr::Con(Constant::Atom(name, op_spec)) => {
indices.predicate_exists(name, 0, op_spec), let module = name.owning_module();
indices.predicate_exists(name, module, 0, op_spec)
},
head => { head => {
let err = MachineError::type_error(ValidType::Callable, head); let err = MachineError::type_error(ValidType::Callable, head);
let stub = MachineError::functor_stub(clause_name!("clause"), 2); let stub = MachineError::functor_stub(clause_name!("clause"), 2);

View File

@@ -249,19 +249,27 @@ impl fmt::Display for IndexingInstruction {
impl fmt::Display for SessionError { impl fmt::Display for SessionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&SessionError::CannotOverwriteDynamicClause(ref msg) =>
write!(f, "cannot overwrite dynamic predicate {}", msg),
&SessionError::CannotOverwriteBuiltIn(ref msg) => &SessionError::CannotOverwriteBuiltIn(ref msg) =>
write!(f, "cannot overwrite {}", msg), write!(f, "cannot overwrite {}", msg),
&SessionError::CannotOverwriteImport(ref msg) => &SessionError::CannotOverwriteImport(ref msg) =>
write!(f, "cannot overwrite import {}", msg), write!(f, "cannot overwrite import {}", msg),
&SessionError::ModuleNotFound => write!(f, "module not found."), &SessionError::ModuleNotFound => write!(f, "module not found."),
&SessionError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."), &SessionError::ModuleDoesNotContainExport =>
&SessionError::QueryFailure => write!(f, "false."), write!(f, "module does not contain claimed export."),
&SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)), &SessionError::QueryFailure =>
write!(f, "false."),
&SessionError::QueryFailureWithException(ref e) =>
write!(f, "{}", error_string(e)),
&SessionError::OpIsInfixAndPostFix => &SessionError::OpIsInfixAndPostFix =>
write!(f, "cannot define an op to be both postfix and infix."), write!(f, "cannot define an op to be both postfix and infix."),
&SessionError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."), &SessionError::NamelessEntry =>
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()), write!(f, "the predicate head is not an atom or clause."),
&SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt") &SessionError::ParserError(ref e) =>
write!(f, "syntax_error({})", e.as_str()),
&SessionError::UserPrompt =>
write!(f, "enter predicate at [user] prompt")
} }
} }
} }