perform singleton variable scans on top level terms only
This commit is contained in:
@@ -3,7 +3,6 @@ use prolog_parser::parser::OpDesc;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
|
||||
use prolog::clause_types::*;
|
||||
use prolog::iterators::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_indices::*;
|
||||
use prolog::ordered_float::OrderedFloat;
|
||||
@@ -59,40 +58,6 @@ impl TopLevel {
|
||||
_ => 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)]
|
||||
@@ -145,40 +110,6 @@ pub struct Rule {
|
||||
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)]
|
||||
pub struct Predicate(pub Vec<PredicateClause>);
|
||||
|
||||
@@ -199,10 +130,6 @@ impl Predicate {
|
||||
.first()
|
||||
.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>);
|
||||
@@ -234,39 +161,6 @@ impl PredicateClause {
|
||||
&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)]
|
||||
|
||||
@@ -6,6 +6,7 @@ use prolog::codegen::*;
|
||||
use prolog::debray_allocator::*;
|
||||
use prolog::forms::*;
|
||||
use prolog::instructions::*;
|
||||
use prolog::iterators::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_indices::*;
|
||||
use prolog::machine::term_expansion::ExpansionAdditionResult;
|
||||
@@ -114,32 +115,36 @@ fn compile_relation(
|
||||
}
|
||||
|
||||
fn issue_singleton_warnings(
|
||||
tl: &TopLevel,
|
||||
module_name: ClauseName,
|
||||
terms_and_locs: Vec<(Term, usize, usize)>,
|
||||
) {
|
||||
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 (term, line_num, _col_num) in terms_and_locs {
|
||||
let mut singletons = vec![];
|
||||
let mut var_count = IndexMap::new();
|
||||
|
||||
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);
|
||||
}
|
||||
for subterm in breadth_first_iter(&term, true) {
|
||||
if let TermRef::Var(_, _, var) = subterm {
|
||||
let entry = var_count.entry(var).or_insert(0);
|
||||
*entry += 1;
|
||||
}
|
||||
}
|
||||
|
||||
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_indices: IndexStore,
|
||||
addition_results: ExpansionAdditionResult,
|
||||
top_level_terms: Vec<(Term, usize, usize)>
|
||||
}
|
||||
|
||||
pub struct ClauseCodeGenerator {
|
||||
@@ -687,10 +693,6 @@ impl ListingCompiler {
|
||||
|
||||
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());
|
||||
@@ -942,6 +944,7 @@ impl ListingCompiler {
|
||||
toplevel_results,
|
||||
toplevel_indices,
|
||||
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);
|
||||
}
|
||||
|
||||
if !compiler.suppress_warnings {
|
||||
issue_singleton_warnings(compiler.get_module_name(), results.top_level_terms);
|
||||
}
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ pub struct TermStream<'a, R: Read> {
|
||||
pub(crate) flags: MachineFlags,
|
||||
term_expansion_lens: (usize, usize),
|
||||
goal_expansion_lens: (usize, usize),
|
||||
top_level_terms: Vec<(Term, usize, usize)> // term, line_num, col_num.
|
||||
}
|
||||
|
||||
pub struct ExpansionAdditionResult {
|
||||
@@ -127,9 +128,15 @@ impl<'a, R: Read> TermStream<'a, R> {
|
||||
parser: Parser::new(src, atom_tbl, flags),
|
||||
in_module: false,
|
||||
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]
|
||||
pub fn add_to_top(&mut self, buf: &str) {
|
||||
self.parser.add_to_top(buf);
|
||||
@@ -263,12 +270,18 @@ impl<'a, R: Read> TermStream<'a, R> {
|
||||
|
||||
self.parser.reset();
|
||||
|
||||
let line_num = self.line_num();
|
||||
let col_num = self.col_num();
|
||||
|
||||
let term = self.parser.read_term(composite_op!(
|
||||
self.in_module,
|
||||
&self.wam.indices.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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user