]> Repositorios git - scryer-prolog.git/commitdiff
fix goal expansion in disjunctions, add warnings for singleton variables
authorMark Thom <[email protected]>
Fri, 4 Oct 2019 04:13:34 +0000 (22:13 -0600)
committerMark Thom <[email protected]>
Fri, 4 Oct 2019 04:13:34 +0000 (22:13 -0600)
Cargo.toml
src/prolog/codegen.rs
src/prolog/forms.rs
src/prolog/iterators.rs
src/prolog/lib/dcgs.pl
src/prolog/machine/compile.rs
src/prolog/machine/dynamic_database.rs
src/prolog/machine/mod.rs
src/prolog/machine/term_expansion.rs
src/prolog/machine/toplevel.rs
src/tests.rs

index bd31faa20d9bd2b18f81694cc934ff64f02d6a9d..8a31692a6bbcec14edc8e343c7dc34a9f9a78767 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "scryer-prolog"
-version = "0.8.98"
+version = "0.8.99"
 authors = ["Mark Thom <[email protected]>"]
 build = "build.rs"
 repository = "https://github.com/mthom/scryer-prolog"
@@ -18,7 +18,7 @@ lazy_static = "1.4.0"
 libc = "0.2.62"
 nix = "0.15.0"
 ordered-float = "0.5.0"
-prolog_parser = "0.8.30"
+prolog_parser = "0.8.31"
 ref_thread_local = "0.0.0"
 rug = "1.4.0"
 rustyline = "5.0.3"
index 5d7526bc0c8df2951ccb212c6324029a756d7496..d97c904fb081501507608accc559497e2f32ba54 100644 (file)
@@ -20,7 +20,7 @@ use std::vec::Vec;
 pub struct CodeGenerator<TermMarker> {
     flags: MachineFlags,
     marker: TermMarker,
-    var_count: IndexMap<Rc<Var>, usize>,
+    pub var_count: IndexMap<Rc<Var>, usize>,
     non_counted_bt: bool,
 }
 
@@ -867,8 +867,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
             self.marker.reset();
 
             let mut clause_code = match clause {
-                &PredicateClause::Fact(ref fact) => self.compile_fact(fact),
-                &PredicateClause::Rule(ref rule) => try!(self.compile_rule(rule)),
+                &PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
+                &PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
             };
 
             if num_clauses > 1 {
index 0f05587c9f242e740ab47c34ba6cd2cdd57f98ea..f6b9e25f58932675e46f73ed141bb2a233b6c9c2 100644 (file)
@@ -3,6 +3,7 @@ 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;
@@ -23,41 +24,75 @@ pub type JumpStub = Vec<Term>;
 #[derive(Clone)]
 pub enum TopLevel {
     Declaration(Declaration),
-    Fact(Term),
+    Fact(Term, usize, usize), // Term, line_num, col_num
     Predicate(Predicate),
     Query(Vec<QueryTerm>),
-    Rule(Rule),
+    Rule(Rule, usize, usize), // Rule, line_num, col_num
 }
 
 impl TopLevel {
     pub fn name(&self) -> Option<ClauseName> {
         match self {
             &TopLevel::Declaration(_) => None,
-            &TopLevel::Fact(ref term) => term.name(),
+            &TopLevel::Fact(ref term, ..) => term.name(),
             &TopLevel::Predicate(ref clauses) => clauses.0.first().and_then(|ref term| term.name()),
             &TopLevel::Query(_) => None,
-            &TopLevel::Rule(Rule { ref head, .. }) => Some(head.0.clone()),
+            &TopLevel::Rule(Rule { ref head, .. }, ..) => Some(head.0.clone()),
         }
     }
 
     pub fn arity(&self) -> usize {
         match self {
             &TopLevel::Declaration(_) => 0,
-            &TopLevel::Fact(ref term) => term.arity(),
+            &TopLevel::Fact(ref term, ..) => term.arity(),
             &TopLevel::Predicate(ref clauses) => clauses.0.first().map(|t| t.arity()).unwrap_or(0),
             &TopLevel::Query(_) => 0,
-            &TopLevel::Rule(Rule { ref head, .. }) => head.1.len(),
+            &TopLevel::Rule(Rule { ref head, .. }, ..) => head.1.len(),
         }
     }
 
     pub fn is_end_of_file_atom(&self) -> bool {
         match self {
-            &TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _))) => {
+            &TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => {
                 return name.as_str() == "end_of_file"
             }
             _ => 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)]
