From: Mark Thom Date: Fri, 4 Oct 2019 16:38:45 +0000 (-0600) Subject: perform singleton variable scans on top level terms only X-Git-Tag: v0.8.110~19 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=caeff99f69e0b304cf703fbd63e5382e4ba8c469;p=scryer-prolog.git perform singleton variable scans on top level terms only --- diff --git a/Cargo.toml b/Cargo.toml index 8a31692a..936e91ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.99" +version = "0.8.100" authors = ["Mark Thom "] build = "build.rs" repository = "https://github.com/mthom/scryer-prolog" diff --git a/src/prolog/forms.rs b/src/prolog/forms.rs index f6b9e25f..38904435 100644 --- a/src/prolog/forms.rs +++ b/src/prolog/forms.rs @@ -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, 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, } -impl Rule { - pub fn var_count(&self) -> IndexMap, 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); @@ -199,10 +130,6 @@ impl Predicate { .first() .and_then(|clause| clause.name().map(|name| (name, clause.arity()))) } - - pub fn var_count(&self) -> Vec, usize>> { - self.0.iter().map(|clause| clause.var_count()).collect() - } } pub type CompiledResult = (Predicate, VecDeque); @@ -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, 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)] diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index b226cb48..b946951a 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -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,31 +115,35 @@ 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 (var, count) in var_count { - if count == 1 && !var.starts_with("_") && var.as_str() != "!" { - singletons.push(var); - } - } + for (term, line_num, _col_num) in terms_and_locs { + let mut singletons = vec![]; + let mut var_count = IndexMap::new(); + + 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); - } + 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, 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 } diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index 931e6adc..acd71db6 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -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); } }