Merge pull request #621 from notoria/tabling

Tabling
This commit is contained in:
Mark Thom
2020-07-03 14:40:52 -03:00
committed by GitHub
8 changed files with 145 additions and 240 deletions

103
build.rs
View File

@@ -1,74 +1,55 @@
extern crate indexmap; extern crate indexmap;
use crate::indexmap::IndexSet;
use std::env; use std::env;
use std::fs::{File, copy, create_dir_all, read_dir}; use std::fs;
use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
fn main() fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
{ let entries = match current_dir.read_dir() {
Ok(entries) => entries,
Err(_) => return,
};
for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
if entry.is_dir() {
if let Some(file_name) = entry.file_name() {
let new_prefix =
prefix.to_owned() + file_name.to_str().unwrap() + "/";
find_prolog_files(libraries, &new_prefix, &entry);
}
} else if entry.is_file() {
let ext = std::ffi::OsStr::new("pl");
if entry.extension() == Some(ext) {
let contain =
String::from_utf8(fs::read(&entry).unwrap()).unwrap();
let name = entry.file_stem().unwrap().to_str().unwrap();
let line = format!(
" m.insert(\"{}\",\n{:?});\n",
prefix.to_owned() + name,
contain
);
libraries.write_all(line.as_bytes()).unwrap();
}
}
}
}
fn main() {
let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("libraries.rs"); let dest_path = Path::new(&out_dir).join("libraries.rs");
let mut libraries = File::create(&dest_path).unwrap(); let mut libraries = File::create(&dest_path).unwrap();
let mut library_index = IndexSet::new(); let lib_path = Path::new("src/lib");
let mut paths: Vec<_> = read_dir("./src/lib").unwrap() libraries
.map(|e| e.unwrap().path()).collect(); .write_all(
b"ref_thread_local! {
while let Some(item) = paths.pop() {
if item.is_file() {
let file_name = item.strip_prefix(".").unwrap();
if let Some(ext) = item.extension() {
if ext == "pl" {
let file_stem = item.file_stem().unwrap();
let file_str = file_stem.to_string_lossy().to_uppercase();
let dest = Path::new(&out_dir).join(file_name);
let dir_name = dest.parent().unwrap();
if !dir_name.exists() {
create_dir_all(dir_name).unwrap();
}
match copy(&item, dest) {
Ok(_) => {
}
Err(e) => {
panic!("die: {:?}", e)
}
};
let include_line = format!("static {}: &str = include_str!({:?});\n",
file_str, file_name); //file_stem.to_string_lossy());
libraries.write_all(include_line.as_bytes()).unwrap();
library_index.insert(file_stem.to_string_lossy().to_string());
}
}
} else if item.is_dir() {
for entry in read_dir(item).unwrap() {
let path = entry.unwrap().path();
paths.push(path);
}
}
}
libraries.write_all(b"\nref_thread_local! {
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = { pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
let mut m = IndexMap::new();\n").unwrap(); let mut m = IndexMap::new();\n",
)
for item in library_index { .unwrap();
let line = format!("\n m.insert(\"{}\", {});", item, item.to_uppercase()); find_prolog_files(&mut libraries, "", &lib_path);
libraries.write_all(line.as_bytes()).unwrap(); libraries.write_all(b"\n m\n };\n}\n").unwrap();
}
libraries.write_all(b"\n\n m\n };
}\n").unwrap();
libraries.write_all(b"\npub static PROJECT_DIR: &'static str = \"").unwrap();
libraries.write_all(env::var("CARGO_MANIFEST_DIR").unwrap().as_bytes()).unwrap();
libraries.write_all(b"\";\n").unwrap();
} }

View File

@@ -8,12 +8,12 @@
op(1150, fx, table) op(1150, fx, table)
]). ]).
:- use_module('tabling/double_linked_list'). :- use_module(library(tabling/double_linked_list)).
:- use_module('tabling/table_data_structure'). :- use_module(library(tabling/table_data_structure)).
:- use_module('tabling/batched_worklist'). :- use_module(library(tabling/batched_worklist)).
:- use_module('tabling/wrapper'). :- use_module(library(tabling/wrapper)).
:- use_module('tabling/global_worklist'). :- use_module(library(tabling/global_worklist)).
:- use_module('tabling/table_link_manager'). :- use_module(library(tabling/table_link_manager)).
:- use_module(library(cont)). :- use_module(library(cont)).
:- use_module(library(lists)). :- use_module(library(lists)).

View File

