[package]
name = "scryer-prolog"
-version = "0.8.98"
+version = "0.8.99"
build = "build.rs"
repository = "https://github.com/mthom/scryer-prolog"
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"
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,
}
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 {
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;
#[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)]
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>);
.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()
}
}
}
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,
}
}
}
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 {
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,
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 {
}
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(|_| {
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);
+ }
+ }
+ }
}
}
) -> 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(())
}
}
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));
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,
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())?;
{
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 {
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) {
}
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)
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,
.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
}
}
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());
}
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
};
}
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
};
}
}
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)
}
}
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(
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() {
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)
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) => {
}
}
-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)
}
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),
}
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) {
Err(_) => return,
};
- compile_user_module(self, file_src);
+ compile_user_module(self, file_src, true);
}
}
&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();
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|
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|
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));
}
}
}
}
+ #[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);
) -> 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);
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);
}
}
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()) {
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();
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))
}
_ =>
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
}
}
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!(","))
})
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)
}
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)),
}
}
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)?;
) -> 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,
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,
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),
}
}
#[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)]