fix goal expansion in disjunctions, add warnings for singleton variables

This commit is contained in:
Mark Thom
2019-10-03 22:13:34 -06:00
parent 02d1ed237f
commit b61ed65208
11 changed files with 348 additions and 116 deletions

View File

@@ -56,16 +56,18 @@ fn fix_filename(atom_tbl: TabledData<Atom>, filename: &str) -> Result<PathBuf, S
Ok(path)
}
fn load_module<R: Read>(wam: &mut Machine, stream: ParsingStream<R>)
-> Result<Option<ClauseName>, SessionError>
{
fn load_module<R: Read>(
wam: &mut Machine,
stream: ParsingStream<R>,
suppress_warnings: bool,
) -> Result<Option<ClauseName>, SessionError> {
// follow the operation of compile_user_module, but before
// compiling, check that a module is declared in the file. if not,
// throw an exception.
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
setup_indices(wam, clause_name!("builtins"), &mut indices)?;
let mut compiler = ListingCompiler::new(&wam.code_repo);
let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings);
let results = compiler.gather_items(wam, stream, &mut indices)?;
let module_name = if let Some(ref module) = &compiler.module {
@@ -81,9 +83,11 @@ fn load_module<R: Read>(wam: &mut Machine, stream: ParsingStream<R>)
}
pub(super)
fn load_module_from_file(wam: &mut Machine, filename: &str)
-> Result<Option<ClauseName>, SessionError>
{
fn load_module_from_file(
wam: &mut Machine,
filename: &str,
suppress_warnings: bool,
) -> Result<Option<ClauseName>, SessionError> {
let path = fix_filename(wam.indices.atom_tbl.clone(), filename)?;
let file_handle = File::open(&path).or_else(|_| {
@@ -91,24 +95,51 @@ fn load_module_from_file(wam: &mut Machine, filename: &str)
Err(SessionError::InvalidFileName(filename))
})?;
load_module(wam, parsing_stream(file_handle))
load_module(wam, parsing_stream(file_handle), suppress_warnings)
}
pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
// throw errors if declaration or query found.
fn compile_relation(
tl: &TopLevel,
non_counted_bt: bool,
flags: MachineFlags,
cg: &mut CodeGenerator<DebrayAllocator>,
tl: &TopLevel
) -> Result<Code, ParserError> {
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt, flags);
match tl {
&TopLevel::Declaration(_) | &TopLevel::Query(_) => Err(ParserError::ExpectedRel),
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses.0),
&TopLevel::Fact(ref fact) => Ok(cg.compile_fact(fact)),
&TopLevel::Rule(ref rule) => cg.compile_rule(rule),
&TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)),
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
}
}
fn issue_singleton_warnings(
tl: &TopLevel,
module_name: ClauseName,
) {
if let Some((line_num, _)) = tl.location() {
if let Some(var_counts) = tl.var_count() {
for var_count in var_counts {
let mut singletons = vec![];
for (var, count) in var_count {
if count == 1 && !var.starts_with("_") && var.as_str() != "!" {
singletons.push(var);
}
}
if let Some(last_var) = singletons.pop() {
print!("Warning: {}:{}: Singleton variables: [",
module_name, line_num);
for var in singletons {
print!("{}, ", var);
}
println!("{}]", last_var);
}
}
}
}
}
@@ -139,7 +170,9 @@ pub fn compile_appendix(
) -> Result<(), ParserError> {
for tl in queue.iter() {
set_first_index(code);
code.append(&mut compile_relation(tl, non_counted_bt, flags)?);
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt, flags);
let decl_code = compile_relation(&mut cg, tl)?;
code.extend(decl_code.into_iter());
}
Ok(())
@@ -209,7 +242,7 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession {
}
}
TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => {
let mut compiler = ListingCompiler::new(&wam.code_repo);
let mut compiler = ListingCompiler::new(&wam.code_repo, false);
let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl));
try_eval_session!(wam.check_toplevel_code(&indices));
@@ -294,7 +327,7 @@ pub(super) fn compile_into_module<R: Read>(
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
try_eval_session!(setup_indices(wam, module_name.clone(), &mut indices));
let mut compiler = ListingCompiler::new(&wam.code_repo);
let mut compiler = ListingCompiler::new(&wam.code_repo, true);
match compile_into_module_impl(wam, &mut compiler, module_name, src, indices) {
Ok(()) => EvalSession::EntrySuccess,
@@ -382,14 +415,18 @@ impl ClauseCodeGenerator {
vec![Box::new(head.clone()), Box::new(tail.clone())],
None,
);
PredicateClause::Fact(clause)
PredicateClause::Fact(clause, 0, 0)
})
.collect(),
);
let p = self.code.len() + wam.code_repo.code.len() + self.len_offset;
let mut decl_code =
compile_relation(&TopLevel::Predicate(predicate), false, wam.machine_flags())?;
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, wam.machine_flags());
let mut decl_code = compile_relation(
&mut cg,
&TopLevel::Predicate(predicate),
)?;
compile_appendix(&mut decl_code, &VecDeque::new(), false, wam.machine_flags())?;
@@ -404,16 +441,18 @@ impl ClauseCodeGenerator {
{
wam.code_repo.code.extend(self.code.into_iter());
for ((name, arity), _) in dynamic_code_dir {
wam.indices.dynamic_code_dir.insert((name.owning_module(), name.clone(), arity),
DynamicPredicateInfo::default());
if self.module_name.as_str() == "user" {
wam.indices.code_dir.entry((name, arity))
.or_insert(CodeIndex::dynamic_undefined(self.module_name.clone()));
if self.module_name.as_str() == "user" {
for ((name, arity), _) in &dynamic_code_dir {
wam.indices.code_dir.entry((name.clone(), *arity))
.or_insert(CodeIndex::dynamic_undefined(clause_name!("user")));
}
}
for ((name, arity), _) in dynamic_code_dir {
wam.indices.dynamic_code_dir.insert((name.owning_module(), name, arity),
DynamicPredicateInfo::default());
}
for ((name, arity), p) in self.pi_to_loc {
let entry = wam
.indices
@@ -432,7 +471,8 @@ pub struct ListingCompiler {
user_term_dir: TermDir,
orig_term_expansion_lens: (usize, usize),
orig_goal_expansion_lens: (usize, usize),
initialization_goals: (Vec<QueryTerm>, VecDeque<TopLevel>)
initialization_goals: (Vec<QueryTerm>, VecDeque<TopLevel>),
suppress_warnings: bool
}
fn add_toplevel_code(wam: &mut Machine, code: Code, mut indices: IndexStore) {
@@ -480,11 +520,14 @@ fn add_non_module_code(
}
pub(super)
fn load_library(wam: &mut Machine, name: ClauseName) -> Result<ClauseName, SessionError>
{
fn load_library(
wam: &mut Machine,
name: ClauseName,
suppress_warnings: bool,
) -> Result<ClauseName, SessionError> {
match LIBRARIES.borrow().get(name.as_str()) {
Some(code) => {
let module_name = load_module(wam, parsing_stream(code.as_bytes()))?;
let module_name = load_module(wam, parsing_stream(code.as_bytes()), suppress_warnings)?;
module_name.ok_or(SessionError::NoModuleDeclaration(name))
}
None => Err(SessionError::ModuleNotFound)
@@ -493,7 +536,7 @@ fn load_library(wam: &mut Machine, name: ClauseName) -> Result<ClauseName, Sessi
impl ListingCompiler {
#[inline]
pub fn new(code_repo: &CodeRepo) -> Self {
pub fn new(code_repo: &CodeRepo, suppress_warnings: bool) -> Self {
ListingCompiler {
non_counted_bt_preds: IndexSet::new(),
module: None,
@@ -502,7 +545,8 @@ impl ListingCompiler {
.term_dir_entry_len((clause_name!("term_expansion"), 2)),
orig_goal_expansion_lens: code_repo
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
initialization_goals: (vec![], VecDeque::from(vec![]))
initialization_goals: (vec![], VecDeque::from(vec![])),
suppress_warnings
}
}
@@ -636,14 +680,17 @@ impl ListingCompiler {
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
let p = code.len() + wam.code_repo.code.len() + code_offset;
let mut decl_code = compile_relation(
&TopLevel::Predicate(decl),
non_counted_bt,
wam.machine_flags(),
)?;
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt, wam.machine_flags());
let decl = TopLevel::Predicate(decl);
let mut decl_code = compile_relation(&mut cg, &decl)?;
compile_appendix(&mut decl_code, &queue, non_counted_bt, wam.machine_flags())?;
if !self.suppress_warnings {
issue_singleton_warnings(&decl, self.get_module_name());
}
let idx = code_dir
.entry((name.clone(), arity))
.or_insert(CodeIndex::default());
@@ -748,7 +795,7 @@ impl ListingCompiler {
}
Declaration::UseModule(ModuleSource::Library(name)) => {
let name = if !wam.indices.modules.contains_key(&name) {
load_library(wam, name)?
load_library(wam, name, true)?
} else {
name
};
@@ -757,7 +804,7 @@ impl ListingCompiler {
}
Declaration::UseQualifiedModule(ModuleSource::Library(name), exports) => {
let name = if !wam.indices.modules.contains_key(&name) {
load_library(wam, name)?
load_library(wam, name, true)?
} else {
name
};
@@ -782,7 +829,7 @@ impl ListingCompiler {
}
}
Declaration::UseModule(ModuleSource::File(filename)) => {
let name = load_module_from_file(wam, filename.as_str())?;
let name = load_module_from_file(wam, filename.as_str(), true)?;
if let Some(name) = name {
self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices)
@@ -791,7 +838,7 @@ impl ListingCompiler {
}
}
Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => {
let name = load_module_from_file(wam, filename.as_str())?;
let name = load_module_from_file(wam, filename.as_str(), true)?;
if let Some(name) = name {
self.use_qualified_module(
@@ -877,7 +924,7 @@ impl ListingCompiler {
self.process_and_commit_decl(decl, &mut worker, indices, flags)?;
if let &Some(ref module) = &self.module {
if let Some(ref module) = &self.module {
worker.term_stream.set_atom_tbl(module.atom_tbl.clone());
}
} else if decl.is_end_of_file() {
@@ -997,7 +1044,7 @@ pub fn compile_special_form<R: Read>(
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
setup_indices(wam, clause_name!("builtins"), &mut indices)?;
let mut compiler = ListingCompiler::new(&wam.code_repo);
let mut compiler = ListingCompiler::new(&wam.code_repo, true);
let results = compiler.gather_items(wam, src, &mut indices)?;
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)
@@ -1008,8 +1055,9 @@ pub fn compile_listing<R: Read>(
wam: &mut Machine,
src: ParsingStream<R>,
indices: IndexStore,
suppress_warnings: bool
) -> EvalSession {
let mut compiler = ListingCompiler::new(&wam.code_repo);
let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings);
match compile_work(&mut compiler, wam, src, indices) {
EvalSession::Error(e) => {
@@ -1036,8 +1084,12 @@ pub(super) fn setup_indices(
}
}
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: ParsingStream<R>) -> EvalSession {
pub fn compile_user_module<R: Read>(
wam: &mut Machine,
src: ParsingStream<R>,
suppress_warnings: bool,
) -> EvalSession {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
compile_listing(wam, src, indices)
compile_listing(wam, src, indices, suppress_warnings)
}