From 989d44d7022d4a2789748dbe89f84411df79d145 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 18 Apr 2018 19:24:32 -0600 Subject: [PATCH] make module code entries immutable (re: issue #27) --- src/prolog/ast.rs | 72 +++++++++++++----------- src/prolog/builtins.rs | 2 +- src/prolog/io.rs | 4 +- src/prolog/machine/machine_state.rs | 23 ++++---- src/prolog/machine/machine_state_impl.rs | 2 +- src/prolog/machine/mod.rs | 27 ++++++--- src/prolog/parser | 2 +- 7 files changed, 73 insertions(+), 59 deletions(-) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index bee15064..47edbdcb 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -139,6 +139,8 @@ pub type OpDirKey = (ClauseName, Fixity); // name and fixity -> operator type and precedence. pub type OpDir = HashMap; +pub type ModuleCodeDir = HashMap; + pub type CodeDir = HashMap; pub type TermDir = HashMap; @@ -152,68 +154,63 @@ pub struct ModuleDecl { pub struct Module { pub module_decl: ModuleDecl, - pub code_dir: CodeDir, + pub code_dir: ModuleCodeDir, pub op_dir: OpDir } impl Module { pub fn new(module_decl: ModuleDecl) -> Self { Module { module_decl, - code_dir: CodeDir::new(), + code_dir: ModuleCodeDir::new(), op_dir: OpDir::new() } } } +pub fn as_module_code_dir(code_dir: CodeDir) -> ModuleCodeDir { + code_dir.into_iter() + .map(|(k, code_idx)| (k, ModuleCodeIndex(code_idx.0.get(), code_idx.1))) + .collect() +} + impl SubModuleUser for Module { fn op_dir(&mut self) -> &mut OpDir { &mut self.op_dir } - fn code_dir(&mut self) -> &mut CodeDir { - &mut self.code_dir + fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) { + self.code_dir.insert((name, arity), idx); } } pub trait SubModuleUser { fn op_dir(&mut self) -> &mut OpDir; - fn code_dir(&mut self) -> &mut CodeDir; + fn insert_dir_entry(&mut self, ClauseName, usize, ModuleCodeIndex); // returns true on successful import. fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool { let name = name.defrock_brackets(); - - if arity == 1 { - if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Pre)) { - self.op_dir().insert((name.clone(), Fixity::Pre), op_data.clone()); - } - - if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Post)) { - self.op_dir().insert((name.clone(), Fixity::Post), op_data.clone()); - } - } else if arity == 2 { - if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::In)) { - self.op_dir().insert((name.clone(), Fixity::In), op_data.clone()); + + { + let mut insert_op_dir = |fix| { + if let Some(op_data) = submodule.op_dir.get(&(name.clone(), fix)) { + self.op_dir().insert((name.clone(), fix), op_data.clone()); + } + }; + + if arity == 1 { + insert_op_dir(Fixity::Pre); + insert_op_dir(Fixity::Post); + } else if arity == 2 { + insert_op_dir(Fixity::In); } } - - if self.code_dir().contains_key(&(name.clone(), arity)) { - println!("warning: overwriting {}/{}", &name, arity); - } - + if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) { - if let Some(ref mut global_code_data) = self.code_dir().get_mut(&(name.clone(), arity)) { - global_code_data.1 = code_data.1.clone(); - global_code_data.0.set(code_data.0.get()); - - return true; // done to appease the borrow checker. - } - - self.code_dir().insert((name, arity), code_data.clone()); + self.insert_dir_entry(name, arity, code_data.clone()); + true } else { - return false; + false } - - true } fn use_qualified_module(&mut self, submodule: &Module, exports: Vec) -> EvalSession @@ -1397,6 +1394,15 @@ pub enum IndexPtr { #[derive(Clone)] pub struct CodeIndex(pub Rc>, pub ClauseName); +#[derive(Clone)] +pub struct ModuleCodeIndex(pub IndexPtr, pub ClauseName); + +impl From for CodeIndex { + fn from(value: ModuleCodeIndex) -> Self { + CodeIndex(Rc::new(Cell::new(value.0)), value.1.clone()) + } +} + impl Default for CodeIndex { fn default() -> Self { CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined)), clause_name!("")) diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 71d4c7e3..bb88d6bf 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -832,5 +832,5 @@ pub fn builtin_module() -> Module module_decl.exports.push((clause_name!("call"), arity)); } - Module { module_decl, code_dir, op_dir } + Module { module_decl, code_dir: as_module_code_dir(code_dir), op_dir } } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 1b005bd3..9259054f 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -642,7 +642,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession } else { return EvalSession::from(EvalError::ModuleNotFound); } - + wam.use_module_in_toplevel(name); }, TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)), _) => { @@ -689,7 +689,7 @@ pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession } if let Some(mut module) = module { - module.code_dir.extend(code_dir.into_iter()); + module.code_dir.extend(as_module_code_dir(code_dir)); module.op_dir.extend(op_dir.into_iter()); wam.add_module(module, code); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index c76edba2..81cff9c9 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -24,19 +24,17 @@ impl<'a> CodeDirs<'a> { CodeDirs { code_dir, modules } } - fn get_current_code_dir(&self, p: &CodePtr) -> &CodeDir { - let module_name = p.module_name(); - - match module_name { - ClauseName::BuiltIn("user") | ClauseName::BuiltIn("builtin") => self.code_dir, - _ => &self.modules.get(&module_name).unwrap().code_dir + pub(super) fn get(&self, name: ClauseName, arity: usize, in_mod: ClauseName) -> Option + { + match in_mod.as_str() { + "user" | "builtin" => self.code_dir.get(&(name, arity)).cloned(), + _ => match self.modules.get(&in_mod) { + Some(&Module { ref code_dir, .. }) => + code_dir.get(&(name, arity)).cloned().map(CodeIndex::from), + None => None + } } } - - pub(super) fn get(&self, name: ClauseName, arity: usize, p: &CodePtr) -> Option { - let code_dir = self.get_current_code_dir(p); - code_dir.get(&(name, arity)).cloned() - } } pub(super) struct DuplicateTerm<'a> { @@ -428,7 +426,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.clone(), arity, &machine_st.p.clone()) { + if let Some(idx) = code_dirs.get(name.clone(), arity, machine_st.p.module_name()) + { self.context_call(machine_st, name, arity, idx, lco) } else { Err(predicate_existence_error(name, arity, machine_st.heap.h)) diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 3d893e87..6d1b33f0 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -909,7 +909,7 @@ 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.clone(), arity, &self.p.clone()) { + if let Some(idx) = code_dirs.get(name.clone(), arity, self.p.module_name()) { 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 10ed2074..8c4b977e 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -53,8 +53,17 @@ impl<'a> SubModuleUser for MachineCodeIndex<'a> { self.op_dir } - fn code_dir(&mut self) -> &mut CodeDir { - self.code_dir + fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) { + if let Some(ref mut code_idx) = self.code_dir.get_mut(&(name.clone(), arity)) { + println!("warning: overwriting {}/{}", &name, arity); + + code_idx.0.set(idx.0); + code_idx.1 = idx.1; + + return; + } + + self.code_dir.insert((name, arity), CodeIndex::from(idx)); } } @@ -132,8 +141,8 @@ impl Machine { { self.remove_module(name.clone()); - match self.modules.get(&name) { - Some(ref module) => { + match self.modules.get_mut(&name) { + Some(ref mut module) => { let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir, op_dir: &mut self.op_dir }; @@ -146,8 +155,8 @@ impl Machine { pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession { self.remove_module(name.clone()); - match self.modules.get(&name) { - Some(ref module) => { + match self.modules.get_mut(&name) { + Some(ref mut module) => { let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir, op_dir: &mut self.op_dir }; @@ -196,7 +205,7 @@ impl Machine { entry.0.set(IndexPtr::Index(offset)); entry.1 = clause_name!("user"); - + EvalSession::EntrySuccess } @@ -312,8 +321,8 @@ impl Machine { let e = self.ms.e; let r = var_data.as_reg_type().reg_num(); let addr = self.ms.and_stack[e][r].clone(); - - heap_locs.insert(var.clone(), addr); + + heap_locs.insert(var.clone(), addr); }, &VarData::Temp(cn, _, _) if cn == chunk_num => { let r = var_data.as_reg_type(); diff --git a/src/prolog/parser b/src/prolog/parser index 0e9dd3a0..1b3bcc77 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit 0e9dd3a01f21c6457bd1bcb35518ccdb502c82bd +Subproject commit 1b3bcc77f2b9d264c9753653ae87bfa3b4c11081 -- 2.54.0