From 8073a4ba872303ad4abf745e5c20212836db8c6c Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Thu, 3 Aug 2023 22:27:13 +0200 Subject: [PATCH 1/4] add character_si/1 and use it to correct chars_si/1 This addresses #1947. --- src/lib/si.pl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/si.pl b/src/lib/si.pl index 4c3b6c65..910cad5b 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,15 @@ 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(Chs) :- + \+ \+ length(Chs,_), + \+ ( once(length(Chs,_)), member(Ch,Chs), nonvar(Ch), \+ character_si(Ch) ), + \+ ( member(Ch,Chs), \+ character_si(Ch) ). % for the instantiation error dif_si(X, Y) :- X \== Y, From 924750f826d2aecc0612619102a20d9ab79ba909 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 4 Aug 2023 21:18:00 +0200 Subject: [PATCH 2/4] ENHANCED: more efficient chars_si/1, using specialized predicates of Scryer Source: https://github.com/mthom/scryer-prolog/issues/1947#issuecomment-1665113488 --- src/lib/si.pl | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/lib/si.pl b/src/lib/si.pl index 910cad5b..bdebc956 100644 --- a/src/lib/si.pl +++ b/src/lib/si.pl @@ -68,10 +68,24 @@ character_si(Ch) :- atom(Ch), atom_length(Ch,1). -chars_si(Chs) :- - \+ \+ length(Chs,_), - \+ ( once(length(Chs,_)), member(Ch,Chs), nonvar(Ch), \+ character_si(Ch) ), - \+ ( member(Ch,Chs), \+ character_si(Ch) ). % for the instantiation error +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, From 094cf2ac5dc0533cf04e83c0068758aa74e50df1 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 5 Aug 2023 12:15:28 -0600 Subject: [PATCH 3/4] retract discontiguous non-multifile predicates between consultations (#1202, #1058, #1585) --- src/machine/compile.rs | 6 ++++-- src/machine/loader.rs | 14 ++++++++++++-- src/machine/term_stream.rs | 7 ++++--- 3 files changed, 20 insertions(+), 7 deletions(-) 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/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![], - } + } } } From fad363e64acf8be7c0888a7f3bf399b598591fbb Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 6 Aug 2023 01:26:01 -0600 Subject: [PATCH 4/4] shed CodeIndex for control predicates in disjuncts.rs (#1791) --- src/machine/disjuncts.rs | 46 ++++++++++++++++++++++++++-------------- src/parser/ast.rs | 27 ----------------------- 2 files changed, 30 insertions(+), 43 deletions(-) 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/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 -} - -