* `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`
```
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
InvalidModuleExport,
InvalidRuleHead,
InvalidUseModuleDecl,
+ InvalidModuleResolution,
MissingQuote,
ParseBigInt,
ParseFloat,
&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(')') {
}
}
-#[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)]
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
pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
{
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);
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());
}
-fn use_module(module: &mut Option<Module>, submodule: &Module, indices: &mut MachineCodeIndex)
+fn use_module(module: &mut Option<Module>, submodule: &Module, indices: &mut MachineCodeIndices)
{
indices.use_module(submodule);
}
fn use_qualified_module(module: &mut Option<Module>, submodule: &Module, exports: &Vec<PredicateKey>,
- indices: &mut MachineCodeIndex)
+ indices: &mut MachineCodeIndices)
{
indices.use_qualified_module(submodule, 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);
}
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)
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)
}
}
}
(>>)/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).
:- 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).
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));
pub(crate) struct CodeDirs<'a> {
code_dir: &'a CodeDir,
- modules: &'a HashMap<ClauseName, Module>
+ modules: &'a ModuleDir
}
impl<'a> CodeDirs<'a> {
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<HeapCellValue>>;
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)
}
}
}
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);
}
}
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);
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));
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()
}
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);
} 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;
&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;
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<Fixity>) -> ClauseType
{
}
}
-impl<'a> SubModuleUser for MachineCodeIndex<'a> {
+impl<'a> SubModuleUser for MachineCodeIndices<'a> {
fn op_dir(&mut self) -> &mut OpDir {
self.op_dir
}
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);
self.ms.atom_tbl.clone()
}
- pub fn use_qualified_module_in_toplevel(&mut self, name: ClauseName, exports: Vec<PredicateKey>) -> EvalSession
+ pub fn use_qualified_module_in_toplevel(&mut self, name: ClauseName, exports: Vec<PredicateKey>)
+ -> 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)
};
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)
};
}}
}
-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 }
)
}
-Subproject commit 25b422477921de898dd50b0aa33be8fac5a0ec61
+Subproject commit a7b81b591bce10f93a5f835336c588be763516c6
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;
found_cut_var
}
+fn module_resolution_call(mod_name: Term, body: Term) -> Result<QueryTerm, ParserError> {
+ 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<QueryTerm>, Vec<TopLevel>),
Decl(TopLevel, Vec<TopLevel>)
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<QueryTerm, ParserError>
{
match term {
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();
}
}
- fn setup_query(&mut self, idx: &mut MachineCodeIndex, terms: Vec<Box<Term>>, blocks_cuts: bool)
+ fn setup_query(&mut self, idx: &mut MachineCodeIndices, terms: Vec<Box<Term>>, blocks_cuts: bool)
-> Result<Vec<QueryTerm>, ParserError>
{
let mut query_terms = vec![];
Ok(query_terms)
}
- fn setup_rule(&mut self, idx: &mut MachineCodeIndex, mut terms: Vec<Box<Term>>, blocks_cuts: bool)
+ fn setup_rule(&mut self, idx: &mut MachineCodeIndices, mut terms: Vec<Box<Term>>, blocks_cuts: bool)
-> Result<Rule, ParserError>
{
let post_head_terms = terms.drain(1..).collect();
}
}
- 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<TopLevel, ParserError>
{
match term {
}
}
- fn try_terms_to_tls<Iter>(&mut self, idx: &mut MachineCodeIndex, terms: Iter, blocks_cuts: bool)
+ fn try_terms_to_tls<Iter>(&mut self, idx: &mut MachineCodeIndices, terms: Iter, blocks_cuts: bool)
-> Result<VecDeque<TopLevel>, ParserError>
where Iter: IntoIterator<Item=Term>
{
Ok(results)
}
- fn parse_queue(&mut self, idx: &mut MachineCodeIndex) -> Result<VecDeque<TopLevel>, ParserError>
+ fn parse_queue(&mut self, idx: &mut MachineCodeIndices) -> Result<VecDeque<TopLevel>, ParserError>
{
let mut queue = VecDeque::new();
pub struct TopLevelWorker<'a, R: Read> {
pub parser: Parser<R>,
- indices: MachineCodeIndex<'a>
+ indices: MachineCodeIndices<'a>
}
impl<'a, R: Read> TopLevelWorker<'a, R> {
- pub fn new(inner: R, atom_tbl: TabledData<Atom>, indices: MachineCodeIndex<'a>) -> Self {
+ pub fn new(inner: R, atom_tbl: TabledData<Atom>, indices: MachineCodeIndices<'a>) -> Self {
TopLevelWorker { parser: Parser::new(inner, atom_tbl), indices }
}
}
pub
- fn consume(&mut self, indices: &mut MachineCodeIndex) -> Result<Option<Declaration>, SessionError>
+ fn consume(&mut self, indices: &mut MachineCodeIndices) -> Result<Option<Declaration>, SessionError>
{
let mut preds = vec![];