perform singleton variable scans on top level terms only

This commit is contained in:
Mark Thom
2019-10-04 10:38:45 -06:00
parent 0a84f183fe
commit caeff99f69
4 changed files with 46 additions and 132 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.99" version = "0.8.100"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
build = "build.rs" build = "build.rs"
repository = "https://github.com/mthom/scryer-prolog" repository = "https://github.com/mthom/scryer-prolog"

View File

@@ -3,7 +3,6 @@ use prolog_parser::parser::OpDesc;
use prolog_parser::tabled_rc::*; use prolog_parser::tabled_rc::*;
use prolog::clause_types::*; use prolog::clause_types::*;
use prolog::iterators::*;
use prolog::machine::machine_errors::*; use prolog::machine::machine_errors::*;
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use prolog::ordered_float::OrderedFloat; use prolog::ordered_float::OrderedFloat;
@@ -59,40 +58,6 @@ impl TopLevel {
_ => false, _ => false,
} }
} }
pub fn location(&self) -> Option<(usize, usize)> {
match self {
&TopLevel::Fact(_, line_num, col_num) | &TopLevel::Rule(_, line_num, col_num) =>
Some((line_num, col_num)),
&TopLevel::Predicate(Predicate(ref clauses)) =>
clauses.first().map(|clause| (clause.line_num(), clause.col_num())),
_ =>
None
}
}
pub fn var_count(&self) -> Option<Vec<IndexMap<Rc<Var>, usize>>> {
match self {
&TopLevel::Fact(ref term, ..) => {
let mut var_count = IndexMap::new();
for term_ref in breadth_first_iter(term, true) {
if let TermRef::Var(_, _, var) = term_ref {
let entry = var_count.entry(var).or_insert(0);
*entry += 1;
}
}
Some(vec![var_count])
}
&TopLevel::Rule(ref rule, ..) =>
Some(vec![rule.var_count()]),
&TopLevel::Predicate(ref predicate) =>
Some(predicate.var_count()),
_ =>
None
}
}
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@@ -145,40 +110,6 @@ pub struct Rule {
pub clauses: Vec<QueryTerm>, pub clauses: Vec<QueryTerm>,
} }
impl Rule {
pub fn var_count(&self) -> IndexMap<Rc<Var>, usize> {
let mut var_count = IndexMap::new();
for root_term in &self.head.1 {
// true because the root term is iterable.
for term_ref in breadth_first_iter(root_term, true) {
if let TermRef::Var(_, _, var) = term_ref {
let entry = var_count.entry(var).or_insert(0);
*entry += 1;
}
}
}
for term_ref in query_term_post_order_iter(&self.head.2) {
if let TermRef::Var(_, _, var) = term_ref {
let entry = var_count.entry(var).or_insert(0);
*entry += 1;
}
}
for clause in &self.clauses {
for term_ref in query_term_post_order_iter(clause) {
if let TermRef::Var(_, _, var) = term_ref {
let entry = var_count.entry(var).or_insert(0);
*entry += 1;
}
}
}
var_count
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct Predicate(pub Vec<PredicateClause>); pub struct Predicate(pub Vec<PredicateClause>);
@@ -199,10 +130,6 @@ impl Predicate {
.first() .first()
.and_then(|clause| clause.name().map(|name| (name, clause.arity()))) .and_then(|clause| clause.name().map(|name| (name, clause.arity())))
} }
pub fn var_count(&self) -> Vec<IndexMap<Rc<Var>, usize>> {
self.0.iter().map(|clause| clause.var_count()).collect()
}
} }
pub type CompiledResult = (Predicate, VecDeque<TopLevel>); pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
@@ -234,39 +161,6 @@ impl PredicateClause {
&PredicateClause::Rule(ref rule, ..) => Some(rule.head.0.clone()), &PredicateClause::Rule(ref rule, ..) => Some(rule.head.0.clone()),
} }
} }
pub fn line_num(&self) -> usize {
match self {
&PredicateClause::Fact(_, line_num, _) => line_num,
&PredicateClause::Rule(_, line_num, _) => line_num
}
}
pub fn col_num(&self) -> usize {
match self {
&PredicateClause::Fact(_, _, col_num) => col_num,
&PredicateClause::Rule(_, _, col_num) => col_num
}
}
pub fn var_count(&self) -> IndexMap<Rc<Var>, usize> {
match self {
&PredicateClause::Fact(ref term, ..) => {
let mut var_count = IndexMap::new();
for term_ref in breadth_first_iter(term, true) {
if let TermRef::Var(_, _, var) = term_ref {
let entry = var_count.entry(var).or_insert(0);
*entry += 1;
}
}
var_count
}
&PredicateClause::Rule(ref rule, ..) =>
rule.var_count()
}
}
} }
#[derive(Clone)] #[derive(Clone)]

View File