@@ -110,6 +145,40 @@ 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>);
 
@@ -130,35 +199,72 @@ 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>);
 
 #[derive(Clone)]
 pub enum PredicateClause {
-    Fact(Term),
-    Rule(Rule),
+    Fact(Term, usize, usize), // Term, line number, column number.
+    Rule(Rule, usize, usize), // Term, line number, column number.
 }
 
 impl PredicateClause {
     pub fn first_arg(&self) -> Option<&Term> {
         match self {
-            &PredicateClause::Fact(ref term) => term.first_arg(),
-            &PredicateClause::Rule(ref rule) => rule.head.1.first().map(|bt| bt.as_ref()),
+            &PredicateClause::Fact(ref term, ..) => term.first_arg(),
+            &PredicateClause::Rule(ref rule, ..) => rule.head.1.first().map(|bt| bt.as_ref()),
         }
     }
 
     pub fn arity(&self) -> usize {
         match self {
-            &PredicateClause::Fact(ref term) => term.arity(),
-            &PredicateClause::Rule(ref rule) => rule.head.1.len(),
+            &PredicateClause::Fact(ref term, ..) => term.arity(),
+            &PredicateClause::Rule(ref rule, ..) => rule.head.1.len(),
         }
     }
 
     pub fn name(&self) -> Option<ClauseName> {
         match self {
-            &PredicateClause::Fact(ref term) => term.name(),
-            &PredicateClause::Rule(ref rule) => Some(rule.head.0.clone()),
+            &PredicateClause::Fact(ref term, ..) => term.name(),
+            &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()
         }
     }
 }
index 96724665edc8dec01c2537b7f27e64f652988471..ddc77613d897ec33f116945daa0efdaa0e8a6957 100644 (file)
@@ -23,10 +23,10 @@ impl<'a> TermRef<'a> {
     pub fn level(self) -> Level {
         match self {
             TermRef::AnonVar(lvl)
-            | TermRef::Cons(lvl, ..)
-            | TermRef::Constant(lvl, ..)
-            | TermRef::Var(lvl, ..)
-            | TermRef::Clause(lvl, ..) => lvl,
+          | TermRef::Cons(lvl, ..)
+          | TermRef::Constant(lvl, ..)
+          | TermRef::Var(lvl, ..)
+          | TermRef::Clause(lvl, ..) => lvl,
         }
     }
 }
@@ -112,7 +112,8 @@ impl<'a> QueryIterator<'a> {
                     state_stack: vec![],
                 }
             }
-            &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()),
+            &Term::Var(ref cell, ref var) =>
+                TermIterState::Var(Level::Root, cell, (*var).clone()),
         };
 
         QueryIterator {
index 1805dc802cd77e8b7767c59b907eb1bc712fb6ad..3dea6bb3919778f1771dfa99d2f5fdcff0313333 100644 (file)
@@ -81,10 +81,12 @@ expand_body_term([Arg|Args], ModTerm, N0, N) :-
     append([Arg|Args], '$VAR'(N), ModArgs),
     ModTerm = ('$VAR'(N0) = ModArgs).
 expand_body_term((P -> Q), (PModTerm -> QModTerm), N0, N) :-
-    !, expand_body(P, PModTerm, N0, N1),
+    !,
+    expand_body(P, PModTerm, N0, N1),
     expand_body(Q, QModTerm, N1, N).
 expand_body_term((P ; Q), (PModTerm ; QModTerm), N0, N) :-
-    !, expand_body(P, PModTerm0, N0, N1),
+    !,
+    expand_body(P, PModTerm0, N0, N1),
     expand_body(Q, QModTerm0, N0, N2),
     ( N1 == N2 -> PModTerm = PModTerm0,
                  QModTerm = QModTerm0,
index 2554e256ab49c80798820a5997ee599abdf7550f..b226cb482418b6eb0f87be80e9d4f96021156f6d 100644 (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,14 +441,16 @@ impl ClauseCodeGenerator {
     {
         wam.code_repo.code.extend(self.code.into_iter());
 
+        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.clone(), arity),
+            wam.indices.dynamic_code_dir.insert((name.owning_module(), name, 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()));
-            }
         }
 
         for ((name, arity), p) in self.pi_to_loc {
@@ -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)
 }
index b9ea7457b76baf30c38d28ef80373548d14e347d..9ebdcdf66951c609c61f80888524f5d12f744e37 100644 (file)
@@ -27,11 +27,11 @@ impl Machine {
                     let module = idx.0.borrow().1.clone();
 
                     match module.as_str() {
-                        "user" => compile_user_module(self, src),
+                        "user" => compile_user_module(self, src, true),
                         _ => compile_into_module(self, module, src, name),
                     }
                 }
-                None => compile_user_module(self, src),
+                None => compile_user_module(self, src, true),
             },
             _ => compile_into_module(self, name.owning_module(), src, name),
         }
