diff --git a/src/lib/si.pl b/src/lib/si.pl index 4c3b6c65..bdebc956 100644 --- a/src/lib/si.pl +++ b/src/lib/si.pl @@ -36,6 +36,7 @@ integer_si/1, atomic_si/1, list_si/1, + character_si/1, chars_si/1, dif_si/2]). @@ -62,9 +63,29 @@ list_si(L0) :- ; throw(error(instantiation_error, list_si/1)) ). -chars_si(Cs) :- - list_si(Cs), - '$is_partial_string'(Cs). +character_si(Ch) :- + functor(Ch,Ch,0), + atom(Ch), + atom_length(Ch,1). + +chars_si(Chs0) :- + '$skip_max_list'(_,_, Chs0,Chs), + ( nonvar(Chs) -> Chs == [] ; true ), % fails for infinite lists too + failnochars(Chs0, Uninstantiated), + ( nonvar(Uninstantiated) + -> throw(error(instantiation_error, chars_si/1)) + ; true + ). + +failnochars(Chs0, U) :- + ( var(Chs0) -> U = true + ; Chs0 == [] -> true + ; Chs0 = [Ch|Chs1], + ( nonvar(Ch) -> atom(Ch), atom_length(Ch,1) + ; U = true + ), + failnochars(Chs1, U) + ). dif_si(X, Y) :- X \== Y, diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 0faf34c3..a3575c7f 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1258,7 +1258,7 @@ fn print_overwrite_warning( _ => {} } - println!("Warning: overwriting {}/{}", key.0.as_str(), key.1); + println!("Warning: overwriting {}/{} because the clauses are discontiguous", key.0.as_str(), key.1); } impl<'a, LS: LoadState<'a>> Loader<'a, LS> { @@ -2220,7 +2220,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let payload_compilation_target = self.payload.compilation_target; - let local_predicate_info = self + let mut local_predicate_info = self .wam_prelude .indices .get_local_predicate_skeleton( @@ -2242,6 +2242,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let is_cross_module_clause = payload_compilation_target != self.payload.predicates.compilation_target; + local_predicate_info.is_discontiguous = predicate_info.is_discontiguous; + if local_predicate_info.must_retract_local_clauses(is_cross_module_clause) { self.retract_local_clauses(&key, predicate_info.is_dynamic); } diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index 6c6d3a7b..a17240f1 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -530,7 +530,36 @@ impl VariableClassifier { } }; + let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec| { + if update_chunk_data(classifier, name, terms.len()) { + build_stack.add_chunk(); + } + + for (arg_c, term) in terms.iter().enumerate() { + classifier.probe_body_term(arg_c + 1, terms.len(), term); + } + + build_stack.push_chunk_term( + clause_to_query_term( + loader, + name, + terms, + classifier.call_policy, + ), + ); + }; + match term { + Term::Clause(_, name @ (atom!("->") | atom!(";") | atom!(",")), mut terms) if terms.len() == 3 => { + if let Some(last_arg) = terms.last() { + if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { + terms.pop(); + state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), name, terms))); + } else { + add_chunk(self, name, terms); + } + } + } Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => { let tail = terms.pop().unwrap(); let head = terms.pop().unwrap(); @@ -700,22 +729,7 @@ impl VariableClassifier { self.call_policy = CallPolicy::Counted; } Term::Clause(_, name, terms) => { - if update_chunk_data(self, name, terms.len()) { - build_stack.add_chunk(); - } - - for (arg_c, term) in terms.iter().enumerate() { - self.probe_body_term(arg_c + 1, terms.len(), term); - } - - build_stack.push_chunk_term( - clause_to_query_term( - loader, - name, - terms, - self.call_policy, - ), - ); + add_chunk(self, name, terms); } var @ Term::Var(..) => { if update_chunk_data(self, atom!("call"), 1) { diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 9d66ce64..0fe88cbb 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -32,8 +32,7 @@ use std::ops::{Deref, DerefMut}; * loader.pl does a few high-level things more easily handled from * Prolog that are not supported (or needed) during bootstrapping: * term and goal expansion, loading modules from different streams, - * verifying certain kinds of declarations, perhaps (in the future?) - * compiling inline disjunctions. + * and verifying certain kinds of declarations. * * Since the loader can operate incrementally, it uses an intermittent * structure to rebuild the loader between invocations. Preprocessor @@ -1279,6 +1278,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { name: Atom, arity: usize, ) -> Result<(), SessionError> { + let key = (name, arity); + + let predicate_info = self + .wam_prelude + .indices + .get_predicate_skeleton(&self.payload.predicates.compilation_target, &key) + .map(|skeleton| skeleton.predicate_info()) + .unwrap_or_default(); + + self.retract_local_clauses(&key, predicate_info.is_dynamic); + self.add_extensible_predicate_declaration( compilation_target, name, diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index 8c6b055d..e352fc45 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -9,6 +9,7 @@ use crate::read::devour_whitespace; use crate::predicate_queue; +use fxhash::FxBuildHasher; use indexmap::IndexSet; use std::collections::VecDeque; @@ -19,7 +20,7 @@ pub struct LoadStatePayload { pub(super) compilation_target: CompilationTarget, pub(super) retraction_info: RetractionInfo, pub(super) module_op_exports: ModuleOpExports, - pub(super) non_counted_bt_preds: IndexSet, + pub(super) non_counted_bt_preds: IndexSet, pub(super) predicates: PredicateQueue, pub(super) clause_clauses: Vec<(Term, Term)>, } @@ -97,10 +98,10 @@ impl LoadStatePayload { compilation_target: CompilationTarget::default(), retraction_info: RetractionInfo::new(code_repo_len), module_op_exports: vec![], - non_counted_bt_preds: IndexSet::new(), + non_counted_bt_preds: IndexSet::with_hasher(FxBuildHasher::default()), predicates: predicate_queue![], clause_clauses: vec![], - } + } } } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index fc728782..05ca5a37 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -830,30 +830,3 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { terms.push(term); terms } - -fn unfold_by_str_ref_once(term: &Term, s: Atom) -> Option<(&Term, &Term)> { - if let Term::Clause(_, ref name, ref subterms) = term { - if name == &s && subterms.len() == 2 { - let fst = &subterms[0]; - let snd = &subterms[1]; - - return Some((fst, snd)); - } - } - - None -} - -pub fn unfold_by_str_ref(mut term: &Term, s: Atom) -> Vec<&Term> { - let mut terms = vec![]; - - while let Some((fst, snd)) = unfold_by_str_ref_once(&term, s) { - terms.push(fst); - term = snd; - } - - terms.push(term); - terms -} - -