perform singleton variable scans on top level terms only
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user