index a5a65934190fa8fdd28f42fce6e507390ac678c1..7247170d96fb9c2379e6b9458d04104da54bd3ea 100644 (file)
@@ -193,7 +193,7 @@ impl Machine {
 
     fn compile_top_level(&mut self) {
         self.toplevel_idx = self.code_repo.code.len();
-        compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()));
+        compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()), true);
     }
 
     fn compile_scryerrc(&mut self) {
@@ -210,7 +210,7 @@ impl Machine {
                 Err(_) => return,
             };
 
-            compile_user_module(self, file_src);
+            compile_user_module(self, file_src, true);
         }
     }
 
@@ -268,14 +268,15 @@ impl Machine {
             &mut wam,
             parsing_stream(BUILTINS.as_bytes()),
             default_index_store!(atom_tbl.clone()),
+            true
         );
 
         wam.compile_special_forms();
 
-        compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()));
-        compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()));
-        compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()));
-        compile_user_module(&mut wam, parsing_stream(SI.as_bytes()));
+        compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true);
+        compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true);
+        compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()), true);
+        compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true);
 
         wam.compile_top_level();
         wam.compile_scryerrc();
@@ -430,12 +431,12 @@ impl Machine {
        let load_result = match to_src(name) {
            ModuleSource::Library(name) =>
                if !self.indices.modules.contains_key(&name) {
-                   load_library(self, name).map(Some)
+                   load_library(self, name, false).map(Some)
                } else {
                    Ok(Some(name))
                },
            ModuleSource::File(name) =>
-                load_module_from_file(self, name.as_str())
+                load_module_from_file(self, name.as_str(), false)
        };
 
        let result = load_result.and_then(|name|
@@ -477,12 +478,12 @@ impl Machine {
        let load_result = match to_src(name) {
            ModuleSource::Library(name) =>
                if !self.indices.modules.contains_key(&name) {
-                   load_library(self, name).map(Some)
+                   load_library(self, name, false).map(Some)
                } else {
                    Ok(Some(name))
                },
            ModuleSource::File(name) =>
-                load_module_from_file(self, name.as_str())
+                load_module_from_file(self, name.as_str(), false)
        };
 
        let result = load_result.and_then(|name|
@@ -515,7 +516,7 @@ impl Machine {
                 let src = readline::input_stream();
                 readline::set_prompt(false);
 
-                if let EvalSession::Error(e) = compile_user_module(self, src) {
+                if let EvalSession::Error(e) = compile_user_module(self, src, false) {
                     self.throw_session_error(e, (clause_name!("repl"), 0));
                 }
             }
index 645f6fc3273aeac327e022a0e286f67ad153ffb7..931e6adceaa9a393c51d068fdaf11cf69b5371c9 100644 (file)
@@ -150,6 +150,16 @@ impl<'a, R: Read> TermStream<'a, R> {
         }
     }
 
+    #[inline]
+    pub fn line_num(&self) -> usize {
+        self.parser.line_num()
+    }
+
+    #[inline]
+    pub fn col_num(&self) -> usize {
+        self.parser.col_num()
+    }
+    
     #[inline]
     pub fn update_expansion_lens(&mut self) {
         let te_key = (clause_name!("term_expansion"), 2);
@@ -362,7 +372,7 @@ impl MachineState {
     ) -> Option<String> {
         let term_write_result = write_term_to_heap(term, self);
         let h = self.heap.h;
-
+        
         self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
         self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
         self[temp_v!(2)] = Addr::HeapCell(h);
index 3a7c4322fba8e2fcd2a20e279b6856a05e3f5a2b..12135a7bbdcd751c9142bd44ecf1aaad74cabba1 100644 (file)
@@ -287,15 +287,14 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
             TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl),
             TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl),
             TopLevel::Query(_) => return Err(ParserError::InconsistentEntry),
-            TopLevel::Fact(_) if is_consistent(&tl, &clauses) => {
-                if let TopLevel::Fact(fact) = tl {
-                    let clause = PredicateClause::Fact(fact);
+            TopLevel::Fact(..) if is_consistent(&tl, &clauses) =>
+                if let TopLevel::Fact(fact, line_num, col_num) = tl {
+                    let clause = PredicateClause::Fact(fact, line_num, col_num);
                     clauses.push(clause);
-                }
-            }
-            TopLevel::Rule(_) if is_consistent(&tl, &clauses) => {
-                if let TopLevel::Rule(rule) = tl {
-                    let clause = PredicateClause::Rule(rule);
+                },
+            TopLevel::Rule(..) if is_consistent(&tl, &clauses) => {
+                if let TopLevel::Rule(rule, line_num, col_num) = tl {
+                    let clause = PredicateClause::Rule(rule, line_num, col_num);
                     clauses.push(clause);
                 }
             }
@@ -357,6 +356,44 @@ fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
     found_cut_var
 }
 
+// terms is a list of goals composing one clause in a (;) functor. it
+// checks that the first (and only) of these clauses is a ->. if so,
+// it expands its terms using a blocked_!.
+fn check_for_internal_if_then(terms: &mut Vec<Term>) {
+    if terms.len() != 1 {
+        return;
+    }
+
+    if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
+        if name.as_str() != "->" || subterms.len() != 2 {
+            return;
+        }
+    } else {
+        return;
+    }
+
+    if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() {
+        let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
+        let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
+
+        conq_terms.push_front(Term::Constant(
+            Cell::default(),
+            Constant::Atom(clause_name!("blocked_!"), None))
+        );
+
+        while let Some(term) = pre_cut_terms.pop_back() {
+            conq_terms.push_front(term);
+        }
+
+        let tail_term = conq_terms.pop_back().unwrap();
+        terms.push(fold_by_str(
+            conq_terms.into_iter(),
+            tail_term,
+            clause_name!(","),
+        ));
+    }
+}
+
 fn flatten_hook(mut term: Term) -> Term {
     if let &mut Term::Clause(_, ref mut name, ref mut terms, _) = &mut term {
         match (name.as_str(), terms.len()) {
@@ -387,7 +424,9 @@ fn flatten_hook(mut term: Term) -> Term {
 fn setup_declaration(
     indices: &mut CompositeIndices,
     flags: MachineFlags,
-    mut terms: Vec<Box<Term>>
+    mut terms: Vec<Box<Term>>,
+    line_num: usize,
+    col_num: usize,
 ) -> Result<Declaration, ParserError> {
     let term = *terms.pop().unwrap();
 
@@ -413,10 +452,10 @@ fn setup_declaration(
                    Ok(Declaration::Dynamic(name, arity))
                }
                ("initialization", 1) => {
-                   let mut rel_worker = RelationWorker::new(flags);
+                   let mut rel_worker = RelationWorker::new(flags, line_num, col_num);
                    let query_terms = rel_worker.setup_query(indices, terms, false)?;
                    let queue = rel_worker.parse_queue(indices)?;
-                   
+
                    Ok(Declaration::ModuleInitialization(query_terms, queue))
                }
                _ =>
@@ -435,14 +474,18 @@ struct RelationWorker {
     flags: MachineFlags,
     dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
     queue: VecDeque<VecDeque<Term>>,
+    line_num: usize,
+    col_num: usize
 }
 
 impl RelationWorker {
-    fn new(flags: MachineFlags) -> Self {
+    fn new(flags: MachineFlags, line_num: usize, col_num: usize) -> Self {
         RelationWorker {
             dynamic_clauses: vec![],
             flags,
             queue: VecDeque::new(),
+            line_num,
+            col_num
         }
     }
 
@@ -507,6 +550,8 @@ impl RelationWorker {
                 let mut subterms = unfold_by_str(term, ",");
                 mark_cut_variables(&mut subterms);
 
+                check_for_internal_if_then(&mut subterms);
+
                 let term = subterms.pop().unwrap();
                 fold_by_str(subterms.into_iter(), term, clause_name!(","))
             })
@@ -704,12 +749,12 @@ impl RelationWorker {
             Term::Clause(r, name, terms, _) => {
                 if name == hook.name() && terms.len() == hook.arity() {
                     let term = self.setup_fact(Term::Clause(r, name, terms, None), false)?;
-                    Ok((hook, PredicateClause::Fact(term), VecDeque::from(vec![])))
+                    Ok((hook, PredicateClause::Fact(term, 0, 0), VecDeque::from(vec![])))
                 } else if name.as_str() == ":-" && terms.len() == 2 {
                     let rule = self.setup_rule(indices, terms, true, false)?;
                     let results_queue = self.parse_queue(indices)?;
 
-                    Ok((hook, PredicateClause::Rule(rule), results_queue))
+                    Ok((hook, PredicateClause::Rule(rule, 0, 0), results_queue))
                 } else {
                     Err(ParserError::InvalidHook)
                 }
@@ -787,15 +832,16 @@ impl RelationWorker {
                         terms,
                         blocks_cuts,
                         true,
-                    )?))
+                    )?, self.line_num, self.col_num))
                 } else if name.as_str() == ":-" && terms.len() == 1 {
-                    Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms)?))
+                    Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms,
+                                                               self.line_num, self.col_num)?))
                 } else {
                     let term = Term::Clause(r, name, terms, fixity);
-                    Ok(TopLevel::Fact(try!(self.setup_fact(term, true))))
+                    Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
                 }
             }