@@ -45,8 +45,8 @@
wkl_worklist_work_done/1 % +WorkList wkl_worklist_work_done/1 % +WorkList
]). ]).
:- use_module(global_worklist). :- use_module(library(tabling/global_worklist)).
:- use_module(double_linked_list). :- use_module(library(tabling/double_linked_list)).
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(lists)). :- use_module(library(lists)).

View File

@@ -15,8 +15,8 @@
get_nb_identifiers/3 % +Table, -NbWorklistID, -NbAnswerTreeID get_nb_identifiers/3 % +Table, -NbWorklistID, -NbAnswerTreeID
]). ]).
:- use_module(table_link_manager). :- use_module(library(tabling/table_link_manager)).
:- use_module(trie). :- use_module(library(tabling/trie)).
/* Part of SWI-Prolog /* Part of SWI-Prolog
@@ -53,7 +53,7 @@
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
:- use_module(batched_worklist). :- use_module(library(tabling/batched_worklist)).
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(gensym)). :- use_module(library(gensym)).

View File

@@ -47,7 +47,7 @@
:- use_module(library(iso_ext)). :- use_module(library(iso_ext)).
:- use_module(library(terms)). :- use_module(library(terms)).
:- use_module(trie). :- use_module(library(tabling/trie)).
:- attribute trie_table_link/1. :- attribute trie_table_link/1.

View File

@@ -600,45 +600,26 @@ fn load_library(
name: ClauseName, name: ClauseName,
suppress_warnings: bool, suppress_warnings: bool,
) -> Result<ClauseName, SessionError> { ) -> Result<ClauseName, SessionError> {
let mut lib_path = current_dir();
lib_path.pop();
lib_path.push("lib");
let (stream, listing_src) =
match LIBRARIES.borrow().get(name.as_str()) { match LIBRARIES.borrow().get(name.as_str()) {
Some(code) => { Some(code) => {
let listing_src = ListingSource::from_file_and_path(name, lib_path); let listing_src = ListingSource::User;
(Stream::from(*code), listing_src)
}
None => {
// assume that name is a path.
lib_path.push(name.as_str());
lib_path.set_extension("pl");
let file =
match File::open(&lib_path) {
Ok(file) => {
file
}
Err(_) => {
let err = ExistenceError::ModuleSource(ModuleSource::Library(name));
return Err(SessionError::ExistenceError(err));
}
};
let listing_src = ListingSource::from_file_and_path(name.clone(), lib_path);
(Stream::from_file_as_input(name, file), listing_src)
}
};
load_module( load_module(
wam, wam,
stream, Stream::from(*code),
suppress_warnings, suppress_warnings,
&listing_src, &listing_src,
) )
} }
None => {
let err = ExistenceError::ModuleSource(ModuleSource::Library(
name.clone()
));
Err(SessionError::ExistenceError(err))
}
}
}
impl ListingCompiler { impl ListingCompiler {
#[inline] #[inline]

View File

@@ -212,17 +212,6 @@ impl SubModuleUser for IndexStore {
} }
} }
#[inline]
fn current_dir() -> std::path::PathBuf {
let mut path_buf = std::path::PathBuf::from(PROJECT_DIR);
// file!() always produces a path relative to PROJECT_DIR.
path_buf = path_buf.join(std::path::PathBuf::from(file!()));
path_buf.pop();
path_buf
}
include!(concat!(env!("OUT_DIR"), "/libraries.rs")); include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
static TOPLEVEL: &str = include_str!("../toplevel.pl"); static TOPLEVEL: &str = include_str!("../toplevel.pl");
@@ -230,12 +219,7 @@ static TOPLEVEL: &str = include_str!("../toplevel.pl");
impl Machine { impl Machine {
fn compile_special_forms(&mut self) fn compile_special_forms(&mut self)
{ {
let current_dir = current_dir(); let verify_attrs_src = ListingSource::User;
let verify_attrs_src = ListingSource::from_file_and_path(
clause_name!("attributed_variables.pl"),
current_dir.clone(),
);
match compile_special_form( match compile_special_form(
self, self,
@@ -250,10 +234,7 @@ impl Machine {
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"), panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
} }
let project_attrs_src = ListingSource::from_file_and_path( let project_attrs_src = ListingSource::User;
clause_name!("project_attributes.pl"),
current_dir,
);
match compile_special_form( match compile_special_form(
self, self,
@@ -273,13 +254,7 @@ impl Machine {
{ {
self.toplevel_idx = self.code_repo.code.len(); self.toplevel_idx = self.code_repo.code.len();
let mut current_dir = current_dir(); let top_lvl_src = ListingSource::User;
current_dir.pop();
let top_lvl_src = ListingSource::from_file_and_path(
clause_name!("toplevel.pl"),
current_dir,
);
compile_user_module( compile_user_module(
self, self,
@@ -371,6 +346,8 @@ impl Machine {
pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self
{ {
use crate::ref_thread_local::RefThreadLocal;
let mut wam = Machine { let mut wam = Machine {
machine_st: MachineState::new(), machine_st: MachineState::new(),
inner_heap: Heap::new(), inner_heap: Heap::new(),
@@ -383,78 +360,59 @@ impl Machine {
}; };
let atom_tbl = wam.indices.atom_tbl.clone(); let atom_tbl = wam.indices.atom_tbl.clone();
let mut lib_path = current_dir();
lib_path.pop();
lib_path.push("lib");
wam.indices.add_term_and_goal_expansion_indices(); wam.indices.add_term_and_goal_expansion_indices();
compile_listing( compile_listing(
&mut wam, &mut wam,
Stream::from(BUILTINS), Stream::from(LIBRARIES.borrow()["builtins"]),
default_index_store!(atom_tbl.clone()), default_index_store!(atom_tbl.clone()),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("builtins.pl"),
lib_path.clone(),
),
); );
wam.compile_special_forms(); wam.compile_special_forms();
compile_user_module(&mut wam, compile_user_module(
Stream::from(ERROR), &mut wam,
Stream::from(LIBRARIES.borrow()["error"]),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("error"),
lib_path.clone(),
)
); );
compile_user_module(&mut wam, compile_user_module(
Stream::from(PAIRS), &mut wam,
Stream::from(LIBRARIES.borrow()["pairs"]),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("pairs"),
lib_path.clone(),
)
); );
compile_user_module(&mut wam, compile_user_module(
Stream::from(LISTS), &mut wam,
Stream::from(LIBRARIES.borrow()["lists"]),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("lists"),
lib_path.clone(),
),
); );
compile_user_module(&mut wam, compile_user_module(
Stream::from(ISO_EXT), &mut wam,
Stream::from(LIBRARIES.borrow()["iso_ext"]),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("iso_ext"),
lib_path.clone(),
)
); );
compile_user_module(&mut wam, compile_user_module(
Stream::from(SI), &mut wam,
Stream::from(LIBRARIES.borrow()["si"]),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("si"),
lib_path.clone(),
)
); );
compile_user_module(&mut wam, compile_user_module(
Stream::from(CHARSIO), &mut wam,
Stream::from(LIBRARIES.borrow()["charsio"]),
true, true,
ListingSource::from_file_and_path( ListingSource::User,
clause_name!("charsio"),
lib_path.clone(),
)
); );
if wam.compile_top_level().is_err() { if wam.compile_top_level().is_err() {
@@ -666,37 +624,35 @@ impl Machine {
Ok(exports) Ok(exports)
} }
fn use_module(&mut self, to_src: impl Fn(ClauseName) -> ModuleSource) fn use_module<ToSource>(&mut self, to_src: ToSource)
where ToSource: Fn(ClauseName) -> ModuleSource
{ {
// the term expander will overwrite the cached query, so save it here. // the term expander will overwrite the cached query, so save it here.
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone(); let module_spec = self.machine_st[temp_v!(1)].clone();
let (name, is_path) = { let name = {
let addr = self.machine_st.store(self.machine_st.deref(module_spec)); let addr = self.machine_st.store(self.machine_st.deref(module_spec));
match self.machine_st.heap.index_addr(&addr).as_ref() { match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => HeapCellValue::Atom(name, _) =>
(name.clone(), name.as_str().contains('/')), name.clone(),
HeapCellValue::Addr(Addr::Char(c)) => HeapCellValue::Addr(Addr::Char(c)) =>
(clause_name!(c.to_string(), self.indices.atom_tbl), false), clause_name!(c.to_string(), self.indices.atom_tbl),
HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => { HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => {
let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(*addr); let mut heap_pstr_iter =
let filename = heap_pstr_iter.to_string(); self.machine_st.heap_pstr_iter(*addr);
let is_path = filename.contains('/'); clause_name!(
heap_pstr_iter.to_string(),
(clause_name!(filename, self.indices.atom_tbl), is_path) self.indices.atom_tbl
)
} }
_ => _ => unreachable!(),
unreachable!(),
} }
}; };
let load_result = match to_src(name) { let load_result = match to_src(name) {
ModuleSource::Library(name) => ModuleSource::Library(name) =>
if is_path {
load_library(self, name, false)
} else {
if let Some(module) = self.indices.take_module(name.clone()) { if let Some(module) = self.indices.take_module(name.clone()) {
self.indices.remove_module(clause_name!("user"), &module); self.indices.remove_module(clause_name!("user"), &module);
self.indices.modules.insert(name.clone(), module); self.indices.modules.insert(name.clone(), module);
@@ -704,8 +660,7 @@ impl Machine {
Ok(name) Ok(name)
} else { } else {
load_library(self, name, false) load_library(self, name, false)
} },
}
ModuleSource::File(name) => ModuleSource::File(name) =>
load_module_from_file(self, PathBuf::from(name.as_str()), false) load_module_from_file(self, PathBuf::from(name.as_str()), false)
}; };
@@ -727,27 +682,21 @@ impl Machine {
} }
} }
fn use_qualified_module(&mut self, to_src: impl Fn(ClauseName) -> ModuleSource) fn use_qualified_module<ToSource>(&mut self, to_src: ToSource)
where ToSource: Fn(ClauseName) -> ModuleSource
{ {
// the term expander will overwrite the cached query, so save it here. // the term expander will overwrite the cached query, so save it here.
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
let module_spec = self.machine_st[temp_v!(1)].clone(); let module_spec = self.machine_st[temp_v!(1)].clone();
let (name, is_path) = { let name = {
let addr = self.machine_st.store(self.machine_st.deref(module_spec)); let addr = self.machine_st.store(self.machine_st.deref(module_spec));
match self.machine_st.heap.index_addr(&addr).as_ref() { match self.machine_st.heap.index_addr(&addr).as_ref() {
HeapCellValue::Atom(name, _) => HeapCellValue::Atom(name, _) =>
(name.clone(), name.as_str().contains('/')), name.clone(),
HeapCellValue::Addr(Addr::Char(c)) => HeapCellValue::Addr(Addr::Char(c)) =>
(clause_name!(c.to_string(), self.indices.atom_tbl), false), clause_name!(c.to_string(), self.indices.atom_tbl),
HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => {
let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(*addr);
let filename = heap_pstr_iter.to_string();
let is_path = filename.contains('/');
(clause_name!(filename, self.indices.atom_tbl), is_path)
}
_ => _ =>
unreachable!(), unreachable!(),
} }
@@ -763,9 +712,6 @@ impl Machine {
let load_result = match to_src(name) { let load_result = match to_src(name) {
ModuleSource::Library(name) => ModuleSource::Library(name) =>
if is_path {
load_library(self, name, false)
} else {
if let Some(module) = self.indices.take_module(name.clone()) { if let Some(module) = self.indices.take_module(name.clone()) {
self.indices.remove_module(clause_name!("user"), &module); self.indices.remove_module(clause_name!("user"), &module);
self.indices.modules.insert(name.clone(), module); self.indices.modules.insert(name.clone(), module);
@@ -773,7 +719,6 @@ impl Machine {
Ok(name) Ok(name)
} else { } else {
load_library(self, name, false) load_library(self, name, false)
}
}, },
ModuleSource::File(name) => ModuleSource::File(name) =>
load_module_from_file(self, PathBuf::from(name.as_str()), false) load_module_from_file(self, PathBuf::from(name.as_str()), false)

View File

@@ -340,7 +340,10 @@ fn setup_module_decl(
} }
} }
fn read_library_path(term: Term, atom_tbl: TabledData<Atom>) -> Option<ClauseName> { fn read_library_path(
term: Term,
atom_tbl: TabledData<Atom>,
) -> Option<ClauseName> {
match term { match term {
Term::Constant(_, Constant::Atom(atom, _)) => { Term::Constant(_, Constant::Atom(atom, _)) => {
Some(atom.defrock_brackets()) Some(atom.defrock_brackets())
@@ -353,9 +356,7 @@ fn read_library_path(term: Term, atom_tbl: TabledData<Atom>) -> Option<ClauseNam
Term::Constant(_, Constant::Atom(atom, _)) => { Term::Constant(_, Constant::Atom(atom, _)) => {
atoms.push(atom.as_str().to_owned()); atoms.push(atom.as_str().to_owned());
} }
_ => { _ => return None,
return None;
}
} }
} }
@@ -364,10 +365,7 @@ fn read_library_path(term: Term, atom_tbl: TabledData<Atom>) -> Option<ClauseNam
} }
} }
fn setup_use_module_decl( fn setup_use_module_decl(mut terms: Vec<Box<Term>>, atom_tbl: TabledData<Atom>) -> Result<ModuleSource, ParserError> {
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleSource, ParserError> {
match *terms.pop().unwrap() { match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None) Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 => if name.as_str() == "library" && terms.len() == 1 =>