@@ -6,6 +6,7 @@ use prolog::codegen::*;
use prolog::debray_allocator::*; use prolog::debray_allocator::*;
use prolog::forms::*; use prolog::forms::*;
use prolog::instructions::*; use prolog::instructions::*;
use prolog::iterators::*;
use prolog::machine::machine_errors::*; use prolog::machine::machine_errors::*;
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use prolog::machine::term_expansion::ExpansionAdditionResult; use prolog::machine::term_expansion::ExpansionAdditionResult;
@@ -114,32 +115,36 @@ fn compile_relation(
} }
fn issue_singleton_warnings( fn issue_singleton_warnings(
tl: &TopLevel,
module_name: ClauseName, module_name: ClauseName,
terms_and_locs: Vec<(Term, usize, usize)>,
) { ) {
if let Some((line_num, _)) = tl.location() { for (term, line_num, _col_num) in terms_and_locs {
if let Some(var_counts) = tl.var_count() { let mut singletons = vec![];
for var_count in var_counts { let mut var_count = IndexMap::new();
let mut singletons = vec![];
for (var, count) in var_count { for subterm in breadth_first_iter(&term, true) {
if count == 1 && !var.starts_with("_") && var.as_str() != "!" { if let TermRef::Var(_, _, var) = subterm {
singletons.push(var); let entry = var_count.entry(var).or_insert(0);
} *entry += 1;
}
if let Some(last_var) = singletons.pop() {
print!("Warning: {}:{}: Singleton variables: [",
module_name, line_num);
for var in singletons {
print!("{}, ", var);
}
println!("{}]", last_var);
}
} }
} }
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);
}
} }
} }
@@ -375,6 +380,7 @@ pub struct GatherResult {
toplevel_results: Vec<PredicateCompileQueue>, toplevel_results: Vec<PredicateCompileQueue>,
toplevel_indices: IndexStore, toplevel_indices: IndexStore,
addition_results: ExpansionAdditionResult, addition_results: ExpansionAdditionResult,
top_level_terms: Vec<(Term, usize, usize)>
} }
pub struct ClauseCodeGenerator { pub struct ClauseCodeGenerator {
@@ -687,10 +693,6 @@ impl ListingCompiler {
compile_appendix(&mut decl_code, &queue, non_counted_bt, wam.machine_flags())?; 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 let idx = code_dir
.entry((name.clone(), arity)) .entry((name.clone(), arity))
.or_insert(CodeIndex::default()); .or_insert(CodeIndex::default());
@@ -942,6 +944,7 @@ impl ListingCompiler {
toplevel_results, toplevel_results,
toplevel_indices, toplevel_indices,
addition_results, addition_results,
top_level_terms: worker.term_stream.top_level_terms(),
}) })
} }
@@ -1021,6 +1024,10 @@ fn compile_work_impl(
wam.run_init_code(init_goal_code); wam.run_init_code(init_goal_code);
} }
if !compiler.suppress_warnings {
issue_singleton_warnings(compiler.get_module_name(), results.top_level_terms);
}
EvalSession::EntrySuccess EvalSession::EntrySuccess
} }

View File

@@ -77,6 +77,7 @@ pub struct TermStream<'a, R: Read> {
pub(crate) flags: MachineFlags, pub(crate) flags: MachineFlags,
term_expansion_lens: (usize, usize), term_expansion_lens: (usize, usize),
goal_expansion_lens: (usize, usize), goal_expansion_lens: (usize, usize),
top_level_terms: Vec<(Term, usize, usize)> // term, line_num, col_num.
} }
pub struct ExpansionAdditionResult { pub struct ExpansionAdditionResult {
@@ -127,9 +128,15 @@ impl<'a, R: Read> TermStream<'a, R> {
parser: Parser::new(src, atom_tbl, flags), parser: Parser::new(src, atom_tbl, flags),
in_module: false, in_module: false,
flags, flags,
top_level_terms: vec![]
} }
} }
#[inline]
pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> {
mem::replace(&mut self.top_level_terms, vec![])
}
#[inline] #[inline]
pub fn add_to_top(&mut self, buf: &str) { pub fn add_to_top(&mut self, buf: &str) {
self.parser.add_to_top(buf); self.parser.add_to_top(buf);
@@ -263,12 +270,18 @@ impl<'a, R: Read> TermStream<'a, R> {
self.parser.reset(); self.parser.reset();
let line_num = self.line_num();
let col_num = self.col_num();
let term = self.parser.read_term(composite_op!( let term = self.parser.read_term(composite_op!(
self.in_module, self.in_module,
&self.wam.indices.op_dir, &self.wam.indices.op_dir,
op_dir op_dir
))?; ))?;
// preserve a copy of the original unexpanded term for warning scans,
// if that stage is reached.
self.top_level_terms.push((term.clone(), line_num, col_num));
self.stack.push(term); self.stack.push(term);
} }
} }