add operator exports to module declarations, treat them separately from predicate exports (#230)"

This commit is contained in:
Mark Thom
2019-11-25 23:09:49 -07:00
parent 4e887e3a87
commit 834c57466f
10 changed files with 313 additions and 171 deletions

View File

@@ -574,7 +574,7 @@ impl ListingCompiler {
submodule: ClauseName,
code_repo: &mut CodeRepo,
flags: MachineFlags,
exports: &Vec<PredicateKey>,
exports: &Vec<ModuleExport>,
wam_indices: &mut IndexStore,
indices: &mut IndexStore,
) -> Result<(), SessionError> {
@@ -712,6 +712,24 @@ impl ListingCompiler {
(len, queue_len)
}
fn submit_op(
&mut self,
wam: &Machine,
indices: &mut IndexStore,
op_decl: &OpDecl,
) -> Result<(), SessionError> {
let spec = get_desc(
op_decl.name(),
composite_op!(
self.module.is_some(),
&wam.indices.op_dir,
&mut indices.op_dir
),
);
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
}
fn process_decl(
&mut self,
decl: Declaration,
@@ -730,6 +748,7 @@ impl ListingCompiler {
.code_repo
.compile_hook(hook, flags)
.map_err(SessionError::from);
wam.code_repo.truncate_terms(key, len, queue_len);
result
@@ -738,16 +757,7 @@ impl ListingCompiler {
Ok(self.add_non_counted_bt_flag(name, arity))
}
Declaration::Op(op_decl) => {
let spec = get_desc(
op_decl.name(),
composite_op!(
self.module.is_some(),
&wam.indices.op_dir,
&mut indices.op_dir
),
);
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
self.submit_op(wam, indices, &op_decl)
}
Declaration::UseModule(ModuleSource::Library(name)) => {
let name = if !wam.indices.modules.contains_key(&name) {
@@ -779,6 +789,12 @@ impl ListingCompiler {
let module_name = module_decl.name.clone();
let atom_tbl = TabledData::new(module_name.to_rc());
for export in module_decl.exports.iter() {
if let ModuleExport::OpDecl(ref op_decl) = export {
self.submit_op(wam, indices, op_decl)?;
}
}
Ok(self.module = Some(Module::new(module_decl, atom_tbl)))
} else {
Err(SessionError::from(ParserError::InvalidModuleDecl))
@@ -959,8 +975,9 @@ fn compile_work_impl(
if let Some(mut module) = compiler.module.take() {
if module.is_impromptu_module {
module.module_decl.exports = indices.code_dir.keys().cloned()
.filter(|(name, _)| name.owning_module().as_str() != "builtins")
.collect();
.filter(|(name, _)| name.owning_module().as_str() != "builtins")
.map(ModuleExport::PredicateKey)
.collect();
}
let mut clause_code_generator =

View File

@@ -34,6 +34,7 @@ use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::modules::*;
use crate::prolog::machine::toplevel::*;
use crate::prolog::read::PrologStream;
use indexmap::IndexMap;
@@ -139,7 +140,7 @@ impl SubModuleUser for IndexStore {
code_repo: &mut CodeRepo,
flags: MachineFlags,
submodule: &Module,
exports: &Vec<PredicateKey>,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError> {
use_qualified_module(self, submodule, exports)?;
submodule
@@ -400,30 +401,64 @@ impl Machine {
return;
}
fn extract_predicate_indicator_list(&mut self) -> Vec<PredicateKey>
fn extract_module_export_list(&mut self) -> Result<Vec<ModuleExport>, ParserError>
{
let export_list = self.machine_st[temp_v!(2)].clone();
let mut export_list = self.machine_st.store(self.machine_st.deref(export_list));
let mut export_list = self.machine_st[temp_v!(2)].clone();
let mut exports = vec![];
while let Addr::Lis(l) = export_list {
while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) {
match &self.machine_st.heap[l] {
&HeapCellValue::Addr(Addr::Str(s)) => {
let name = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
name.clone(),
_ =>
unreachable!()
};
match &self.machine_st.heap[s] {
HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 2 && name.as_str() == "/" => {
let name = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
name.clone(),
_ =>
unreachable!()
};
let arity = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
arity.to_usize().unwrap(),
_ =>
unreachable!()
};
exports.push(ModuleExport::PredicateKey((name, arity)));
}
HeapCellValue::NamedStr(arity, ref name, _)
if *arity == 3 && name.as_str() == "op" => {
let name = match &self.machine_st.heap[s+3] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
name.clone(),
_ =>
unreachable!()
};
let arity = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
arity.to_usize().unwrap(),
_ =>
unreachable!()
};
let spec = match &self.machine_st.heap[s+2] {
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
name.clone(),
_ =>
unreachable!()
};
let prec = match &self.machine_st.heap[s+1] {
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
arity.to_usize().unwrap(),
_ =>
unreachable!()
};
exports.push((name, arity));
exports.push(ModuleExport::OpDecl(to_op_decl(
prec,
spec.as_str(),
name,
)?));
}
_ => unreachable!()
}
}
_ => unreachable!()
}
@@ -431,7 +466,7 @@ impl Machine {
export_list = self.machine_st.heap[l+1].as_addr(l+1);
}
exports
Ok(exports)
}
fn use_module<ToSource>(&mut self, to_src: ToSource)
@@ -489,7 +524,13 @@ impl Machine {
_ => unreachable!()
};
let exports = self.extract_predicate_indicator_list();
let exports = match self.extract_module_export_list() {
Ok(exports) => exports,
Err(e) => {
self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2));
return;
}
};
let load_result = match to_src(name) {
ModuleSource::Library(name) =>
@@ -521,7 +562,7 @@ impl Machine {
self.code_repo.cached_query = cached_query;
if let Err(e) = result {
self.throw_session_error(e, (clause_name!("use_module"), 1));
self.throw_session_error(e, (clause_name!("use_module"), 2));
}
}

View File

@@ -137,64 +137,55 @@ pub trait SubModuleUser {
}
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();
for export in module.module_decl.exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
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.get_op_module_name(name.clone(), Fixity::In) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::In));
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;
}
}
} else if arity == 1 {
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Pre));
}
}
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
{
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Post));
self.remove_code_index((name.clone(), arity));
// remove or respecify ops.
if arity == 2 {
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
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.get_op_module_name(name.clone(), Fixity::Pre) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Pre));
}
}
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
{
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Post));
}
}
}
}
}
}
_ => {}
};
},
ModuleExport::OpDecl(op_decl) => {
let op_dir = self.op_dir();
op_dir.remove(&(op_decl.name(), op_decl.fixity()));
}
_ => {}
};
}
}
}
// returns true on successful import.
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
let name = name.defrock_brackets();
let mut found_op = false;
{
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());
found_op = true;
}
};
if arity == 1 {
insert_op_dir(Fixity::Pre);
insert_op_dir(Fixity::Post);
} else if arity == 2 {
insert_op_dir(Fixity::In);
}
}
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
let name = name.with_table(submodule.atom_tbl.clone());
@@ -205,7 +196,7 @@ pub trait SubModuleUser {
self.insert_dir_entry(name, arity, code_data.clone());
true
} else {
found_op || submodule.is_impromptu_module
submodule.is_impromptu_module
}
}
@@ -214,30 +205,58 @@ pub trait SubModuleUser {
_: &mut CodeRepo,
_: MachineFlags,
_: &Module,
_: &Vec<PredicateKey>,
_: &Vec<ModuleExport>,
) -> Result<(), SessionError>;
fn use_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
_: &Module
) -> Result<(), SessionError>;
fn use_module(&mut self, _: &mut CodeRepo, _: MachineFlags, _: &Module) -> Result<(), SessionError>;
}
pub fn use_qualified_module<User>(
user: &mut User,
submodule: &Module,
exports: &Vec<PredicateKey>,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError>
where
User: SubModuleUser,
{
for (name, arity) in exports.iter().cloned() {
if !submodule
.module_decl
.exports
.contains(&(name.clone(), arity))
{
continue;
}
for export in exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
if !submodule
.module_decl
.exports
.contains(&ModuleExport::PredicateKey((name.clone(), arity)))
{
continue;
}
if !user.import_decl(name, arity, submodule) {
return Err(SessionError::ModuleDoesNotContainExport);
if !user.import_decl(name, arity, submodule) {
return Err(SessionError::ModuleDoesNotContainExport);
}
},
ModuleExport::OpDecl(op_decl) => {
if !submodule
.module_decl
.exports
.contains(&ModuleExport::OpDecl(op_decl.clone()))
{
continue;
}
let op_dir = user.op_dir();
let prec = op_decl.0;
op_decl.insert_into_op_dir(
submodule.module_decl.name.clone(),
op_dir,
prec,
);
}
}
}
@@ -248,9 +267,23 @@ pub fn use_module<User: SubModuleUser>(
user: &mut User,
submodule: &Module,
) -> Result<(), SessionError> {
for (name, arity) in submodule.module_decl.exports.iter().cloned() {
if !user.import_decl(name, arity, submodule) {
return Err(SessionError::ModuleDoesNotContainExport);
for export in submodule.module_decl.exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
if !user.import_decl(name, arity, submodule) {
return Err(SessionError::ModuleDoesNotContainExport);
}
}
ModuleExport::OpDecl(op_decl) => {
let op_dir = user.op_dir();
let prec = op_decl.0;
op_decl.insert_into_op_dir(
submodule.module_decl.name.clone(),
op_dir,
prec,
);
}
}
}
@@ -283,7 +316,7 @@ impl SubModuleUser for Module {
_: &mut CodeRepo,
_: MachineFlags,
submodule: &Module,
exports: &Vec<PredicateKey>,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError> {
use_qualified_module(self, submodule, exports)?;

View File

@@ -196,13 +196,13 @@ fn setup_op_decl(
to_op_decl(prec, spec.as_str(), name)
}
fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError> {
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError> {
match term {
Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == "/" && terms.len() == 2 =>
{
let arity = *terms.pop().unwrap();
let name = *terms.pop().unwrap();
let name = *terms.pop().unwrap();
let arity = arity
.to_constant()
@@ -210,7 +210,7 @@ fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError
.and_then(|n| n.to_usize())
.ok_or(ParserError::InvalidModuleExport)?;
let name = name
let name = name
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(ParserError::InvalidModuleExport)?;
@@ -221,7 +221,32 @@ fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError
}
}
fn setup_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleDecl, ParserError> {
fn setup_module_export(
mut term: Term,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleExport, ParserError> {
setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
if let Term::Clause(_, name, terms, _) = term {
if terms.len() == 3 && name.as_str() == "op" {
Ok(ModuleExport::OpDecl(setup_op_decl(
terms,
atom_tbl
)?))
} else {
Err(ParserError::InvalidModuleDecl)
}
} else {
Err(ParserError::InvalidModuleDecl)
}
})
}
fn setup_module_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleDecl, ParserError> {
let mut export_list = *terms.pop().unwrap();
let name = terms
.pop()
@@ -230,10 +255,12 @@ fn setup_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleDecl, ParserErro
.and_then(|c| c.to_atom())
.ok_or(ParserError::InvalidModuleDecl)?;
let mut exports = Vec::new();
let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list {
exports.push(setup_predicate_indicator(*t1)?);
let module_export = setup_module_export(*t1, atom_tbl.clone())?;
exports.push(module_export);
export_list = *t2;
}
@@ -257,14 +284,18 @@ fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, Pars
.map(|c| ModuleSource::Library(c))
.ok_or(ParserError::InvalidUseModuleDecl)
}
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
Term::Constant(_, Constant::Atom(ref name, _)) =>
Ok(ModuleSource::File(name.clone())),
_ => Err(ParserError::InvalidUseModuleDecl),
}
}
type UseModuleExport = (ModuleSource, Vec<PredicateKey>);
type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
fn setup_qualified_import(mut terms: Vec<Box<Term>>) -> Result<UseModuleExport, ParserError> {
fn setup_qualified_import(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<UseModuleExport, ParserError> {
let mut export_list = *terms.pop().unwrap();
let module_src = match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
@@ -282,10 +313,10 @@ fn setup_qualified_import(mut terms: Vec<Box<Term>>) -> Result<UseModuleExport,
_ => Err(ParserError::InvalidUseModuleDecl),
}?;
let mut exports = Vec::new();
let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list {
exports.push(setup_predicate_indicator(*t1)?);
exports.push(setup_module_export(*t1, atom_tbl.clone())?);
export_list = *t2;
}
@@ -460,19 +491,19 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
("op", 3) =>
Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)),
("module", 2) =>
Ok(Declaration::Module(setup_module_decl(terms)?)),
Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)),
("use_module", 1) =>
Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
("use_module", 2) => {
let (name, exports) = setup_qualified_import(terms)?;
let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?;
Ok(Declaration::UseQualifiedModule(name, exports))
}
("non_counted_backtracking", 1) => {
let (name, arity) = setup_predicate_indicator(*terms.pop().unwrap())?;
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity))
}
("dynamic", 1) => {
let (name, arity) = setup_predicate_indicator(*terms.pop().unwrap())?;
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity))
}
("initialization", 1) => {