-            term => Ok(TopLevel::Fact(try!(self.setup_fact(term, true)))),
+            term => Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)),
         }
     }
 
@@ -875,7 +921,10 @@ fn term_to_toplevel<R>(
 where
     R: Read,
 {
-    let mut rel_worker = RelationWorker::new(flags);
+    let line_num = term_stream.line_num();
+    let col_num  = term_stream.col_num();
+
+    let mut rel_worker = RelationWorker::new(flags, line_num, col_num);
     let mut indices = composite_indices!(false, &mut term_stream.wam.indices, code_dir);
 
     let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?;
@@ -928,9 +977,12 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
     ) -> Self {
         let term_stream = TermStream::new(inner, atom_tbl, flags, wam);
 
+        let line_num = term_stream.line_num();
+        let col_num  = term_stream.col_num();
+
         TopLevelBatchWorker {
             term_stream,
-            rel_worker: RelationWorker::new(flags),
+            rel_worker: RelationWorker::new(flags, line_num, col_num),
             results: vec![],
             dynamic_clause_map: IndexMap::new(),
             in_module: false,
@@ -942,7 +994,10 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
         indices: &mut IndexStore,
         term: Term,
     ) -> Result<(TopLevel, RelationWorker), SessionError> {
-        let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags);
+        let line_num = self.term_stream.line_num();
+        let col_num  = self.term_stream.col_num();
+
+        let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags, line_num, col_num);
         let mut indices = composite_indices!(
             self.in_module,
             indices,
@@ -1023,11 +1078,16 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
             self.rel_worker.absorb(new_rel_worker);
 
             match tl {
-                TopLevel::Fact(fact) => preds.push(PredicateClause::Fact(fact)),
-                TopLevel::Rule(rule) => preds.push(PredicateClause::Rule(rule)),
-                TopLevel::Predicate(pred) => preds.extend(pred.0),
-                TopLevel::Declaration(decl) => return Ok(Some(decl)),
-                TopLevel::Query(_) => return Err(SessionError::NamelessEntry),
+                TopLevel::Fact(fact, line_num, col_num) =>
+                    preds.push(PredicateClause::Fact(fact, line_num, col_num)),
+                TopLevel::Rule(rule, line_num, col_num) =>
+                    preds.push(PredicateClause::Rule(rule, line_num, col_num)),
+                TopLevel::Predicate(pred) =>
+                    preds.extend(pred.0),
+                TopLevel::Declaration(decl) =>
+                    return Ok(Some(decl)),
+                TopLevel::Query(_) =>
+                    return Err(SessionError::NamelessEntry),
             }
         }
 
index cbb7a8be175f9cdc18bfddce0351936c13e1d603..1b482e9e36a14c3125758bc6b732e101796c329d 100644 (file)
@@ -195,7 +195,7 @@ pub fn submit_query_with_limit(
 
 #[allow(dead_code)]
 pub fn submit_code(wam: &mut Machine, buf: &str) -> EvalSession {
-    compile_user_module(wam, parsing_stream(buf.as_bytes()))
+    compile_user_module(wam, parsing_stream(buf.as_bytes()), true)
 }
 
 #[allow(unused_macros)]