From: Mark Thom Date: Sun, 8 Jul 2018 21:21:09 +0000 (-0600) Subject: finalize the module resolution operator. X-Git-Tag: v0.8.110~447 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=cd03b7795f66626d7c29531d94f1b43f24e22393;p=scryer-prolog.git finalize the module resolution operator. --- diff --git a/README.md b/README.md index 908a79cc..5629e7ae 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ The following predicates are built-in to rusty-wam. * `is/2` works for `(+)/2`, `(-)/{1,2}`, `(*)/2`, `(//)/2`, `(div)/2`, `(/)/2`, `(rdiv)/2`, `(xor)/2`, `(rem)/2`, `(mod)/2`, `(/\)/2`, `(\/)/2`, `(>>)/2`, `(<<)/2`. * Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`. +* `(:)/2` * `(@>)/2` * `(@>=)/2` * `(@=<)/2` @@ -277,4 +278,13 @@ prolog> :- use_module(library(lists), [member/2]). ``` A qualified `use_module` can be used to remove imports from the -toplevel by calling it with an empty import list. \ No newline at end of file +toplevel by calling it with an empty import list. + +The `(:)/2` operator is used to resolve calls to predicates +not within the current working namespace: + +``` +prolog> ?- lists:member(X, Xs). +``` + +This is a debugging kludge. Mostly. \ No newline at end of file diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 4ddaa2d0..51b6cce7 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -495,6 +495,7 @@ pub enum ParserError InvalidModuleExport, InvalidRuleHead, InvalidUseModuleDecl, + InvalidModuleResolution, MissingQuote, ParseBigInt, ParseFloat, @@ -860,7 +861,7 @@ impl ClauseName { &ClauseName::User(ref name) => name.as_ref() } } - + pub fn defrock_brackets(self) -> Self { fn defrock_brackets(s: &str) -> &str { if s.starts_with('(') && s.ends_with(')') { @@ -1532,9 +1533,11 @@ impl HeapCellValue { } } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy,PartialEq)] pub enum IndexPtr { - Undefined, Index(usize) + Undefined, Index(usize), + Module // This is a resolved module call. The module + // targeted is in the wrapping CodeIndex, and the name is in the ClauseType. } #[derive(Clone)] @@ -1542,7 +1545,7 @@ pub struct CodeIndex(pub Rc>); impl CodeIndex { 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 { true diff --git a/src/prolog/compile.rs b/src/prolog/compile.rs index 35b0c697..d2906acb 100644 --- a/src/prolog/compile.rs +++ b/src/prolog/compile.rs @@ -38,10 +38,9 @@ fn print_code(code: &Code) { pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result { let atom_tbl = wam.atom_tbl(); - let index = MachineCodeIndex { + let index = MachineCodeIndices { code_dir: &mut wam.code_dir, op_dir: &mut wam.op_dir, - //modules: &wam.modules }; let mut worker = TopLevelWorker::new(buffer.as_bytes(), atom_tbl, index); @@ -189,11 +188,11 @@ impl<'a> ListingCompiler<'a> { Ok(code) } - fn add_code(self, code: Code, indices: MachineCodeIndex) { + fn add_code(self, code: Code, indices: MachineCodeIndices) { 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 { module.code_dir.extend(as_module_code_dir(code_dir)); module.op_dir.extend(op_dir.into_iter()); @@ -206,7 +205,7 @@ impl<'a> ListingCompiler<'a> { } -fn use_module(module: &mut Option, submodule: &Module, indices: &mut MachineCodeIndex) +fn use_module(module: &mut Option, submodule: &Module, indices: &mut MachineCodeIndices) { indices.use_module(submodule); @@ -216,7 +215,7 @@ fn use_module(module: &mut Option, submodule: &Module, indices: &mut Mac } fn use_qualified_module(module: &mut Option, submodule: &Module, exports: &Vec, - indices: &mut MachineCodeIndex) + indices: &mut MachineCodeIndices) { indices.use_qualified_module(submodule, exports); @@ -226,7 +225,7 @@ fn use_qualified_module(module: &mut Option, submodule: &Module, exports } pub -fn compile_listing(wam: &mut Machine, src_str: &str, mut indices: MachineCodeIndex) -> EvalSession +fn compile_listing(wam: &mut Machine, src_str: &str, mut indices: MachineCodeIndices) -> EvalSession { let mut worker = TopLevelBatchWorker::new(src_str.as_bytes(), wam.atom_tbl()); let mut compiler = ListingCompiler::new(wam); @@ -264,12 +263,12 @@ fn compile_listing(wam: &mut Machine, src_str: &str, mut indices: MachineCodeInd } pub fn compile_user_module(wam: &mut Machine, src_str: &str) -> EvalSession { - let mut indices = machine_code_index!(&mut CodeDir::new(), &mut default_op_dir()); + let mut indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir()); 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); + return EvalSession::from(SessionError::ModuleNotFound); } compile_listing(wam, src_str, indices) diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 5a55b0f1..7f346b45 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -12,8 +12,12 @@ 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) + &IndexPtr::Module => + write!(f, ""), + &IndexPtr::Undefined => + write!(f, "undefined"), + &IndexPtr::Index(i) => + write!(f, "{}", i) } } } diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 35953a40..94334f2c 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -5,7 +5,7 @@ (>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2, (-)/1, (>=)/2, (=<)/2, (,)/2, (->)/2, (;)/2, (=..)/2, (==)/2, (\==)/2, (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2, (\=@=)/2, - catch/3, throw/1, true/0, false/0]). + (:)/2, catch/3, throw/1, true/0, false/0]). % arithmetic operators. :- op(700, xfx, is). @@ -51,6 +51,9 @@ :- op(700, xfx, =@=). :- op(700, xfx, \=@=). +% module resolution operator. +:- op(600, xfy, :). + % the maximum arity flag. needs to be replaced with current_prolog_flag(max_arity, MAX_ARITY). max_arity(63). diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index a3cb86da..c23dd49b 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -35,6 +35,22 @@ impl MachineError { MachineError { stub, from: ErrorProvenance::Received } } + pub(super) + fn module_resolution_error(h: usize, mod_name: ClauseName, name: ClauseName, arity: usize) -> Self + { + let mod_name = HeapCellValue::Addr(Addr::Con(Constant::Atom(mod_name))); + let name = HeapCellValue::Addr(Addr::Con(Constant::Atom(name))); + + let mut stub = functor!("evaluation_error", 1, [HeapCellValue::Addr(Addr::HeapCell(h + 2))]); + + stub.append(&mut functor!("/", 2, [HeapCellValue::Addr(Addr::HeapCell(h + 2 + 3)), + heap_integer!(arity)], + Fixity::In)); + stub.append(&mut functor!(":", 2, [mod_name, name], Fixity::In)); + + MachineError { stub, from: ErrorProvenance::Constructed } + } + pub(super) fn existence_error(h: usize, name: ClauseName, arity: usize) -> Self { let mut stub = functor!("existence_error", 2, [heap_atom!("procedure"), heap_str!(3 + h)]); stub.append(&mut Self::functor_stub(name, arity)); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 5ccf181c..8e1a9a04 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -33,7 +33,7 @@ impl Ball { pub(crate) struct CodeDirs<'a> { code_dir: &'a CodeDir, - modules: &'a HashMap + modules: &'a ModuleDir } impl<'a> CodeDirs<'a> { @@ -225,6 +225,21 @@ pub struct MachineState { pub(super) last_call: bool } +fn call_at_index(machine_st: &mut MachineState, module_name: ClauseName, arity: usize, idx: usize) +{ + machine_st.cp.assign_if_local(machine_st.p.clone() + 1); + machine_st.num_of_args = arity; + machine_st.b0 = machine_st.b; + machine_st.p = dir_entry!(idx, module_name); +} + +fn execute_at_index(machine_st: &mut MachineState, module_name: ClauseName, arity: usize, idx: usize) +{ + machine_st.num_of_args = arity; + machine_st.b0 = machine_st.b; + machine_st.p = dir_entry!(idx, module_name); +} + pub(crate) type CallResult = Result<(), Vec>; pub(crate) trait CallPolicy: Any { @@ -352,35 +367,46 @@ pub(crate) trait CallPolicy: Any { } fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex) + idx: CodeIndex, code_dirs: CodeDirs) -> CallResult { if machine_st.last_call { - self.try_execute(machine_st, name, arity, idx) + self.try_execute(machine_st, name, arity, idx, code_dirs) } else { - self.try_call(machine_st, name, arity, idx) + self.try_call(machine_st, name, arity, idx, code_dirs) } } - fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName, - arity: usize, idx: CodeIndex) + fn try_call(&mut self, machine_st: &mut MachineState, name: ClauseName, arity: usize, + idx: CodeIndex, code_dirs: CodeDirs) -> CallResult - { + { match idx.0.borrow().0 { + IndexPtr::Module => { + let stub = MachineError::functor_stub(name.clone(), arity); + let module_name = idx.0.borrow().1.clone(); + let h = machine_st.heap.h; + + if let Some(ref idx) = code_dirs.get(name.clone(), arity, module_name.clone()) { + if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 { + call_at_index(machine_st, module_name, arity, compiled_tl_index); + return Ok(()); + } + } + + let err = MachineError::module_resolution_error(h, module_name, name, arity); + return Err(machine_st.error_form(err, stub)); + }, IndexPtr::Undefined => { let stub = MachineError::functor_stub(name.clone(), arity); let h = machine_st.heap.h; - + return Err(machine_st.error_form(MachineError::existence_error(h, name, arity), stub)); }, IndexPtr::Index(compiled_tl_index) => { let module_name = idx.0.borrow().1.clone(); - - machine_st.cp.assign_if_local(machine_st.p.clone() + 1); - machine_st.num_of_args = arity; - machine_st.b0 = machine_st.b; - machine_st.p = dir_entry!(compiled_tl_index, module_name); + call_at_index(machine_st, module_name, arity, compiled_tl_index) } } @@ -388,23 +414,35 @@ pub(crate) trait CallPolicy: Any { } fn try_execute<'a>(&mut self, machine_st: &mut MachineState, name: ClauseName, - arity: usize, idx: CodeIndex) + arity: usize, idx: CodeIndex, code_dirs: CodeDirs) -> CallResult { match idx.0.borrow().0 { + IndexPtr::Module => { + let stub = MachineError::functor_stub(name.clone(), arity); + let module_name = idx.0.borrow().1.clone(); + let h = machine_st.heap.h; + + if let Some(ref idx) = code_dirs.get(name.clone(), arity, module_name.clone()) { + if let IndexPtr::Index(compiled_tl_index) = idx.0.borrow().0 { + execute_at_index(machine_st, module_name, arity, compiled_tl_index); + return Ok(()); + } + } + + let err = MachineError::module_resolution_error(h, module_name, name, arity); + return Err(machine_st.error_form(err, stub)); + }, IndexPtr::Undefined => { let stub = MachineError::functor_stub(name.clone(), arity); let h = machine_st.heap.h; - + return Err(machine_st.error_form(MachineError::existence_error(h, name, arity), stub)); }, IndexPtr::Index(compiled_tl_index) => { let module_name = idx.0.borrow().1.clone(); - - machine_st.num_of_args = arity; - machine_st.b0 = machine_st.b; - machine_st.p = dir_entry!(compiled_tl_index, module_name); + execute_at_index(machine_st, module_name, arity, compiled_tl_index); } } @@ -552,7 +590,7 @@ pub(crate) trait CallPolicy: Any { machine_st.execute_inlined(&inlined), ClauseType::Op(..) | ClauseType::Named(..) => if let Some(idx) = code_dirs.get(name.clone(), arity, user) { - self.context_call(machine_st, name, arity, idx)?; + self.context_call(machine_st, name, arity, idx, code_dirs)?; } else { let h = machine_st.heap.h; let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); @@ -562,7 +600,7 @@ pub(crate) trait CallPolicy: Any { ClauseType::System(_) => { let name = Addr::Con(Constant::Atom(name)); let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - + return Err(machine_st.error_form(MachineError::type_error(ValidType::Callable, name), stub)); @@ -576,10 +614,10 @@ pub(crate) trait CallPolicy: Any { impl CallPolicy for CallWithInferenceLimitCallPolicy { fn context_call(&mut self, machine_st: &mut MachineState, name: ClauseName, - arity: usize, idx: CodeIndex) + arity: usize, idx: CodeIndex, code_dirs: CodeDirs) -> CallResult { - self.prev_policy.context_call(machine_st, name, arity, idx)?; + self.prev_policy.context_call(machine_st, name, arity, idx, code_dirs)?; self.increment() } @@ -747,7 +785,7 @@ impl CutPolicy for SCCCutPolicy { let b = machine_st.b; if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() { - if b > b0 { + if b > b0 { machine_st.b = b0; machine_st.tidy_trail(); machine_st.or_stack.truncate(machine_st.b); @@ -755,8 +793,8 @@ impl CutPolicy for SCCCutPolicy { } else { machine_st.fail = true; return; - } - + } + if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() { if machine_st.b < b_cutoff { machine_st.block = prev_block; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 984d1dc2..2ee034c0 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1832,7 +1832,8 @@ impl MachineState { &ControlInstruction::CallClause(ClauseType::Named(ref name, ref idx), arity, _, lco) | &ControlInstruction::CallClause(ClauseType::Op(ref name, _, ref idx), arity, _, lco) => { self.last_call = lco; - try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone())); + try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(), + code_dirs)); }, &ControlInstruction::CallClause(ClauseType::System(ref ct), _, _, lco) => { self.last_call = lco; diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index e42981f0..dc3bdd19 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -17,13 +17,12 @@ use std::mem::swap; use std::ops::Index; use std::rc::Rc; -pub struct MachineCodeIndex<'a> { - pub code_dir: &'a mut CodeDir, - pub op_dir: &'a mut OpDir, -// pub modules: &'a ModuleDir +pub struct MachineCodeIndices<'a> { + pub(super) code_dir: &'a mut CodeDir, + pub(super) op_dir: &'a mut OpDir, } -impl<'a> MachineCodeIndex<'a> { +impl<'a> MachineCodeIndices<'a> { pub(super) fn lookup(&mut self, name: ClauseName, arity: usize, fixity: Option) -> ClauseType { @@ -73,7 +72,7 @@ impl Index for Machine { } } -impl<'a> SubModuleUser for MachineCodeIndex<'a> { +impl<'a> SubModuleUser for MachineCodeIndices<'a> { fn op_dir(&mut self) -> &mut OpDir { self.op_dir } @@ -111,7 +110,7 @@ impl Machine { cached_query: None }; - let indices = machine_code_index!(&mut CodeDir::new(), &mut default_op_dir()); + let indices = machine_code_indices!(&mut CodeDir::new(), &mut default_op_dir()); compile_listing(&mut wam, BUILTINS, indices); compile_user_module(&mut wam, LISTS); @@ -178,14 +177,14 @@ impl Machine { self.ms.atom_tbl.clone() } - pub fn use_qualified_module_in_toplevel(&mut self, name: ClauseName, exports: Vec) -> EvalSession + 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_index!(&mut self.code_dir, &mut self.op_dir); - //&self.modules); + let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir); indices.use_qualified_module(&mut module, &exports) }; @@ -202,8 +201,7 @@ impl Machine { if let Some(mut module) = self.modules.remove(&name) { let result = { - let mut indices = machine_code_index!(&mut self.code_dir, &mut self.op_dir); - //&self.modules); + let mut indices = machine_code_indices!(&mut self.code_dir, &mut self.op_dir); indices.use_module(&mut module) }; diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index f3bb0d50..fc287fc7 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -233,9 +233,9 @@ macro_rules! set_code_index { }} } -macro_rules! machine_code_index { +macro_rules! machine_code_indices { ($code_dir:expr, $op_dir:expr) => ( //, $modules:expr) => ( - MachineCodeIndex { code_dir: $code_dir, op_dir: $op_dir } //, modules: $modules } + MachineCodeIndices { code_dir: $code_dir, op_dir: $op_dir } //, modules: $modules } ) } diff --git a/src/prolog/parser b/src/prolog/parser index 25b42247..a7b81b59 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit 25b422477921de898dd50b0aa33be8fac5a0ec61 +Subproject commit a7b81b591bce10f93a5f835336c588be763516c6 diff --git a/src/prolog/toplevel.rs b/src/prolog/toplevel.rs index 3fac73ca..2c82ea56 100644 --- a/src/prolog/toplevel.rs +++ b/src/prolog/toplevel.rs @@ -5,7 +5,7 @@ use prolog::parser::parser::*; use prolog::tabled_rc::*; use std::collections::{HashSet, VecDeque}; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::io::Read; use std::mem; use std::rc::Rc; @@ -288,6 +288,17 @@ fn mark_cut_variables(terms: &mut Vec) -> bool { found_cut_var } +fn module_resolution_call(mod_name: Term, body: Term) -> Result { + if let Term::Constant(_, Constant::Atom(mod_name)) = mod_name { + if let Term::Clause(_, name, terms, _) = body { + let idx = CodeIndex(Rc::new(RefCell::new((IndexPtr::Module, mod_name)))); + return Ok(QueryTerm::Clause(Cell::default(), ClauseType::Named(name, idx), terms)); + } + } + + Err(ParserError::InvalidModuleResolution) +} + pub enum TopLevelPacket { Query(Vec, Vec), Decl(TopLevel, Vec) @@ -391,7 +402,7 @@ impl RelationWorker { self.fabricate_rule(fold_by_str(prec_seq, body_term, comma_sym)) } - fn to_query_term(&mut self, indices: &mut MachineCodeIndex, term: Term) + fn to_query_term(&mut self, indices: &mut MachineCodeIndices, term: Term) -> Result { match term { @@ -411,6 +422,11 @@ impl RelationWorker { self.queue.push_back(clauses); Ok(QueryTerm::Jump(stub)) + } else if name.as_str() == ":" && terms.len() == 2 { + let callee = *terms.pop().unwrap(); + let mod_name = *terms.pop().unwrap(); + + module_resolution_call(mod_name, callee) } else if name.as_str() == "->" && terms.len() == 2 { let conq = *terms.pop().unwrap(); let prec = *terms.pop().unwrap(); @@ -460,7 +476,7 @@ impl RelationWorker { } } - fn setup_query(&mut self, idx: &mut MachineCodeIndex, terms: Vec>, blocks_cuts: bool) + fn setup_query(&mut self, idx: &mut MachineCodeIndices, terms: Vec>, blocks_cuts: bool) -> Result, ParserError> { let mut query_terms = vec![]; @@ -495,7 +511,7 @@ impl RelationWorker { Ok(query_terms) } - fn setup_rule(&mut self, idx: &mut MachineCodeIndex, mut terms: Vec>, blocks_cuts: bool) + fn setup_rule(&mut self, idx: &mut MachineCodeIndices, mut terms: Vec>, blocks_cuts: bool) -> Result { let post_head_terms = terms.drain(1..).collect(); @@ -512,7 +528,7 @@ impl RelationWorker { } } - fn try_term_to_tl(&mut self, idx: &mut MachineCodeIndex, term: Term, blocks_cuts: bool) + fn try_term_to_tl(&mut self, idx: &mut MachineCodeIndices, term: Term, blocks_cuts: bool) -> Result { match term { @@ -531,7 +547,7 @@ impl RelationWorker { } } - fn try_terms_to_tls(&mut self, idx: &mut MachineCodeIndex, terms: Iter, blocks_cuts: bool) + fn try_terms_to_tls(&mut self, idx: &mut MachineCodeIndices, terms: Iter, blocks_cuts: bool) -> Result, ParserError> where Iter: IntoIterator { @@ -544,7 +560,7 @@ impl RelationWorker { Ok(results) } - fn parse_queue(&mut self, idx: &mut MachineCodeIndex) -> Result, ParserError> + fn parse_queue(&mut self, idx: &mut MachineCodeIndices) -> Result, ParserError> { let mut queue = VecDeque::new(); @@ -563,11 +579,11 @@ impl RelationWorker { pub struct TopLevelWorker<'a, R: Read> { pub parser: Parser, - indices: MachineCodeIndex<'a> + indices: MachineCodeIndices<'a> } impl<'a, R: Read> TopLevelWorker<'a, R> { - pub fn new(inner: R, atom_tbl: TabledData, indices: MachineCodeIndex<'a>) -> Self { + pub fn new(inner: R, atom_tbl: TabledData, indices: MachineCodeIndices<'a>) -> Self { TopLevelWorker { parser: Parser::new(inner, atom_tbl), indices } } @@ -612,7 +628,7 @@ impl TopLevelBatchWorker { } pub - fn consume(&mut self, indices: &mut MachineCodeIndex) -> Result, SessionError> + fn consume(&mut self, indices: &mut MachineCodeIndices) -> Result, SessionError> { let mut preds = vec![];