From fbf16e2aeadee570754b3f351a30af2f39a694dd Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 12 Sep 2018 20:46:15 -0600 Subject: [PATCH] provisional changes to module insertion --- src/main.rs | 35 ++--- src/prolog/compile.rs | 222 ++++++++++++++-------------- src/prolog/instructions.rs | 103 ++++++++++--- src/prolog/machine/machine_state.rs | 62 -------- src/prolog/machine/mod.rs | 197 ++++++++++-------------- src/prolog/machine/term_writer.rs | 54 +++++++ src/prolog/macros.rs | 7 + src/prolog/read.rs | 30 +--- src/prolog/toplevel.rs | 71 +++------ src/prolog/write.rs | 6 +- 10 files changed, 375 insertions(+), 412 deletions(-) create mode 100644 src/prolog/machine/term_writer.rs diff --git a/src/main.rs b/src/main.rs index a4fce5f1..fd910dee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,22 +11,11 @@ use prolog::machine::*; use prolog::read::*; use prolog::write::*; -use std::io::{Write, stdout}; +use std::io::{Write, stdin, stdout}; #[cfg(test)] mod tests; -fn parse_and_compile_line(wam: &mut Machine, buffer: &str) -{ - match parse_code(wam, buffer) { - Ok(packet) => { - let result = compile_packet(wam, packet); - print(wam, result); - }, - Err(e) => print(wam, EvalSession::from(e)) - } -} - fn prolog_repl() { let mut wam = Machine::new(); @@ -35,17 +24,14 @@ fn prolog_repl() { stdout().flush().unwrap(); match read_toplevel(&mut wam) { - Ok(Input::Term(term)) => - match compile_term(&mut wam, term) { - Ok(packet) => { - let result = compile_packet(&mut wam, packet); - print(&mut wam, result); - }, - Err(e) => print(&mut wam, EvalSession::from(e)) - }, - Ok(Input::Line(line)) => parse_and_compile_line(&mut wam, line.as_str()), - Ok(Input::Batch(batch)) => { - let result = compile_user_module(&mut wam, batch.as_bytes()); + Ok(Input::Term(term)) => { + let result = compile_term(&mut wam, term); + print(&mut wam, result) + }, + Ok(Input::Batch) => { + let stdin = stdin(); + let result = compile_user_module(&mut wam, stdin.lock()); + print(&mut wam, result); }, Ok(Input::Quit) => break, @@ -53,7 +39,8 @@ fn prolog_repl() { wam.clear(); continue; }, - Err(e) => print(&mut wam, EvalSession::from(e)) + Err(e) => + print(&mut wam, EvalSession::from(e)) }; wam.reset(); diff --git a/src/prolog/compile.rs b/src/prolog/compile.rs index 9c6183ff..94feb835 100644 --- a/src/prolog/compile.rs +++ b/src/prolog/compile.rs @@ -38,22 +38,6 @@ fn print_code(code: &Code) { } } -pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result -{ - let atom_tbl = wam.atom_tbl(); - let flags = wam.machine_flags(); - - let indices = machine_code_indices!(&mut wam.code_dir, &mut wam.op_dir, &mut HashMap::new()); - - let mut worker = TopLevelWorker::new(buffer.as_bytes(), atom_tbl, flags, indices); - worker.parse_code() -} - -pub fn compile_term(wam: &mut Machine, term: Term) -> Result { - let indices = machine_code_indices!(&mut wam.code_dir, &mut wam.op_dir, &mut HashMap::new()); - parse_term(term, indices) -} - // throw errors if declaration or query found. fn compile_relation(tl: &TopLevel, non_counted_bt: bool, flags: MachineFlags) -> Result { @@ -112,78 +96,89 @@ fn compile_query(terms: Vec, queue: Vec, flags: MachineFlag Ok((code, cg.take_vars())) } -fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec) -> EvalSession -{ - match tl { - TopLevel::Declaration(Declaration::Op(op_decl)) => { - try_eval_session!(op_decl.submit(clause_name!("user"), &mut wam.op_dir)); - EvalSession::EntrySuccess - }, - TopLevel::Declaration(Declaration::UseModule(name)) => - wam.use_module_in_toplevel(name), - TopLevel::Declaration(Declaration::UseQualifiedModule(name, exports)) => - wam.use_qualified_module_in_toplevel(name, exports), - TopLevel::Declaration(_) => - EvalSession::from(ParserError::InvalidModuleDecl), - _ => { - let name = try_eval_session!(if let Some(name) = tl.name() { - match ClauseType::from(name.clone(), tl.arity(), None) { - ClauseType::Named(..) | ClauseType::Op(..) => - Ok(name), - _ => { - let err_str = format!("{}/{}", name.as_str(), tl.arity()); - Err(SessionError::ImpermissibleEntry(err_str)) - } - } - } else { - Err(SessionError::NamelessEntry) - }); - - let mut code = try_eval_session!(compile_relation(&tl, false, wam.machine_flags())); - try_eval_session!(compile_appendix(&mut code, queue, false, wam.machine_flags())); - - if !code.is_empty() { - wam.add_user_code(name, tl.arity(), code) - } else { - EvalSession::from(SessionError::ImpermissibleEntry(String::from("no code generated."))) - } - } - } +fn package_term(wam: &mut Machine, term: Term) -> Result { + let indices = machine_code_indices!(&mut wam.code_dir, &mut wam.op_dir, &mut wam.modules); + parse_term(term, indices) } -pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession +pub fn compile_term(wam: &mut Machine, term: Term) -> EvalSession { - match tl { + let packet = try_eval_session!(package_term(wam, term)); + + match packet { TopLevelPacket::Query(terms, queue) => match compile_query(terms, queue, wam.machine_flags()) { Ok((mut code, vars)) => wam.submit_query(code, vars), Err(e) => EvalSession::from(e) }, - TopLevelPacket::Decl(tl, queue) => - compile_decl(wam, tl, queue) + TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => { + let mut compiler = ListingCompiler::new(); + let mut indices = default_machine_code_indices!(); + + try_eval_session!(compiler.process_decl(decl, wam, &mut indices)); + try_eval_session!(compiler.add_code(wam, vec![], indices)); + + EvalSession::EntrySuccess + }, + _ => EvalSession::from(SessionError::UserPrompt) } } -pub struct ListingCompiler<'a> { - wam: &'a mut Machine, +pub struct ListingCompiler { non_counted_bt_preds: HashSet, - module: Option + module: Option, } -impl<'a> ListingCompiler<'a> { - pub fn new(wam: &'a mut Machine) -> Self { - ListingCompiler { wam, - module: None, - non_counted_bt_preds: HashSet::new() } +impl ListingCompiler { + pub fn new() -> Self { + ListingCompiler { module: None, non_counted_bt_preds: HashSet::new() } + } + + fn use_module(&mut self, submodule: Module, wam: &mut Machine, + indices: &mut MachineCodeIndices) -> Result<(), SessionError> + { + let mod_name = self.get_module_name(); + + indices.use_module(&submodule)?; + + if let &mut Some(ref mut module) = &mut self.module { + module.remove_module(mod_name, &submodule); + module.use_module(&submodule)?; + } else { + wam.remove_module(&submodule); + } + + wam.insert_module(submodule); + Ok(()) } + fn use_qualified_module(&mut self, submodule: Module, wam: &mut Machine, + exports: &Vec, indices: &mut MachineCodeIndices) + -> Result<(), SessionError> + { + let mod_name = self.get_module_name(); + + indices.use_qualified_module(&submodule, exports)?; + + if let &mut Some(ref mut module) = &mut self.module { + module.remove_module(mod_name, &submodule); + module.use_qualified_module(&submodule, exports)?; + } else { + wam.remove_module(&submodule); + } + + wam.insert_module(submodule); + Ok(()) + } + fn get_module_name(&self) -> ClauseName { self.module.as_ref() .map(|module| module.module_decl.name.clone()) .unwrap_or(ClauseName::BuiltIn("user")) } - fn generate_code(&mut self, decls: Vec<(Predicate, VecDeque)>, code_dir: &mut CodeDir) + fn generate_code(&mut self, decls: Vec<(Predicate, VecDeque)>, + wam: &Machine, code_dir: &mut CodeDir) -> Result { let mut code = vec![]; @@ -196,12 +191,11 @@ impl<'a> ListingCompiler<'a> { let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity)); - let p = code.len() + self.wam.code_size(); + let p = code.len() + wam.code_size(); let mut decl_code = compile_relation(&TopLevel::Predicate(decl), non_counted_bt, - self.wam.machine_flags())?; + wam.machine_flags())?; - compile_appendix(&mut decl_code, Vec::from(queue), non_counted_bt, - self.wam.machine_flags())?; + compile_appendix(&mut decl_code, Vec::from(queue), non_counted_bt, wam.machine_flags())?; let idx = code_dir.entry((name, arity)).or_insert(CodeIndex::default()); set_code_index!(idx, IndexPtr::Index(p), self.get_module_name()); @@ -212,26 +206,30 @@ impl<'a> ListingCompiler<'a> { Ok(code) } - fn add_code(self, code: Code, indices: MachineCodeIndices) { + fn add_code(&mut self, wam: &mut Machine, code: Code, indices: MachineCodeIndices) + -> Result<(), SessionError> + { let code_dir = mem::replace(indices.code_dir, HashMap::new()); let op_dir = mem::replace(indices.op_dir, HashMap::new()); - if let Some(mut module) = self.module { + if let Some(mut module) = self.module.take() { module.code_dir.extend(as_module_code_dir(code_dir)); module.op_dir.extend(op_dir.into_iter()); - self.wam.add_module(module, code); + wam.add_module(module, code); } else { - self.wam.add_batched_code(code, code_dir); - self.wam.add_batched_ops(op_dir); + wam.add_batched_code(code, code_dir)?; + wam.add_batched_ops(op_dir); } + + Ok(()) } fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) { self.non_counted_bt_preds.insert((name, arity)); } - fn process_decl(&mut self, decl: Declaration, indices: &mut MachineCodeIndices) + fn process_decl(&mut self, decl: Declaration, wam: &mut Machine, indices: &mut MachineCodeIndices) -> Result<(), SessionError> { match decl { @@ -240,22 +238,20 @@ impl<'a> ListingCompiler<'a> { Declaration::Op(op_decl) => op_decl.submit(self.get_module_name(), &mut indices.op_dir), Declaration::UseModule(name) => - if let Some(ref submodule) = self.wam.get_module(name.clone()) { - Ok(use_module(&mut self.module, submodule, indices)) + if let Some(submodule) = wam.take_module(name) { + self.use_module(submodule, wam, indices) } else { Err(SessionError::ModuleNotFound) }, Declaration::UseQualifiedModule(name, exports) => - if let Some(ref submodule) = self.wam.get_module(name.clone()) { - Ok(use_qualified_module(&mut self.module, submodule, &exports, indices)) + if let Some(submodule) = wam.take_module(name) { + self.use_qualified_module(submodule, wam, &exports, indices) } else { Err(SessionError::ModuleNotFound) }, Declaration::Module(module_decl) => if self.module.is_none() { - // worker.source_mod = module_decl.name.clone(); - self.module = Some(Module::new(module_decl)); - Ok(()) + Ok(self.module = Some(Module::new(module_decl))) } else { Err(SessionError::from(ParserError::InvalidModuleDecl)) } @@ -263,50 +259,46 @@ impl<'a> ListingCompiler<'a> { } } -fn use_module(module: &mut Option, submodule: &Module, indices: &mut MachineCodeIndices) -{ - indices.use_module(submodule); - - if let &mut Some(ref mut module) = module { - module.use_module(submodule); - } -} - -fn use_qualified_module(module: &mut Option, submodule: &Module, exports: &Vec, - indices: &mut MachineCodeIndices) -{ - indices.use_qualified_module(submodule, exports); - - if let &mut Some(ref mut module) = module { - module.use_qualified_module(submodule, exports); - } -} - -pub -fn compile_listing(wam: &mut Machine, src: R, mut indices: MachineCodeIndices) -> EvalSession +pub fn compile_listing<'a, R>(wam: &mut Machine, src: R, mut indices: MachineCodeIndices<'a>, + mut toplevel_indices: MachineCodeIndices<'a>) + -> EvalSession + where R: Read { let mut worker = TopLevelBatchWorker::new(src, wam.atom_tbl(), wam.machine_flags()); - let mut compiler = ListingCompiler::new(wam); + let mut compiler = ListingCompiler::new(); + let mut toplevel_results = vec![]; while let Some(decl) = try_eval_session!(worker.consume(&mut indices)) { - try_eval_session!(compiler.process_decl(decl, &mut indices)); + if decl.is_module_decl() { + toplevel_indices.copy_and_swap(&mut indices); + mem::swap(&mut worker.results, &mut toplevel_results); + } + + try_eval_session!(compiler.process_decl(decl, wam, &mut indices)); } - let code = try_eval_session!(compiler.generate_code(worker.results, &mut indices.code_dir)); - compiler.add_code(code, indices); + let module_code = try_eval_session!(compiler.generate_code(worker.results, wam, + &mut indices.code_dir)); + let toplvl_code = try_eval_session!(compiler.generate_code(toplevel_results, wam, + &mut toplevel_indices.code_dir)); + + try_eval_session!(compiler.add_code(wam, module_code, indices)); + try_eval_session!(compiler.add_code(wam, toplvl_code, toplevel_indices)); EvalSession::EntrySuccess } -pub fn compile_user_module(wam: &mut Machine, src: R) -> EvalSession { - let mut indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(), - &mut HashMap::new()); - +fn setup_indices(wam: &Machine, indices: &mut MachineCodeIndices) -> Result<(), SessionError> { if let Some(ref builtins) = wam.modules.get(&clause_name!("builtins")) { - indices.use_module(builtins); + indices.use_module(builtins) } else { - return EvalSession::from(SessionError::ModuleNotFound); + Err(SessionError::ModuleNotFound) } +} + +pub fn compile_user_module(wam: &mut Machine, src: R) -> EvalSession { + let mut indices = default_machine_code_indices!(); + try_eval_session!(setup_indices(&wam, &mut indices)); - compile_listing(wam, src, indices) + compile_listing(wam, src, indices, default_machine_code_indices!()) } diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index 1563648b..a19642dc 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -791,6 +791,11 @@ impl CodeIndex { false } } + + #[inline] + pub fn module_name(&self) -> ClauseName { + self.0.borrow().1.clone() + } } #[derive(Clone)] @@ -1033,20 +1038,54 @@ pub fn as_module_code_dir(code_dir: CodeDir) -> ModuleCodeDir { .collect() } -impl SubModuleUser for Module { - fn op_dir(&mut self) -> &mut OpDir { - &mut self.op_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 remove_code_index(&mut self, key: PredicateKey); + fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option; + fn insert_dir_entry(&mut self, ClauseName, usize, ModuleCodeIndex); + fn remove_module(&mut self, mod_name: ClauseName, module: &Module) { + for (name, arity) in module.module_decl.exports.iter().cloned() { + let name = name.defrock_brackets(); + + match self.get_code_index((name.clone(), arity), mod_name.clone()) { + Some(CodeIndex (ref code_idx)) => { + if &code_idx.borrow().1 != &module.module_decl.name { + continue; + } + + self.remove_code_index((name.clone(), arity)); + + // remove or respecify ops. + if arity == 2 { + if let Some((_, _, mod_name)) = self.op_dir().get(&(name.clone(), Fixity::In)).cloned() + { + if mod_name == module.module_decl.name { + self.op_dir().remove(&(name.clone(), Fixity::In)); + } + } + } else if arity == 1 { + if let Some((_, _, mod_name)) = self.op_dir().get(&(name.clone(), Fixity::Pre)).cloned() + { + if mod_name == module.module_decl.name { + self.op_dir().remove(&(name.clone(), Fixity::Pre)); + } + } + + if let Some((_, _, mod_name)) = self.op_dir().get(&(name.clone(), Fixity::Post)).cloned() + { + if mod_name == module.module_decl.name { + self.op_dir().remove(&(name.clone(), Fixity::Post)); + } + } + } + }, + _ => {} + }; + } + } + // returns true on successful import. fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool { let name = name.defrock_brackets(); @@ -1076,7 +1115,8 @@ pub trait SubModuleUser { } } - fn use_qualified_module(&mut self, submodule: &Module, exports: &Vec) -> EvalSession + fn use_qualified_module(&mut self, submodule: &Module, exports: &Vec) + -> Result<(), SessionError> { for (name, arity) in exports.iter().cloned() { if !submodule.module_decl.exports.contains(&(name.clone(), arity)) { @@ -1084,21 +1124,39 @@ pub trait SubModuleUser { } if !self.import_decl(name, arity, submodule) { - return EvalSession::from(SessionError::ModuleDoesNotContainExport); + return Err(SessionError::ModuleDoesNotContainExport); } } - EvalSession::EntrySuccess + Ok(()) } - fn use_module(&mut self, submodule: &Module) -> EvalSession { + fn use_module(&mut self, submodule: &Module) -> Result<(), SessionError> { for (name, arity) in submodule.module_decl.exports.iter().cloned() { if !self.import_decl(name, arity, submodule) { - return EvalSession::from(SessionError::ModuleDoesNotContainExport); + return Err(SessionError::ModuleDoesNotContainExport); } } - EvalSession::EntrySuccess + Ok(()) + } +} + +impl SubModuleUser for Module { + fn op_dir(&mut self) -> &mut OpDir { + &mut self.op_dir + } + + fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option { + self.code_dir.get(&key).cloned().map(CodeIndex::from) + } + + fn remove_code_index(&mut self, key: PredicateKey) { + self.code_dir.remove(&key); + } + + fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) { + self.code_dir.insert((name, arity), idx); } } @@ -1110,6 +1168,13 @@ pub enum Declaration { UseQualifiedModule(ClauseName, Vec) } +impl Declaration { + #[inline] + pub fn is_module_decl(&self) -> bool { + if let &Declaration::Module(_) = self { true } else { false } + } +} + pub enum TopLevel { Declaration(Declaration), Fact(Term), @@ -1224,14 +1289,16 @@ pub type HeapVarDict = HashMap, Addr>; pub type AllocVarDict = HashMap, VarData>; pub enum SessionError { - ImpermissibleEntry(String), + CannotOverwriteBuiltIn(String), + CannotOverwriteImport(String), ModuleDoesNotContainExport, ModuleNotFound, NamelessEntry, OpIsInfixAndPostFix, ParserError(ParserError), QueryFailure, - QueryFailureWithException(String) + QueryFailureWithException(String), + UserPrompt } pub enum EvalSession { diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index a2a4c09e..c48748b8 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -12,7 +12,6 @@ use prolog::or_stack::*; use downcast::Any; -use std::cell::RefCell; use std::cmp::Ordering; use std::io::stdin; use std::mem::swap; @@ -68,67 +67,6 @@ impl<'a> CodeDirs<'a> { } } -pub trait CodeDirsAdapter<'a> { - fn get_code_index(&self, PredicateKey, ClauseName) -> Option; - fn get_op(&self, OpDirKey) -> Option<(Specifier, usize, ClauseName)>; - fn op_dir(&self) -> &OpDir; -} - -fn get_code_index(code_dir: &CodeDir, modules: &ModuleDir, key: PredicateKey, module: ClauseName) - -> Option -{ - match module.as_str() { - "user" | "builtin" => code_dir.get(&key).cloned(), - _ => modules.get(&module).and_then(|ref module| { - module.code_dir.get(&key).cloned().map(CodeIndex::from) - }) - } -} - -impl<'a> CodeDirsAdapter<'a> for MachineCodeIndices<'a> { - fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option { - get_code_index(&self.code_dir, &self.modules, key, module) - } - - fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> { - self.op_dir.get(&key).cloned() - } - - fn op_dir(&self) -> &OpDir { - &self.op_dir - } -} - -impl<'a> CodeDirsAdapter<'a> for CodeDirs<'a> { - fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option { - get_code_index(&self.code_dir, &self.modules, key, module) - } - - fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> { - self.op_dir.get(&key).cloned() - } - - fn op_dir(&self) -> &OpDir { - &self.op_dir - } -} - -impl<'a> CodeDirsAdapter<'a> for &'a Module { - fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option { - self.code_dir.get(&key) - .cloned() - .map(|ModuleCodeIndex(ptr, module)| CodeIndex(Rc::new(RefCell::new((ptr, module))))) - } - - fn get_op(&self, key: OpDirKey) -> Option<(Specifier, usize, ClauseName)> { - self.op_dir.get(&key).cloned() - } - - fn op_dir(&self) -> &OpDir { - &self.op_dir - } -} - pub(super) struct DuplicateTerm<'a> { state: &'a mut MachineState } diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 8c9f16a4..d07bf29b 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -27,8 +27,18 @@ pub struct MachineCodeIndices<'a> { } impl<'a> MachineCodeIndices<'a> { + #[inline] + pub(super) fn copy_and_swap(&mut self, other: &mut MachineCodeIndices<'a>) { + *self.code_dir = other.code_dir.clone(); + *self.op_dir = other.op_dir.clone(); + + swap(&mut self.code_dir, &mut other.code_dir); + swap(&mut self.op_dir, &mut other.op_dir); + swap(&mut self.modules, &mut other.modules); + } + pub(super) - fn lookup(&mut self, name: ClauseName, arity: usize, fixity: Option) -> ClauseType + fn get_clause_type(&mut self, name: ClauseName, arity: usize, fixity: Option) -> ClauseType { match ClauseType::from(name, arity, fixity) { ClauseType::Named(name, _) => { @@ -67,6 +77,17 @@ pub struct Machine { cached_query: Option } +fn get_code_index(code_dir: &CodeDir, modules: &ModuleDir, key: PredicateKey, module: ClauseName) + -> Option +{ + match module.as_str() { + "user" | "builtin" => code_dir.get(&key).cloned(), + _ => modules.get(&module).and_then(|ref module| { + module.code_dir.get(&key).cloned().map(CodeIndex::from) + }) + } +} + impl Index for Machine { type Output = Line; @@ -88,6 +109,14 @@ impl<'a> SubModuleUser for MachineCodeIndices<'a> { self.op_dir } + fn get_code_index(&self, key: PredicateKey, module: ClauseName) -> Option { + get_code_index(&self.code_dir, &self.modules, key, module) + } + + fn remove_code_index(&mut self, key: PredicateKey) { + self.code_dir.remove(&key); + } + 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)) { if !code_idx.is_undefined() { @@ -116,22 +145,19 @@ impl Machine { code: Code::new(), code_dir: CodeDir::new(), op_dir: default_op_dir(), - // term_dir: TermDir::new(), + // term_dir: TermDir::new(), modules: HashMap::new(), cached_query: None }; - let indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(), - &mut HashMap::new()); - - compile_listing(&mut wam, BUILTINS.as_bytes(), indices); + compile_listing(&mut wam, BUILTINS.as_bytes(), + default_machine_code_indices!(), + default_machine_code_indices!()); compile_user_module(&mut wam, LISTS.as_bytes()); compile_user_module(&mut wam, CONTROL.as_bytes()); compile_user_module(&mut wam, QUEUES.as_bytes()); - wam.use_module_in_toplevel(clause_name!("builtins")); - wam } @@ -139,53 +165,6 @@ impl Machine { pub fn machine_flags(&self) -> MachineFlags { self.ms.flags } - - fn remove_module(&mut self, module_name: ClauseName) { - let iter = if let Some(submodule) = self.modules.get(&module_name) { - submodule.module_decl.exports.iter().cloned() - } else { - return; - }; - - for (name, arity) in iter { - let name = name.defrock_brackets(); - - match self.code_dir.get(&(name.clone(), arity)).cloned() { - Some(CodeIndex (ref code_idx)) => { - if &code_idx.borrow().1 != &module_name { - continue; - } - - self.code_dir.remove(&(name.clone(), arity)); - - // remove or respecify ops. - if arity == 2 { - if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::In)).cloned() - { - if mod_name == module_name { - self.op_dir.remove(&(name.clone(), Fixity::In)); - } - } - } else if arity == 1 { - if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::Pre)).cloned() - { - if mod_name == module_name { - self.op_dir.remove(&(name.clone(), Fixity::Pre)); - } - } - - if let Some((_, _, mod_name)) = self.op_dir.get(&(name.clone(), Fixity::Post)).cloned() - { - if mod_name == module_name { - self.op_dir.remove(&(name.clone(), Fixity::Post)); - } - } - } - }, - _ => {} - }; - } - } #[inline] pub fn failed(&self) -> bool { @@ -196,84 +175,68 @@ impl Machine { pub fn atom_tbl(&self) -> TabledData { self.ms.atom_tbl.clone() } - - pub fn use_qualified_module_in_toplevel(&mut self, name: ClauseName, exports: Vec) - -> EvalSession - { - self.remove_module(name.clone()); - - if let Some(mut module) = self.modules.remove(&name) { - let result = { - let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir, - &mut self.modules); - indices.use_qualified_module(&mut module, &exports) - }; - self.modules.insert(name, module); - result - } else { - EvalSession::from(SessionError::ModuleNotFound) - } + pub fn get_module(&self, name: ClauseName) -> Option<&Module> { + self.modules.get(&name) } - pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession + pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) -> Result<(), SessionError> { - self.remove_module(name.clone()); - - if let Some(mut module) = self.modules.remove(&name) { - let result = { - let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir, - &mut self.modules); - indices.use_module(&mut module) + for (ref key, ref idx) in code_dir.iter() { + match ClauseType::from(key.0.clone(), key.1, None) { + ClauseType::Named(..) | ClauseType::Op(..) => {}, + _ => { + // ensure we don't try to overwrite the name/arity of a builtin. + let err_str = format!("{}/{}", key.0, key.1); + return Err(SessionError::CannotOverwriteBuiltIn(err_str)); + } }; - self.modules.insert(name, module); - result - } else { - EvalSession::from(SessionError::ModuleNotFound) - } - } + if idx.module_name().as_str() == "builtins" { + continue; + } - pub fn get_module(&self, name: ClauseName) -> Option<&Module> { - self.modules.get(&name) - } + if let Some(ref existing_idx) = self.code_dir.get(&key) { + // ensure we don't try to overwrite an existing predicate from a different module. + if !existing_idx.is_undefined() { + if existing_idx.module_name() != idx.module_name() { + let err_str = format!("{}/{} from module {}", key.0, key.1, + existing_idx.module_name().as_str()); + return Err(SessionError::CannotOverwriteImport(err_str)); + } + } + } + } - pub fn add_batched_code(&mut self, mut code: Code, code_dir: CodeDir) { - self.code.append(&mut code); - self.code_dir.extend(code_dir.into_iter()); + self.code.extend(code.into_iter()); + Ok(self.code_dir.extend(code_dir.into_iter())) } + #[inline] pub fn add_batched_ops(&mut self, op_dir: OpDir) { self.op_dir.extend(op_dir.into_iter()); } - pub fn add_module(&mut self, module: Module, code: Code) { - self.modules.insert(module.module_decl.name.clone(), module); - self.code.extend(code.into_iter()); + #[inline] + pub fn remove_module(&mut self, module: &Module) { + let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir, &mut self.modules); + indices.remove_module(clause_name!("user"), module); } - pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession - { - match self.code_dir.get(&(name.clone(), arity)) { - Some(&CodeIndex (ref idx)) if idx.borrow().1 != clause_name!("user") => - if !(&CodeIndex(idx.clone())).is_undefined() { - return EvalSession::from(SessionError::ImpermissibleEntry(format!("{}/{}", - name, - arity))) - }, - _ => {} - }; - - let offset = self.code.len(); + #[inline] + pub fn take_module(&mut self, name: ClauseName) -> Option { + self.modules.remove(&name) + } + #[inline] + pub fn insert_module(&mut self, module: Module) { + self.modules.insert(module.module_decl.name.clone(), module); + } + + #[inline] + pub fn add_module(&mut self, module: Module, code: Code) { + self.modules.insert(module.module_decl.name.clone(), module); self.code.extend(code.into_iter()); - //self.term_dir.insert((name.clone(), arity), pred); - - let idx = self.code_dir.entry((name, arity)) - .or_insert(CodeIndex::from((offset, clause_name!("user")))); - - set_code_index!(idx, IndexPtr::Index(offset), clause_name!("user")); - EvalSession::EntrySuccess } pub fn code_size(&self) -> usize { @@ -422,7 +385,7 @@ impl Machine { while self.ms.p < end_ptr { if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.ms.p { match &self[LocalCodePtr::TopLevel(cn, p)] { - &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => { + &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => { self.record_var_places(cn, alloc_locs, heap_locs); cn += 1; }, @@ -506,7 +469,7 @@ impl Machine { { let mut sorted_vars: Vec<(&Rc, &Addr)> = var_dir.iter().collect(); sorted_vars.sort_by_key(|ref v| v.0); - + for (var, addr) in sorted_vars { let fmt = TermFormatter {}; output = self.ms.print_var_eq(var.clone(), addr.clone(), var_dir, fmt, output); diff --git a/src/prolog/machine/term_writer.rs b/src/prolog/machine/term_writer.rs new file mode 100644 index 00000000..d094a236 --- /dev/null +++ b/src/prolog/machine/term_writer.rs @@ -0,0 +1,54 @@ +use prolog_parser::ast::*; + +use prolog::heap_iter::*; +use prolog::instructions::*; +use prolog::machine::machine_state::MachineState; + +use std::cell::Cell; +use std::rc::Rc; + +pub fn term_write(machine_st: &MachineState, addr: Addr) -> Result +{ + let pre_order_iter = HCPreOrderIterator::new(machine_st, addr); + let post_order_iter = HCPostOrderIterator::new(pre_order_iter); + + let mut stack = vec![]; + + for value in post_order_iter { + match value { + HeapCellValue::NamedStr(arity, ref name, fixity) + if stack.len() >= arity => { + let stack_len = stack.len(); + let subterms: Vec<_> = stack.drain(stack_len - arity ..).collect(); + + stack.push(Box::new(Term::Clause(Cell::default(), name.clone(), subterms, + fixity))); + }, + HeapCellValue::Addr(Addr::Con(constant)) => + stack.push(Box::new(Term::Constant(Cell::default(), constant))), + HeapCellValue::Addr(Addr::Lis(_)) + if stack.len() >= 2 => { + let stack_len = stack.len(); + let mut iter = stack.drain(stack_len - 2 ..); + + let head = iter.next().unwrap(); + let tail = iter.next().unwrap(); + + stack.push(Box::new(Term::Cons(Cell::default(), head, tail))); + }, + HeapCellValue::Addr(Addr::HeapCell(h)) => + stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}", h))))), + HeapCellValue::Addr(Addr::StackCell(fr, sc)) => + stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}_{}", sc, fr))))), + _ => return Err(ParserError::IncompleteReduction) + } + } + + if let Some(term) = stack.pop() { + if stack.is_empty() { + return Ok(*term); + } + } + + Err(ParserError::IncompleteReduction) +} diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 48712dfc..69f86b3b 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -216,6 +216,13 @@ macro_rules! machine_code_indices { ) } +macro_rules! default_machine_code_indices { + () => ( + machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir(), + &mut HashMap::new()); + ) +} + macro_rules! put_constant { ($lvl:expr, $cons:expr, $r:expr) => ( QueryInstruction::PutConstant($lvl, $cons, $r) diff --git a/src/prolog/read.rs b/src/prolog/read.rs index 7432ec65..b079eef2 100644 --- a/src/prolog/read.rs +++ b/src/prolog/read.rs @@ -25,27 +25,10 @@ impl<'a> TermRef<'a> { pub enum Input { Quit, Clear, - Line(String), - Batch(String), + Batch, Term(Term) } -fn read_lines(buffer: &mut String, end_delim: &str) -> String { - let mut result = String::new(); - let stdin = stdin(); - - buffer.clear(); - stdin.read_line(buffer).unwrap(); - - while &*buffer.trim() != end_delim { - result += buffer.as_str(); - buffer.clear(); - stdin.read_line(buffer).unwrap(); - } - - result -} - pub fn read_toplevel(wam: &Machine) -> Result { let mut buffer = String::new(); @@ -53,16 +36,15 @@ pub fn read_toplevel(wam: &Machine) -> Result { stdin.read_line(&mut buffer).unwrap(); match &*buffer.trim() { - ":{" => Ok(Input::Line(read_lines(&mut buffer, "}:"))), - ":{{" => Ok(Input::Batch(read_lines(&mut buffer, "}}:"))), - "quit" => Ok(Input::Quit), - "clear" => Ok(Input::Clear), - _ => { + "quit" => Ok(Input::Quit), + "clear" => Ok(Input::Clear), + "[user]" => Ok(Input::Batch), + _ => { let mut parser = Parser::new(stdin.lock(), wam.atom_tbl(), wam.machine_flags()); parser.add_to_top(buffer.as_str()); Ok(Input::Term(parser.read_term(&wam.op_dir)?)) - } + } } } diff --git a/src/prolog/toplevel.rs b/src/prolog/toplevel.rs index c731d2e0..267695f6 100644 --- a/src/prolog/toplevel.rs +++ b/src/prolog/toplevel.rs @@ -416,7 +416,7 @@ impl RelationWorker { if name.as_str() == "!" || name.as_str() == "blocked_!" { Ok(QueryTerm::BlockedCut) } else { - let ct = indices.lookup(name, 0, None); + let ct = indices.get_clause_type(name, 0, None); Ok(QueryTerm::Clause(r, ct, vec![], false)) }, Term::Var(_, ref v) if v.as_str() == "!" => @@ -462,7 +462,7 @@ impl RelationWorker { Err(ParserError::InadmissibleQueryTerm) }, _ => { - let ct = indices.lookup(name, terms.len(), fixity); + let ct = indices.get_clause_type(name, terms.len(), fixity); Ok(QueryTerm::Clause(Cell::default(), ct, terms, false)) } }, @@ -496,24 +496,24 @@ impl RelationWorker { } } - fn pre_query_term(&mut self, idx: &mut MachineCodeIndices, term: Term) -> Result + fn pre_query_term(&mut self, indices: &mut MachineCodeIndices, term: Term) -> Result { match term { Term::Clause(r, name, mut subterms, fixity) => if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" { - self.to_query_term(idx, *subterms.pop().unwrap()) + self.to_query_term(indices, *subterms.pop().unwrap()) .map(|mut query_term| { query_term.set_default_caller(); query_term }) } else { - self.to_query_term(idx, Term::Clause(r, name, subterms, fixity)) + self.to_query_term(indices, Term::Clause(r, name, subterms, fixity)) }, - _ => self.to_query_term(idx, term) + _ => self.to_query_term(indices, term) } } - fn setup_query(&mut self, idx: &mut MachineCodeIndices, terms: Vec>, blocks_cuts: bool) + fn setup_query(&mut self, indices: &mut MachineCodeIndices, terms: Vec>, blocks_cuts: bool) -> Result, ParserError> { let mut query_terms = vec![]; @@ -541,18 +541,18 @@ impl RelationWorker { mark_cut_variable(&mut subterm); } - query_terms.push(self.pre_query_term(idx, subterm)?); + query_terms.push(self.pre_query_term(indices, subterm)?); } } Ok(query_terms) } - fn setup_rule(&mut self, idx: &mut MachineCodeIndices, mut terms: Vec>, blocks_cuts: bool) + fn setup_rule(&mut self, indices: &mut MachineCodeIndices, mut terms: Vec>, blocks_cuts: bool) -> Result { let post_head_terms = terms.drain(1..).collect(); - let mut query_terms = try!(self.setup_query(idx, post_head_terms, blocks_cuts)); + let mut query_terms = try!(self.setup_query(indices, post_head_terms, blocks_cuts)); let clauses = query_terms.drain(1 ..).collect(); let qt = query_terms.pop().unwrap(); @@ -565,15 +565,15 @@ impl RelationWorker { } } - fn try_term_to_tl(&mut self, idx: &mut MachineCodeIndices, term: Term, blocks_cuts: bool) + fn try_term_to_tl(&mut self, indices: &mut MachineCodeIndices, term: Term, blocks_cuts: bool) -> Result { match term { Term::Clause(r, name, mut terms, fixity) => if name.as_str() == "?-" { - Ok(TopLevel::Query(try!(self.setup_query(idx, terms, blocks_cuts)))) + Ok(TopLevel::Query(try!(self.setup_query(indices, terms, blocks_cuts)))) } else if name.as_str() == ":-" && terms.len() > 1 { - Ok(TopLevel::Rule(try!(self.setup_rule(idx, terms, blocks_cuts)))) + Ok(TopLevel::Rule(try!(self.setup_rule(indices, terms, blocks_cuts)))) } else if name.as_str() == ":-" && terms.len() == 1 { let term = *terms.pop().unwrap(); Ok(TopLevel::Declaration(try!(setup_declaration(term)))) @@ -584,25 +584,25 @@ impl RelationWorker { } } - fn try_terms_to_tls(&mut self, idx: &mut MachineCodeIndices, terms: Iter, blocks_cuts: bool) - -> Result, ParserError> - where Iter: IntoIterator + fn try_terms_to_tls(&mut self, indices: &mut MachineCodeIndices, terms: I, blocks_cuts: bool) + -> Result, ParserError> + where I: IntoIterator { let mut results = VecDeque::new(); for term in terms.into_iter() { - results.push_back(self.try_term_to_tl(idx, term, blocks_cuts)?); + results.push_back(self.try_term_to_tl(indices, term, blocks_cuts)?); } Ok(results) } - fn parse_queue(&mut self, idx: &mut MachineCodeIndices) -> Result, ParserError> + fn parse_queue(&mut self, indices: &mut MachineCodeIndices) -> Result, ParserError> { let mut queue = VecDeque::new(); while let Some(terms) = self.queue.pop_front() { - let clauses = merge_clauses(&mut self.try_terms_to_tls(idx, terms, false)?)?; + let clauses = merge_clauses(&mut self.try_terms_to_tls(indices, terms, false)?)?; queue.push_back(clauses); } @@ -614,37 +614,6 @@ impl RelationWorker { } } -pub struct TopLevelWorker<'a, R: Read> { - pub parser: Parser, - indices: MachineCodeIndices<'a> -} - -impl<'a, R: Read> TopLevelWorker<'a, R> { - pub fn new(inner: R, atom_tbl: TabledData, flags: MachineFlags, - indices: MachineCodeIndices<'a>) - -> Self - { - TopLevelWorker { parser: Parser::new(inner, atom_tbl, flags), indices } - } - - pub fn parse_code(&mut self) -> Result - { - let mut rel_worker = RelationWorker::new(); - - let terms = self.parser.read(self.indices.op_dir)?; - let mut tls = rel_worker.try_terms_to_tls(&mut self.indices, terms, true)?; - let results = rel_worker.parse_queue(&mut self.indices)?; - - let tl = merge_clauses(&mut tls)?; - - if tls.is_empty() { - Ok(deque_to_packet(tl, results)) - } else { - Err(ParserError::InconsistentEntry) - } - } -} - pub fn parse_term(term: Term, mut indices: MachineCodeIndices) -> Result { let mut rel_worker = RelationWorker::new(); @@ -667,7 +636,7 @@ impl TopLevelBatchWorker { TopLevelBatchWorker { parser: Parser::new(inner, atom_tbl, flags), rel_worker: RelationWorker::new(), results: vec![] } - } + } pub fn consume(&mut self, indices: &mut MachineCodeIndices) -> Result, SessionError> diff --git a/src/prolog/write.rs b/src/prolog/write.rs index c9259dab..c39da26a 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -193,15 +193,19 @@ impl fmt::Display for IndexingInstruction { impl fmt::Display for SessionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + &SessionError::CannotOverwriteBuiltIn(ref msg) => + write!(f, "cannot overwrite {}", msg), + &SessionError::CannotOverwriteImport(ref msg) => + write!(f, "cannot overwrite import {}", msg), &SessionError::ModuleNotFound => write!(f, "module not found."), &SessionError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."), &SessionError::QueryFailure => write!(f, "false."), &SessionError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)), - &SessionError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite {}.", msg), &SessionError::OpIsInfixAndPostFix => 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::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()), + &SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt") } } } -- 2.54.0