From adb5fcf7085c83b27cc1b3f23fec9be69dc913db Mon Sep 17 00:00:00 2001 From: Jacob Date: Wed, 13 Sep 2023 12:29:12 -0400 Subject: [PATCH 01/60] Upgrade dashu and some changes --- Cargo.lock | 30 ++++++++++------- Cargo.toml | 2 +- src/arithmetic.rs | 11 +++---- src/heap_print.rs | 21 ++++++------ src/machine/arithmetic_ops.rs | 54 ++++++++++++++----------------- src/machine/loader.rs | 2 +- src/machine/machine_state_impl.rs | 6 +--- src/machine/preprocessor.rs | 5 +-- 8 files changed, 61 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5651a7a7..a2a4121d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,8 +388,9 @@ dependencies = [ [[package]] name = "dashu" -version = "0.3.1" -source = "git+https://github.com/cmpute/dashu.git#9d1ba4ac98a4675f294e2f2c072bf47f96d33e9b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b669b1473cc6b33aba72ab3ddfe1055ff8fc28accd85130c412c2cd922a7c4e" dependencies = [ "dashu-base", "dashu-float", @@ -400,13 +401,15 @@ dependencies = [ [[package]] name = "dashu-base" -version = "0.3.1" -source = "git+https://github.com/cmpute/dashu.git#9d1ba4ac98a4675f294e2f2c072bf47f96d33e9b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e183fc153511989674ede304b5592c74683393ca09cf20391898c28d6ba04264" [[package]] name = "dashu-float" -version = "0.3.2" -source = "git+https://github.com/cmpute/dashu.git#9d1ba4ac98a4675f294e2f2c072bf47f96d33e9b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7696675af30ae057b1629d27b153bbafb06461826b7d0ef1858d06b801f355f" dependencies = [ "dashu-base", "dashu-int", @@ -417,8 +420,9 @@ dependencies = [ [[package]] name = "dashu-int" -version = "0.3.1" -source = "git+https://github.com/cmpute/dashu.git#9d1ba4ac98a4675f294e2f2c072bf47f96d33e9b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc257a884b3e8c9a1a577ff7226dcb4d6bda0ff96dfa76975e2c9d7205e3b8ea" dependencies = [ "cfg-if", "dashu-base", @@ -429,8 +433,9 @@ dependencies = [ [[package]] name = "dashu-macros" -version = "0.3.1" -source = "git+https://github.com/cmpute/dashu.git#9d1ba4ac98a4675f294e2f2c072bf47f96d33e9b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496c319e615b86b21d6b0ea9e2f96a4f5fb2eb4178293b04a51ffc30a6c3f54" dependencies = [ "dashu-base", "dashu-float", @@ -442,8 +447,9 @@ dependencies = [ [[package]] name = "dashu-ratio" -version = "0.3.2" -source = "git+https://github.com/cmpute/dashu.git#9d1ba4ac98a4675f294e2f2c072bf47f96d33e9b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0f73f0ad6cbc94f52306455603e307b065af83bc61101968d53b6870127a05" dependencies = [ "dashu-base", "dashu-float", diff --git a/Cargo.toml b/Cargo.toml index 92c08572..0df15b08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,7 +68,7 @@ libloading = "0.7" derive_deref = "1.1.1" http-body-util = "0.1.0-rc.2" bytes = "1" -dashu = { version = "0.3.1", git = "https://github.com/cmpute/dashu.git" } +dashu = "0.4.0" num-order = { version = "1.2.0" } rand = "0.8.5" diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 95b4fe2c..8ec3cee8 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -386,8 +386,7 @@ pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number { &Number::Rational(ref r) => { let (_, floor) = (r.fract(), r.floor()); - let result = floor.clone().try_into(); - if let Ok(value) = result{ + if let Ok(value) = (&floor).try_into() { fixnum!(Number, value, arena) } else { Number::Integer(arena_alloc!(floor, arena)) @@ -713,13 +712,13 @@ impl TryFrom for Number { // Computes n ^ power. Ignores the sign of power. pub(crate) fn binary_pow(mut n: Integer, power: &Integer) -> Integer { - let mut power = Integer::from(power.abs()); + let mut power = power.abs(); - if power.num_eq(&0) { - return Integer::from(1); + if power.is_zero() { + return Integer::ONE; } - let mut oddand = Integer::from(1); + let mut oddand = Integer::ONE; while power.num_gt(&1) { if power.bit(0) { diff --git a/src/heap_print.rs b/src/heap_print.rs index 01be59d6..b02ef119 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1,7 +1,9 @@ use crate::arena::*; use crate::atom_table::*; use crate::parser::ast::*; -use crate::parser::dashu::{Integer, Rational}; +use crate::parser::dashu::{ibig, Integer, Rational}; +use crate::parser::dashu::base::RemEuclid; +use crate::parser::dashu::integer::Sign; use crate::{ alpha_numeric_char, capital_letter_char, cut_char, decimal_digit_char, graphic_token_char, is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, semicolon_char, @@ -18,8 +20,6 @@ use crate::machine::stack::*; use crate::machine::streams::*; use crate::types::*; -use dashu::base::DivRem; -use dashu::base::DivRemEuclid; use ordered_float::OrderedFloat; use indexmap::IndexMap; @@ -515,13 +515,10 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ]; - let n_clone: Integer = n.clone(); + let i: usize = (&n).rem_euclid(ibig!(26)).try_into().unwrap(); + let j = n / ibig!(26); - let i = n.div_rem_euclid(Integer::from(26)).1.to_f32().value() as usize; - let j = n_clone.div_rem(Integer::from(26)); - let j = <(Integer, Integer)>::from(j).0; - - if j == Integer::from(0) { + if j.is_zero() { CHAR_CODES[i].to_string() } else { format!("{}{}", CHAR_CODES[i], j) @@ -1024,7 +1021,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) { Some(op_desc) => { - if r.denominator().is_one() { + if r.is_int() { let output_str = format!("{}", r); push_space_if_amb!(self, &output_str, { @@ -1367,10 +1364,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if self.numbervars && arity == 1 && name == atom!("$VAR") { !self.iter.immediate_leaf_has_property(|addr| { match Number::try_from(addr) { - Ok(Number::Integer(n)) => &*n >= &Integer::from(0), + Ok(Number::Integer(n)) => (*n).sign() == Sign::Positive, Ok(Number::Fixnum(n)) => n.get_num() >= 0, Ok(Number::Float(f)) => f >= OrderedFloat(0f64), - Ok(Number::Rational(r)) => &*r >= &Rational::from(0), + Ok(Number::Rational(r)) => (*r).sign() == Sign::Positive, _ => false, } }) && needs_bracketing(op_desc, op) diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 21d46a85..69e48cad 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1,7 +1,5 @@ use dashu::base::Abs; -use dashu::base::DivRem; use dashu::base::Gcd; -use dashu::integer::IBig; use divrem::*; use num_order::NumOrd; @@ -562,7 +560,7 @@ pub(crate) fn rdiv( r1: TypedArenaPtr, r2: TypedArenaPtr, ) -> Result { - if &*r2 == &Rational::from(0) { + if r2.is_zero() { let stub_gen = || { let rdiv_atom = atom!("rdiv"); functor_stub(rdiv_atom, 2) @@ -596,7 +594,7 @@ pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result { - if (&*n2).num_eq(&0) { + if n2.is_zero() { Err(zero_divisor_eval_error(stub_gen)) } else { Ok(Number::arena_from(Integer::from(n1) / &*n2, arena)) @@ -610,13 +608,10 @@ pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result { - if (&*n2).num_eq(&0) { + if n2.is_zero() { Err(zero_divisor_eval_error(stub_gen)) } else { - Ok(Number::arena_from( - <(Integer, Integer)>::from((&*n1).div_rem(&*n2)).0, - arena, - )) + Ok(Number::arena_from(&*n1 / &*n2, arena)) } } (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { @@ -853,6 +848,16 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result Integer { + if n1 > &Integer::ZERO && n2 < &Integer::ZERO { + ((n1 - Integer::ONE) / n2) - Integer::ONE + } else if n1 < &Integer::ZERO && n2 > &Integer::ZERO { + ((n1 + Integer::ONE) / n2) - Integer::ONE + } else { + n1 / n2 + } + } + match (x, y) { (Number::Fixnum(n1), Number::Fixnum(n2)) => { let n2_i = n2.get_num(); @@ -865,14 +870,11 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result { - if (&*n2).num_eq(&0) { + if n2.is_zero() { Err(zero_divisor_eval_error(stub_gen)) } else { let n1 = Integer::from(n1.get_num()); - Ok(Number::arena_from( - <(Integer, Integer)>::from(n1.div_rem(&*n2)).1, - arena, - )) + Ok(Number::arena_from(ibig_rem_floor(&n1, &*n2), arena)) } } (Number::Integer(n1), Number::Fixnum(n2)) => { @@ -882,20 +884,14 @@ pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result::from((&*n1).div_rem(&n2)).1, - arena, - )) + Ok(Number::arena_from(ibig_rem_floor(&*n1, &n2), arena)) } } - (Number::Integer(x), Number::Integer(y)) => { - if (&*y).num_eq(&0) { + (Number::Integer(n1), Number::Integer(n2)) => { + if n2.is_zero() { Err(zero_divisor_eval_error(stub_gen)) } else { - Ok(Number::arena_from( - <(Integer, Integer)>::from((&*x).div_rem(&*y)).1, - arena, - )) + Ok(Number::arena_from(ibig_rem_floor(&*n1, &*n2), arena)) } } (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { @@ -923,7 +919,7 @@ pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result { - if (&*n2).num_eq(&0) { + if n2.is_zero() { Err(zero_divisor_eval_error(stub_gen)) } else { let n1 = Integer::from(n1.get_num()); @@ -941,7 +937,7 @@ pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result { - if (&*n2).num_eq(&0) { + if n2.is_zero() { Err(zero_divisor_eval_error(stub_gen)) } else { Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena)) @@ -968,7 +964,7 @@ pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result Result { - let n1_clone: Integer = (*n1).clone(); let n2: isize = (&*n2).try_into().unwrap(); - Ok(Number::arena_from(Integer::from(n1_clone.gcd(&Integer::from(n2))) as IBig, arena)) + let value: Integer = (&*n1).gcd(&Integer::from(n2)).into(); + Ok(Number::arena_from(value, arena)) } (Number::Float(f), _) | (_, Number::Float(f)) => { let n = Number::Float(f); diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 01c512bf..b5133700 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1636,7 +1636,7 @@ impl Machine { let arity = self.deref_register(3); let arity = match Number::try_from(arity) { - Ok(Number::Integer(n)) if &*n >= &Integer::from(0) && &*n <= &Integer::from(MAX_ARITY) => { + Ok(Number::Integer(n)) if &*n >= &Integer::ZERO && &*n <= &Integer::from(MAX_ARITY) => { let value: usize = (&*n).try_into().unwrap(); Ok(value) }, diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 465b96f5..2c909937 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -16,7 +16,6 @@ use crate::parser::dashu::{Integer, Rational}; use crate::types::*; use indexmap::IndexSet; -use num_order::NumOrd; use std::cmp::Ordering; use std::convert::TryFrom; @@ -1183,10 +1182,7 @@ impl MachineState { let n = match n { Number::Fixnum(n) => n.get_num() as usize, - Number::Integer(n) if (*n).num_ge(&0) && (*n).num_le(&std::usize::MAX) => { - let value: usize = (&*n).try_into().unwrap(); - value - }, + Number::Integer(n) if usize::try_from(&*n).is_ok() => (&*n).try_into().unwrap(), _ => { self.fail = true; return Ok(()); diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 958bc3c4..27152323 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -58,10 +58,7 @@ fn setup_predicate_indicator(term: &mut Term) -> Result { - let value: usize = (&*n).try_into().unwrap(); - Some(value) - }, + Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(), Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(), _ => None, } From 5b1df8c4b3c816a348f7c570066448440d6ff18f Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Wed, 13 Sep 2023 20:45:38 +0200 Subject: [PATCH 02/60] use version from crates.io --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0df15b08..92b35ded 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,7 @@ num-order = { version = "1.2.0" } rand = "0.8.5" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -libffi = { git = "https://github.com/coasys/libffi-rs.git", branch = "windows-space", optional = true, version = "3.2.0" } +libffi = { version = "3.2.0", optional = true } hostname = { version = "0.3.1", optional = true } crossterm = { version = "0.20.0", optional = true } ctrlc = { version = "3.2.2", optional = true } From 9dc1c339ef1f25e4be9bd04b3ad7280e116aefb8 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 15 Sep 2023 14:10:42 -0600 Subject: [PATCH 03/60] remove unnecessary Result return type from read_term_from_heap --- Cargo.lock | 6 ++++-- src/machine/compile.rs | 2 +- src/machine/loader.rs | 18 +++++++++--------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2a4121d..c383d82e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1126,7 +1126,8 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libffi" version = "3.2.0" -source = "git+https://github.com/coasys/libffi-rs.git?branch=windows-space#f6e9e50efde0aa4e940dd6f709a59bb426875362" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" dependencies = [ "libc", "libffi-sys", @@ -1135,7 +1136,8 @@ dependencies = [ [[package]] name = "libffi-sys" version = "2.3.0" -source = "git+https://github.com/coasys/libffi-rs.git?branch=windows-space#f6e9e50efde0aa4e940dd6f709a59bb426875362" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" dependencies = [ "cc", ] diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 170bffaf..2245ef41 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -2331,7 +2331,7 @@ impl Machine { let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {}); - let term = loader.read_term_from_heap(term_loc)?; + let term = loader.read_term_from_heap(term_loc); let clause = build_rule_body(vars, term); let settings = CodeGenSettings { diff --git a/src/machine/loader.rs b/src/machine/loader.rs index b5133700..59db0208 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -483,7 +483,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } - pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Result { + pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; @@ -1074,7 +1074,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; - let export_list = machine_st.read_term_from_heap(cell)?; + let export_list = machine_st.read_term_from_heap(cell); let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl; let export_list = setup_module_export_list(export_list, &atom_tbl)?; @@ -1401,7 +1401,7 @@ impl MachineState { pub(super) fn read_term_from_heap( &mut self, term_addr: HeapCellValue, - ) -> Result { + ) -> Term { let mut term_stack = vec![]; let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, term_addr); @@ -1494,7 +1494,7 @@ impl MachineState { } debug_assert!(term_stack.len() == 1); - Ok(term_stack.pop().unwrap()) + term_stack.pop().unwrap() } } @@ -1661,7 +1661,7 @@ impl Machine { let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { - let term = loader.read_term_from_heap(temp_v!(1))?; + let term = loader.read_term_from_heap(temp_v!(1)); loader.incremental_compile_clause( (atom!("term_expansion"), 2), @@ -1691,7 +1691,7 @@ impl Machine { }; let add_clause = || { - let term = loader.read_term_from_heap(temp_v!(2))?; + let term = loader.read_term_from_heap(temp_v!(2)); let indexing_arg = match term.name() { Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg), @@ -2008,7 +2008,7 @@ impl Machine { loader.payload.compilation_target = compilation_target; let head = LiveLoadAndMachineState::machine_st(&mut loader.payload) - .read_term_from_heap(head)?; + .read_term_from_heap(head); let name = if let Some(name) = head.name() { name @@ -2044,7 +2044,7 @@ impl Machine { return LiveLoadAndMachineState::evacuate(loader); } - let body = loader.read_term_from_heap(temp_v!(3))?; + let body = loader.read_term_from_heap(temp_v!(3)); let asserted_clause = Term::Clause( Cell::default(), @@ -2482,7 +2482,7 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { self.payload.predicates.compilation_target = compilation_target; } - let term = self.read_term_from_heap(term_reg)?; + let term = self.read_term_from_heap(term_reg); self.add_clause_clause_if_dynamic(&term)?; self.payload.term_stream.term_queue.push_back(term); From 7cf6e77f4ddc04d1c5c009a269445935af41ea20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Arroyo=20Calle?= Date: Wed, 20 Sep 2023 21:54:14 +0200 Subject: [PATCH 04/60] Use a SeedableRng to generate random numbers --- src/machine/mock_wam.rs | 1 + src/machine/mod.rs | 4 ++++ src/machine/system_calls.rs | 18 +++++++++--------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index cd8f7836..2b8f2ca0 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -246,6 +246,7 @@ impl Machine { runtime, #[cfg(feature = "ffi")] foreign_function_table: Default::default(), + rng: StdRng::from_entropy(), }; let mut lib_path = current_dir(); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 7e456d4e..d9f68ac3 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -54,6 +54,8 @@ use std::env; use std::path::PathBuf; use std::sync::atomic::AtomicBool; use tokio::runtime::Runtime; +use rand::rngs::StdRng; +use rand::SeedableRng; lazy_static! { pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); @@ -71,6 +73,7 @@ pub struct Machine { pub(super) runtime: Runtime, #[cfg(feature = "ffi")] pub(super) foreign_function_table: ForeignFunctionTable, + pub(super) rng: StdRng, } #[derive(Debug)] @@ -472,6 +475,7 @@ impl Machine { runtime, #[cfg(feature = "ffi")] foreign_function_table: Default::default(), + rng: StdRng::from_entropy(), }; let mut lib_path = current_dir(); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 412afca6..81680e9b 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -42,7 +42,6 @@ use indexmap::IndexSet; pub(crate) use ref_thread_local::RefThreadLocal; -use std::borrow::BorrowMut; use std::cell::Cell; use std::cmp::Ordering; use std::collections::BTreeSet; @@ -4216,15 +4215,13 @@ impl Machine { #[inline(always)] pub(crate) fn maybe(&mut self) { - fn generate_random_bits(num_bits: usize) -> u64 { - let mut rng = rand::thread_rng(); - let rand = rng.borrow_mut(); + fn generate_random_bits(rng: &mut rand::rngs::StdRng, num_bits: usize) -> u64 { let mut random_bits: u64 = 0; for _ in 0..num_bits { random_bits <<= 1; - if rand.gen_bool(0.5) { + if rng.gen_bool(0.5) { random_bits |= 1; } } @@ -4232,7 +4229,7 @@ impl Machine { random_bits } - let result = { generate_random_bits(1) == 0 }; + let result = { generate_random_bits(&mut self.rng, 1) == 0 }; self.machine_st.fail = result; } @@ -6184,16 +6181,19 @@ impl Machine { match Number::try_from(seed) { Ok(Number::Fixnum(n)) => { let n: u64 = Integer::from(n).try_into().unwrap(); - let _: StdRng = SeedableRng::seed_from_u64(n); + let rng: StdRng = SeedableRng::seed_from_u64(n); + self.rng = rng; }, Ok(Number::Integer(n)) => { let n: u64 = (&*n).try_into().unwrap(); - let _: StdRng = SeedableRng::seed_from_u64(n); + let rng: StdRng = SeedableRng::seed_from_u64(n); + self.rng = rng; }, Ok(Number::Rational(n)) => { if n.denominator() == &UBig::from(1 as u32) { let n: u64 = n.numerator().try_into().unwrap(); - let _: StdRng = SeedableRng::seed_from_u64(n); + let rng: StdRng = SeedableRng::seed_from_u64(n); + self.rng = rng; } } _ => { From eecfeb2d037e42a316d3cc9a065b0199a2178a5a Mon Sep 17 00:00:00 2001 From: infogulch Date: Wed, 20 Sep 2023 16:38:58 -0500 Subject: [PATCH 05/60] Simplify maybe Fix whitespace --- src/machine/mock_wam.rs | 2 +- src/machine/mod.rs | 2 +- src/machine/system_calls.rs | 32 ++++++++------------------------ 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 2b8f2ca0..47717d9d 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -246,7 +246,7 @@ impl Machine { runtime, #[cfg(feature = "ffi")] foreign_function_table: Default::default(), - rng: StdRng::from_entropy(), + rng: StdRng::from_entropy(), }; let mut lib_path = current_dir(); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index d9f68ac3..0018610e 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -475,7 +475,7 @@ impl Machine { runtime, #[cfg(feature = "ffi")] foreign_function_table: Default::default(), - rng: StdRng::from_entropy(), + rng: StdRng::from_entropy(), }; let mut lib_path = current_dir(); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 81680e9b..08d7ad21 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -76,7 +76,7 @@ use ring::{digest, hkdf, pbkdf2}; #[cfg(feature = "crypto-full")] use ring::{ - aead, + aead, signature::{self, KeyPair}, }; use ripemd160::{Digest, Ripemd160}; @@ -3263,7 +3263,7 @@ impl Machine { match Number::try_from(addr) { Ok(Number::Integer(n)) => { let n: u8 = (&*n).try_into().unwrap(); - + match n { nb => { match stream.write(&mut [nb]) { @@ -4215,23 +4215,7 @@ impl Machine { #[inline(always)] pub(crate) fn maybe(&mut self) { - fn generate_random_bits(rng: &mut rand::rngs::StdRng, num_bits: usize) -> u64 { - let mut random_bits: u64 = 0; - - for _ in 0..num_bits { - random_bits <<= 1; - - if rng.gen_bool(0.5) { - random_bits |= 1; - } - } - - random_bits - } - - let result = { generate_random_bits(&mut self.rng, 1) == 0 }; - - self.machine_st.fail = result; + self.machine_st.fail = self.rng.gen(); } #[cfg(not(target_arch = "wasm32"))] @@ -4575,7 +4559,7 @@ impl Machine { Ok(Number::Fixnum(n)) => n.get_num() as u16, Ok(Number::Integer(n)) => { let n: Result = (&*n).try_into(); - + if let Ok(value) = n { value } else { @@ -6182,18 +6166,18 @@ impl Machine { Ok(Number::Fixnum(n)) => { let n: u64 = Integer::from(n).try_into().unwrap(); let rng: StdRng = SeedableRng::seed_from_u64(n); - self.rng = rng; + self.rng = rng; }, Ok(Number::Integer(n)) => { let n: u64 = (&*n).try_into().unwrap(); let rng: StdRng = SeedableRng::seed_from_u64(n); - self.rng = rng; + self.rng = rng; }, Ok(Number::Rational(n)) => { if n.denominator() == &UBig::from(1 as u32) { let n: u64 = n.numerator().try_into().unwrap(); let rng: StdRng = SeedableRng::seed_from_u64(n); - self.rng = rng; + self.rng = rng; } } _ => { @@ -7323,7 +7307,7 @@ impl Machine { let iterations = match Number::try_from(iterations) { Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => { - let n: Result = (&*n).try_into(); + let n: Result = (&*n).try_into(); match n { Ok(i) => i, _ => { From a64a765f32af532a3d3211a6d832a08c6d9dd9cf Mon Sep 17 00:00:00 2001 From: bakaq Date: Wed, 20 Sep 2023 20:56:04 -0300 Subject: [PATCH 06/60] Improved dif/2 --- src/lib/dif.pl | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/lib/dif.pl b/src/lib/dif.pl index 73d65518..4fe35b80 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -7,7 +7,7 @@ arguments are different terms. :- use_module(library(atts)). :- use_module(library(dcgs)). -:- use_module(library(lists), [append/3]). +:- use_module(library(lists), [append/3, maplist/3]). :- attribute dif/1. @@ -23,6 +23,29 @@ dif_set_variables([Var|Vars], X, Y) :- put_dif_att(Var, X, Y), dif_set_variables(Vars, X, Y). +remove_goal([], _, []). +remove_goal([G0|G0s], Goal0, Goals) :- + ( G0 == Goal0 -> + remove_goal(G0s, Goal0, Goals) + ; Goals = [G0|Goals1], + remove_goal(G0s, Goal0, Goals1) + ). + +vars_remove_goal([], _). +vars_remove_goal([Var|Vars], Goal0) :- + get_atts(Var, +dif(Goals0)), + remove_goal(Goals0, Goal0, Goals), + put_atts(Var, +dif(Goals)), + vars_remove_goal(Vars, Goal0). + +reinforce_goal(Goal0, Goal) :- + Goal = ( + term_variables(Goal0, Vars), + dif:vars_remove_goal(Vars, Goal0), + Goal0 = (L \== R), + dif(L, R) + ). + append_goals([], _). append_goals([Var|Vars], Goals) :- ( get_atts(Var, +dif(VarGoals)) -> @@ -34,9 +57,10 @@ append_goals([Var|Vars], Goals) :- append_goals(Vars, Goals). verify_attributes(Var, Value, Goals) :- - ( get_atts(Var, +dif(Goals)) -> + ( get_atts(Var, +dif(Goals0)) -> term_variables(Value, ValueVars), - append_goals(ValueVars, Goals) + append_goals(ValueVars, Goals0), + maplist(reinforce_goal, Goals0, Goals) ; Goals = [] ). From f5c23fbb16bcbd1cc25f699c31317f3f4a6e62ce Mon Sep 17 00:00:00 2001 From: bakaq Date: Wed, 20 Sep 2023 20:56:25 -0300 Subject: [PATCH 07/60] Tests for dif/2 --- tests-pl/dif_tests.pl | 235 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 tests-pl/dif_tests.pl diff --git a/tests-pl/dif_tests.pl b/tests-pl/dif_tests.pl new file mode 100644 index 00000000..01ece5fa --- /dev/null +++ b/tests-pl/dif_tests.pl @@ -0,0 +1,235 @@ +/**/ + +:- use_module(library(format)). +:- use_module(library(dcgs)). +:- use_module(library(lists)). +:- use_module(library(debug)). +:- use_module(library(atts)). +:- use_module(library(dif)). + +% Tests from https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif + +test("dif#1",( + call_residual_goals(dif(1,2), Res), + Res = [] +)). + +test("dif#2",( + \+ (dif(1,Y), Y = 1) +)). + +test("dif#3",( + call_residual_goals((dif(1,Y), Y=2), Res), + Y == 2, + Res = [] +)). + +test("dif#4",( + \+ (dif(X,-Y), X= -Y) +)). + +test("dif#5",( + \+ (dif(X,Y), X=Y) +)). + +test("dif#6",( + \+ (dif(X,Y), X=Y, X=1) +)). + +test("dif#7",( + \+ (dif(-X,-Y), X=Y) +)). + +test("dif#8",( + \+ (dif(-X,-Y), X=Y, X=1) +)). + +% I don't understand exactly what is expected for dif#9 and dif#10 + +test("dif#11",( + call_residual_goals((X=Y, dif(X-Y,1-2)), Res), + X == Y, + Res = [] +)). + +test("dif#12",( + call_residual_goals((dif(X-Y,1-2), X=Y), Res), + X == Y, + Res = [] +)). + +test("dif#13",( + call_residual_goals((X=Y, Y=1, dif(X-Y,1-2)), Res), + X == 1, + Y == 1, + Res = [] +)). + +test("dif#14",( + call_residual_goals((dif(X-Y,1-2), X=Y, Y=1), Res), + X == 1, + Y == 1, + Res = [] +)). + +test("dif#15",( + call_residual_goals((dif(X-Y,1-2), X=Y, X=2), Res), + X == 2, + Y == 2, + Res = [] +)). + +test("dif#16",( + call_residual_goals((dif(A-C,B-D), C-D=z-z, A-B=1-2), Res), + A == 1, + B == 2, + C == z, + D == z, + Res = [] +)). + +test("dif#17",( + call_residual_goals((A-B=1-2, C-D=z-z, dif(A-C,B-D)), Res), + A == 1, + B == 2, + C == z, + D == z, + Res = [] +)). + +test("dif#18",( + call_residual_goals((dif(A,[C|B]), A=[[]|_], A=[B]), Res), + A == [[]], + B == [], + Res = [dif:dif([[]], [C])] +)). + +test("dif#19",( + call_residual_goals((dif([E],[/]), E=1), Res), + E == 1, + Res = [] +)). + +test("dif#20",( + call_residual_goals((dif([a],B), B=[_|_], B=[b]), Res), + B == [b], + Res = [] +)). + +test("dif#21",( + call_residual_goals((dif([],A), A = [_]), Res), + A = [_], + Res = [] +)). + +test("dif#22",( + call_residual_goals((A = [_], dif([],A)), Res), + A = [_], + Res = [] +)). + +test("dif#t1",( + set_prolog_flag(occurs_check, false), + \+ \+ -X=X +)). + +test("dif#t2",( + set_prolog_flag(occurs_check, false), + \+ (-X=X, -Y=Y, X\=Y) +)). + +test("dif#t3",( + set_prolog_flag(occurs_check, false), + call_residual_goals((-X=X, dif(X,1)), Res), + X == -X, + Res = [] +)). + +test("dif#t4",( + set_prolog_flag(occurs_check, false), + \+ (-X=X, -Y=Y, dif(X,Y)) +)). + +test("dif#t5",( + set_prolog_flag(occurs_check, false), + \+ (dif(X,Y), -X=X, -Y=Y) +)). + +test("dif#t6",( + set_prolog_flag(occurs_check, false), + \+ (A=[[]|A],dif(A,B),B=[[]|A]) +)). + +test("dif#t7",( + set_prolog_flag(occurs_check, false), + \+ (dif(-X,X),-Y=Y,X=Y) +)). + +test("dif#o1",( + set_prolog_flag(occurs_check, true), + \+ (-X = X) +)). + +test("dif#o2",( + set_prolog_flag(occurs_check, true), + call_residual_goals((dif(-X,X)), Res), + Res = [] +)). + +test("dif#o3",( + set_prolog_flag(occurs_check, true), + call_residual_goals((dif(-X,Y), X=Y), Res), + X == Y, + Res = [] +)). + +test("dif#12 but with multiple variables in the residuals",( + call_residual_goals((dif(X-Y-_, 1-2-3), X = Y), Res), + X == Y, + Res = [] +)). + +main :- + findall(test(Name, Goal), test(Name, Goal), Tests), + run_tests(Tests, Failed), + show_failed(Failed), + halt. + +portray_failed_([]) --> []. +portray_failed_([F|Fs]) --> + "\"", F, "\"", "\n", portray_failed_(Fs). + +portray_failed([]) --> []. +portray_failed([F|Fs]) --> + "\n", "Failed tests:", "\n", portray_failed_([F|Fs]). + +show_failed(Failed) :- + phrase(portray_failed(Failed), F), + format("~s", [F]). + +run_tests([], []). +run_tests([test(Name, Goal)|Tests], Failed) :- + format("Running test \"~s\"~n", [Name]), + ( call(Goal) -> + Failed = Failed1 + ; format("Failed test \"~s\"~n", [Name]), + Failed = [Name|Failed1] + ), + run_tests(Tests, Failed1). + +assert_p(A, B) :- + phrase(portray_clause_(A), Portrayed), + phrase((B, ".\n"), Portrayed). + +call_residual_goals(Goal, ResidualGoals) :- + call_residue_vars(Goal, Vars), + variables_residual_goals(Vars, ResidualGoals). + +variables_residual_goals(Vars, Goals) :- + phrase(variables_residual_goals(Vars), Goals). + +variables_residual_goals([]) --> []. +variables_residual_goals([Var|Vars]) --> + dif:attribute_goals(Var), + variables_residual_goals(Vars). + From cac52c05376b8d1701c81cc5f631913ed2b412c5 Mon Sep 17 00:00:00 2001 From: bakaq Date: Thu, 21 Sep 2023 12:14:27 -0300 Subject: [PATCH 08/60] Run dif tests on cargo test --- tests-pl/dif_tests.pl => src/tests/dif.pl | 17 +++++++++++++++++ tests/scryer/src_tests.rs | 9 +++++++++ 2 files changed, 26 insertions(+) rename tests-pl/dif_tests.pl => src/tests/dif.pl (91%) diff --git a/tests-pl/dif_tests.pl b/src/tests/dif.pl similarity index 91% rename from tests-pl/dif_tests.pl rename to src/tests/dif.pl index 01ece5fa..752458b5 100644 --- a/tests-pl/dif_tests.pl +++ b/src/tests/dif.pl @@ -195,6 +195,15 @@ main :- show_failed(Failed), halt. +main_quiet :- + findall(test(Name, Goal), test(Name, Goal), Tests), + run_tests_quiet(Tests, Failed), + ( Failed = [] -> + format("All tests passed", []) + ; format("Some tests failed", []) + ), + halt. + portray_failed_([]) --> []. portray_failed_([F|Fs]) --> "\"", F, "\"", "\n", portray_failed_(Fs). @@ -217,6 +226,14 @@ run_tests([test(Name, Goal)|Tests], Failed) :- ), run_tests(Tests, Failed1). +run_tests_quiet([], []). +run_tests_quiet([test(Name, Goal)|Tests], Failed) :- + ( call(Goal) -> + Failed = Failed1 + ; Failed = [Name|Failed1] + ), + run_tests_quiet(Tests, Failed1). + assert_p(A, B) :- phrase(portray_clause_(A), Portrayed), phrase((B, ".\n"), Portrayed). diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index f913788e..5572b75f 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -75,3 +75,12 @@ fn clpz_load() { fn iso_conformity_tests() { load_module_test("tests-pl/iso-conformity-tests.pl", "All tests passed"); } + +#[test] +fn dif_tests() { + run_top_level_test_with_args( + &["src/tests/dif.pl", "-f", "-g", "main_quiet"], + "", + "All tests passed", + ); +} From cb79e83510066c2ef14d96ff441d844869222f1e Mon Sep 17 00:00:00 2001 From: bakaq Date: Thu, 21 Sep 2023 14:00:37 -0300 Subject: [PATCH 09/60] Avoid dif/1 attribute with empty list Closes #1956 --- src/lib/dif.pl | 5 ++++- src/tests/dif.pl | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/dif.pl b/src/lib/dif.pl index 4fe35b80..fedb320c 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -35,7 +35,10 @@ vars_remove_goal([], _). vars_remove_goal([Var|Vars], Goal0) :- get_atts(Var, +dif(Goals0)), remove_goal(Goals0, Goal0, Goals), - put_atts(Var, +dif(Goals)), + ( Goals = [] -> + put_atts(Var, -dif(_)) + ; put_atts(Var, +dif(Goals)) + ), vars_remove_goal(Vars, Goal0). reinforce_goal(Goal0, Goal) :- diff --git a/src/tests/dif.pl b/src/tests/dif.pl index 752458b5..bb1c76d6 100644 --- a/src/tests/dif.pl +++ b/src/tests/dif.pl @@ -189,6 +189,13 @@ test("dif#12 but with multiple variables in the residuals",( Res = [] )). +% https://github.com/mthom/scryer-prolog/issues/1956 +test("scryer-prolog#1956",( + call_residue_vars((dif(a-a,X-_),X=b), Res), + X == b, + Res = [] +)). + main :- findall(test(Name, Goal), test(Name, Goal), Tests), run_tests(Tests, Failed), From b3239abea188deb0fa032aa44b494f1a6d19d506 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 21 Sep 2023 14:36:53 -0600 Subject: [PATCH 10/60] throw resource error if OpenOptions raises an error of uncategorized kind (#1375) --- src/machine/machine_errors.rs | 26 +++++++++++++++++++++----- src/machine/streams.rs | 9 ++++----- src/machine/system_calls.rs | 2 +- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 279ec18e..5b4e4479 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -77,6 +77,12 @@ impl ValidType { } } +#[derive(Debug, Clone, Copy)] +pub(crate) enum ResourceError { + FiniteMemory(HeapCellValue), + OutOfFiles +} + pub(crate) trait TypeError { fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError; } @@ -284,11 +290,21 @@ impl MachineState { } } - pub(super) fn resource_error(&mut self, value: HeapCellValue) -> MachineError { - let stub = functor!( - atom!("resource_error"), - [atom(atom!("finite_memory")), cell(value)] - ); + pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError { + let stub = match err { + ResourceError::FiniteMemory(size_requested) => { + functor!( + atom!("resource_error"), + [atom(atom!("finite_memory")), cell(size_requested)] + ) + } + ResourceError::OutOfFiles => { + functor!( + atom!("resource_atom"), + [atom(atom!("out_of_files"))] + ) + } + }; MachineError { stub, diff --git a/src/machine/streams.rs b/src/machine/streams.rs index b91ea8b8..b5632417 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1804,7 +1804,7 @@ impl MachineState { ) -> Result { if file_spec == atom!("") { let stub = functor_stub(atom!("open"), 4); - let err = self.domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); + let err = self.domain_error(DomainErrorType::SourceSink, self.registers[1]); return Err(self.error_form(err, stub)); } @@ -1816,9 +1816,7 @@ impl MachineState { } } - let mode = MachineState::deref(self, self[temp_v!(2)]); - let mode = cell_as_atom!(self.store(mode)); - + let mode = cell_as_atom!(self.store(MachineState::deref(self, self.registers[2]))); let mut open_options = OpenOptions::new(); let (is_input_file, in_append_mode) = match mode { @@ -1875,8 +1873,9 @@ impl MachineState { )); } _ => { + // assume the OS is out of file descriptors. let stub = functor_stub(atom!("open"), 4); - let err = self.syntax_error(ParserError::IO(err)); + let err = self.resource_error(ResourceError::OutOfFiles); return Err(self.error_form(err, stub)); } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 08d7ad21..9e2d9760 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -4244,7 +4244,7 @@ impl Machine { Ok(Number::Integer(n)) => match (&*n).try_into() as Result { Ok(n) => n, Err(_) => { - let err = self.machine_st.resource_error(len); + let err = self.machine_st.resource_error(ResourceError::FiniteMemory(len)); return Err(self.machine_st.error_form(err, stub_gen())); } }, From c26e9436b41f6b02569c9ff23bc5319cc06b754f Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 21 Sep 2023 16:22:41 -0600 Subject: [PATCH 11/60] generalize multifile/dynamic/discontiguous declarations over lists of predicate indicators (#1586) --- src/loader.pl | 62 ++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index 0ba61117..cf72820e 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -379,6 +379,29 @@ remove_module(Module, Evacuable) :- ; domain_error(module_specifier, Module, use_module/2) ). +:- meta_predicate add_predicate_declaration(3, ?). + +add_predicate_declaration(Handler, Name/Arity) :- + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + call(Handler, Module, Name, Arity). +add_predicate_declaration(Handler, Module:Name/Arity) :- + must_be(atom, Module), + must_be(atom, Name), + must_be(integer, Arity), + call(Handler, Module, Name, Arity). +add_predicate_declaration(Handler, [PI|PIs]) :- + maplist(loader:add_predicate_declaration(Handler), [PI|PIs]). + +add_dynamic_predicate(Evacuable, Module, Name, Arity) :- + '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). + +add_multifile_predicate(Evacuable, Module, Name, Arity) :- + '$add_multifile_predicate'(Module, Name, Arity, Evacuable). + +add_discontiguous_predicate(Evacuable, Module, Name, Arity) :- + '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). compile_declaration(use_module(Module), Evacuable) :- use_module(Module, [], Evacuable). @@ -392,39 +415,12 @@ compile_declaration(module(Module, Exports), Evacuable) :- '$declare_module'(Module, Exports, Evacuable) ; type_error(atom, Module, load/1) ). -compile_declaration(dynamic(Module:Name/Arity), Evacuable) :- - !, - must_be(atom, Module), - must_be(atom, Name), - must_be(integer, Arity), - '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). -compile_declaration(dynamic(Name/Arity), Evacuable) :- - must_be(atom, Name), - must_be(integer, Arity), - prolog_load_context(module, Module), - '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). -compile_declaration(multifile(Module:Name/Arity), Evacuable) :- - !, - must_be(atom, Module), - must_be(atom, Name), - must_be(integer, Arity), - '$add_multifile_predicate'(Module, Name, Arity, Evacuable). -compile_declaration(multifile(Name/Arity), Evacuable) :- - must_be(atom, Name), - must_be(integer, Arity), - prolog_load_context(module, Module), - '$add_multifile_predicate'(Module, Name, Arity, Evacuable). -compile_declaration(discontiguous(Module:Name/Arity), Evacuable) :- - !, - must_be(atom, Module), - must_be(atom, Name), - must_be(integer, Arity), - '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). -compile_declaration(discontiguous(Name/Arity), Evacuable) :- - must_be(atom, Name), - must_be(integer, Arity), - prolog_load_context(module, Module), - '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(dynamic(PIs), Evacuable) :- + add_predicate_declaration(loader:add_dynamic_predicate(Evacuable), PIs). +compile_declaration(multifile(PIs), Evacuable) :- + add_predicate_declaration(loader:add_multifile_predicate(Evacuable), PIs). +compile_declaration(discontiguous(PIs), Evacuable) :- + add_predicate_declaration(loader:add_discontiguous_predicate(Evacuable), PIs). compile_declaration(initialization(Goal), Evacuable) :- prolog_load_context(module, Module), assertz(Module:'$initialization_goals'(Goal)). From c547f67c54aa251402838062a37b4ef8383d5dcd Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 21 Sep 2023 16:49:45 -0600 Subject: [PATCH 12/60] add (now failing) test 317 to iso_conformity_tests.pl --- tests-pl/iso-conformity-tests.pl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests-pl/iso-conformity-tests.pl b/tests-pl/iso-conformity-tests.pl index 94185a07..324820ac 100644 --- a/tests-pl/iso-conformity-tests.pl +++ b/tests-pl/iso-conformity-tests.pl @@ -774,7 +774,7 @@ test_175 :- T = t(0b1,0o1,0x1), test_176 :- X is 0b1mod 2, X == 1. -test_217_181_290 :- +test_217_181_290_317 :- setup_call_cleanup(( current_op(P, xfy, '|') -> true ; P = 0 @@ -785,7 +785,10 @@ test_217_181_290 :- C0 == "a-->b,c | d", read_from_chars("[(a|b)].", T1), writeq_term_to_chars(T1, C1), - C1 == "[(a | b)]" + C1 == "[(a | b)]", + read_from_chars("[a,(b,c)|[]].", T2), + writeq_term_to_chars(T2, C2), + C2 == "[a,(b,c)]" ), op(P, xfy, '|')). From 1c8cd85f6c0c429c632ae62f1cbedee17b998554 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 23 Sep 2023 00:19:54 -0600 Subject: [PATCH 13/60] record compaction depth after reduce_op if '|' an operator (#1905) --- src/parser/ast.rs | 2 +- src/parser/parser.rs | 50 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 1351b044..a03602df 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -808,7 +808,7 @@ pub fn source_arity(terms: &[Term]) -> usize { terms.len() } -fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> { +pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> { if let Term::Clause(_, ref name, ref mut subterms) = term { if let Some(last_arg) = subterms.last() { if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 2160c764..57193239 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -58,6 +58,7 @@ struct TokenDesc { tt: TokenType, priority: usize, spec: u32, + unfold_bounds: usize, } pub(crate) fn as_partial_string( @@ -371,6 +372,7 @@ impl<'a, R: CharRead> Parser<'a, R> { tt: TokenType::Term, priority: td.priority, spec, + unfold_bounds: 0, }); } } @@ -392,6 +394,7 @@ impl<'a, R: CharRead> Parser<'a, R> { tt: TokenType::Term, priority: td.priority, spec, + unfold_bounds: 0, }); } } @@ -405,6 +408,7 @@ impl<'a, R: CharRead> Parser<'a, R> { tt: TokenType::Term, priority, spec: assoc, + unfold_bounds: 0, }); } @@ -460,7 +464,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::End => TokenType::End, }; - self.stack.push(TokenDesc { tt, priority, spec }); + self.stack.push(TokenDesc { tt, priority, spec, unfold_bounds: 0, }); } fn reduce_op(&mut self, priority: usize) { @@ -602,14 +606,16 @@ impl<'a, R: CharRead> Parser<'a, R> { } if let Some(&mut TokenDesc { + ref mut tt, ref mut priority, ref mut spec, - ref mut tt, + ref mut unfold_bounds, }) = self.stack.last_mut() { *tt = TokenType::Term; *priority = 0; *spec = TERM; + *unfold_bounds = 0; } return true; @@ -625,8 +631,8 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { - if let Some(term) = self.terms.pop() { - let op_desc = self.stack[index - 1]; + if let Some(mut term) = self.terms.pop() { + let mut op_desc = self.stack[index - 1]; if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { /* '|' is a head-tail separator here, not @@ -634,7 +640,26 @@ impl<'a, R: CharRead> Parser<'a, R> { * terms it compacted out again. */ match (term.name(), term.arity()) { (Some(name), 2) if name == atom!(",") => { - let terms = unfold_by_str(term, name); // notice: name == "," here. + let terms = if op_desc.unfold_bounds == 0 { + unfold_by_str(term, atom!(",")) + } else { + let mut terms = vec![]; + + while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) { + terms.push(fst); + term = snd; + + op_desc.unfold_bounds -= 2; + + if op_desc.unfold_bounds == 0 { + break; + } + } + + terms.push(term); + terms + }; + let arity = terms.len() - 1; self.terms.extend(terms.into_iter()); @@ -750,6 +775,7 @@ impl<'a, R: CharRead> Parser<'a, R> { tt: TokenType::Term, priority: 0, spec: TERM, + unfold_bounds: 0, }); self.terms.push(match list { @@ -975,6 +1001,7 @@ impl<'a, R: CharRead> Parser<'a, R> { ), Token::Literal(c) => { let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c); + if let Some(name) = atomized { if !self.shift_op(name, op_dir)? { self.shift(Token::Literal(c), 0, TERM); @@ -1018,13 +1045,20 @@ impl<'a, R: CharRead> Parser<'a, R> { /* '|' as an operator must have priority > 1000 and can only be infix. * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 */ - let bar_atom = atom!("|"); - - let (priority, spec) = get_op_desc(bar_atom, op_dir) + let (priority, spec) = get_op_desc(atom!("|"), op_dir) .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec)) .unwrap_or((1000, DELIMITER)); + let old_stack_len = self.stack.len(); + self.reduce_op(priority); + + let new_stack_len = self.stack.len(); + + if let Some(term_desc) = self.stack.last_mut() { + term_desc.unfold_bounds = old_stack_len - new_stack_len; + } + self.shift(Token::HeadTailSeparator, priority, spec); } Token::Comma => { From 142e0c2c3ac4aec4831b6fea33fade76dc5bc9e9 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 23 Sep 2023 14:26:28 -0600 Subject: [PATCH 14/60] don't parse bracketed non-operators as functor terms (#2033) --- src/parser/ast.rs | 1 + src/parser/parser.rs | 6 +++++- tests-pl/iso-conformity-tests.pl | 11 ++++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/parser/ast.rs b/src/parser/ast.rs index a03602df..f1f15080 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -34,6 +34,7 @@ pub const FY: u32 = 0x0080; pub const DELIMITER: u32 = 0x0100; pub const TERM: u32 = 0x1000; pub const LTERM: u32 = 0x3000; +pub const BTERM: u32 = 0x11000; pub const NEGATIVE_SIGN: u32 = 0x0200; diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 57193239..f2de37bc 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -612,6 +612,10 @@ impl<'a, R: CharRead> Parser<'a, R> { ref mut unfold_bounds, }) = self.stack.last_mut() { + if *spec == BTERM { + return false; + } + *tt = TokenType::Term; *priority = 0; *spec = TERM; @@ -878,7 +882,7 @@ impl<'a, R: CharRead> Parser<'a, R> { .push(Term::Literal(Cell::default(), Literal::Atom(atom))); } - self.stack[idx].spec = TERM; + self.stack[idx].spec = if self.stack[idx].priority > 0 { TERM } else { BTERM }; self.stack[idx].tt = TokenType::Term; self.stack[idx].priority = 0; diff --git a/tests-pl/iso-conformity-tests.pl b/tests-pl/iso-conformity-tests.pl index 324820ac..2f8adec1 100644 --- a/tests-pl/iso-conformity-tests.pl +++ b/tests-pl/iso-conformity-tests.pl @@ -467,13 +467,14 @@ test_195_205_196_197 :- setup_call_cleanup(op(100,xf,''), ( read_from_chars("(0 '') = ''(X).", T0), call(T0), - T0 = (_ = ('')(0)), + writeq_term_to_chars(T0, C0), + C0 == "0 ''=0 ''", read_from_chars("0 ''.", T1), - writeq_term_to_chars(T1, C0), - C0 == "0 ''", + writeq_term_to_chars(T1, C1), + C1 == "0 ''", read_from_chars("0''.", T2), - writeq_term_to_chars(T2, C1), - C1 == "0 ''" ), + writeq_term_to_chars(T2, C2), + C2 == "0 ''" ), op(0,xf,'')). test_118_119_120 :- From a5db117ef6a60662ac70371481bc6b7df5f83a20 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 23 Sep 2023 18:32:32 -0600 Subject: [PATCH 15/60] fix off-by-1 bug in ''/4 (#2037) --- src/machine/system_calls.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 9e2d9760..4a54ad91 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -180,12 +180,6 @@ impl BrentAlgState { } pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { - /* - if let Some(var) = heap[self.hare].as_var() { - return CycleSearchResult::PartialList(self.num_steps(), var); - } - */ - loop { read_heap_cell!(heap[self.hare], (HeapCellValueTag::PStrOffset) => { @@ -248,7 +242,7 @@ impl BrentAlgState { let cstr = PartialString::from(cstr_atom); let num_chars = cstr.as_str_from(offset).chars().count(); - if self.max_steps == -1 || self.num_steps() + num_chars < self.max_steps as usize { + if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { self.pstr_chars += num_chars; Some(CycleSearchResult::ProperList(self.num_steps())) } else { @@ -261,7 +255,7 @@ impl BrentAlgState { let pstr = PartialString::from(pstr_atom); let num_chars = pstr.as_str_from(offset).chars().count(); - if self.max_steps == -1 || self.num_steps() + num_chars < self.max_steps as usize { + if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { self.pstr_chars += num_chars - 1; self.step(h+1) } else { From f03336b3a2a124107d16d86924c442196aabd2f9 Mon Sep 17 00:00:00 2001 From: Joe Taber Date: Sat, 23 Sep 2023 21:43:51 -0500 Subject: [PATCH 16/60] Allow all jobs to run to completion even if one fails See: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategyfail-fast --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ec3a051..786defb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,7 @@ jobs: build-test: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: include: - { os: windows-latest, rust-version: stable, shell: 'msys2 {0}', target: 'x86_64-pc-windows-gnu'} From 9c43974747aaddb79dc2eb77996b1bf976f819ba Mon Sep 17 00:00:00 2001 From: Rujia Liu Date: Sun, 24 Sep 2023 19:10:40 +0800 Subject: [PATCH 17/60] Solves CRLF/CR issue by considering'\r' a `layout_char` #553 #2028 --- src/parser/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/macros.rs b/src/parser/macros.rs index 702f6ae1..26bd0b2b 100644 --- a/src/parser/macros.rs +++ b/src/parser/macros.rs @@ -132,7 +132,7 @@ macro_rules! hexadecimal_digit_char { #[macro_export] macro_rules! layout_char { ($c: expr) => { - $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']) + $crate::char_class!($c, [' ', '\r', '\n', '\t', '\u{0B}', '\u{0C}']) }; } From 35d0042be1cd83914d3362fafbd1b5d90c4a155a Mon Sep 17 00:00:00 2001 From: bakaq Date: Thu, 21 Sep 2023 21:06:02 -0300 Subject: [PATCH 18/60] Add phrase_from_stream/2 to library(pio) --- src/lib/pio.pl | 170 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 154 insertions(+), 16 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index fdc5bcb1..781f14c8 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -9,6 +9,7 @@ :- module(pio, [phrase_from_file/2, phrase_from_file/3, + phrase_from_stream/2, phrase_to_file/2, phrase_to_file/3, phrase_to_stream/2 @@ -17,16 +18,30 @@ :- use_module(library(dcgs)). :- use_module(library(error)). :- use_module(library(freeze)). -:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]). -:- use_module(library(lists), [member/2, maplist/2]). +:- use_module(library(gensym)). +:- use_module(library(iso_ext), [ + bb_get/2, bb_put/2, setup_call_cleanup/3, partial_string/3, partial_string_tail/2 +]). +:- use_module(library(lists), [length/2, member/2, maplist/2]). :- use_module(library(charsio), [get_n_chars/3]). :- meta_predicate(phrase_from_file(2, ?)). :- meta_predicate(phrase_from_file(2, ?, ?)). +:- meta_predicate(phrase_from_stream(2, ?)). :- meta_predicate(phrase_to_file(2, ?)). :- meta_predicate(phrase_to_file(2, ?, ?)). :- meta_predicate(phrase_to_stream(2, ?)). + +%% phrase_from_stream(+GRBody, +Stream) +% +% True if grammar rule body GRBody covers the contents of the stream, +% represented as a list of characters. + +phrase_from_stream(GRBody, Stream) :- + stream_to_lazy_list(Stream, Ls), + phrase(GRBody, Ls). + %% phrase_from_file(+GRBody, +File) % % True if grammar rule body GRBody covers the contents of File, @@ -49,24 +64,147 @@ phrase_from_file(NT, File, Options) :- ; Type = text ), setup_call_cleanup(open(File, read, Stream, [reposition(true)|Options]), - ( stream_to_lazy_list(Stream, Xs), - phrase(NT, Xs) ), + phrase_from_stream(NT, Stream), close(Stream)) - ). - + ). stream_to_lazy_list(Stream, Xs) :- - stream_property(Stream, position(Pos)), - freeze(Xs, reader_step(Stream, Pos, Xs)). + stream_property(Stream, reposition(Rep)), + ( Rep = true -> + stream_to_lazy_list_repositionable(Stream, Xs) + ; stream_to_lazy_list_buffer(Stream, Xs) + ). -reader_step(Stream, Pos, Xs0) :- - set_stream_position(Stream, Pos), - ( at_end_of_stream(Stream) - -> Xs0 = [] - ; get_n_chars(Stream, 4096, Cs), - partial_string(Cs, Xs0, Xs), - stream_to_lazy_list(Stream, Xs) - ). +stream_to_lazy_list_repositionable(Stream, Xs) :- + stream_property(Stream, position(Pos)), + freeze(Xs, reader_step_repositionable(Stream, Pos, Xs)). + +reader_step_repositionable(Stream, Pos, Xs0) :- + set_stream_position(Stream, Pos), + ( at_end_of_stream(Stream) + -> Xs0 = [] + ; get_n_chars(Stream, 4096, Cs), + partial_string(Cs, Xs0, Xs), + stream_to_lazy_list_repositionable(Stream, Xs) + ). + +stream_to_lazy_list_buffer(Stream, Ls) :- + get_stream_buffer_position(Stream, Pos), + freeze(Ls, render_step_buffer(Stream, Pos, Ls)). + +render_step_buffer(Stream, Pos, Ls) :- + set_stream_buffer_position(Stream, Pos), + ( buffer_at_end_of_stream(Stream) -> + Ls = [] + ; buffer_get_n_chars(Stream, 4096, Chars), + partial_string(Chars, Ls, Ls0), + stream_to_lazy_list_buffer(Stream, Ls0) + ). + +buffer_at_end_of_stream(Stream) :- + stream_bufferids(Stream, _, BufferPosId, _), + bb_get(BufferPosId, Pos), + Pos = eof. + +get_stream_buffer_position(Stream, Pos) :- + stream_bufferids(Stream, _, BufferPosId, _), + bb_get(BufferPosId, Pos). + +set_stream_buffer_position(Stream, Pos) :- + stream_bufferids(Stream, _, BufferPosId, _), + bb_put(BufferPosId, Pos). + +buffer_get_n_chars(Stream, N, Chars) :- + stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId), + buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N), + bb_get(BufferId, Buffer), + bb_get(BufferPosId, BufferPos), + ( BufferPos = eof -> + Chars = [] + ; string_get_n_chars(Buffer, BufferPos, N, Chars), + length(Chars, NChars), + ( NChars = 0 -> + BufferPos1 = eof + ; BufferPos1 is BufferPos + NChars + ), + bb_put(BufferPosId, BufferPos1) + ). + +buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N) :- + bb_get(BufferPosId, BufferPos), + bb_get(BufferLenId, BufferLen), + ( BufferLen < BufferPos + N -> + bb_get(BufferId, Buffer), + ( + ( var(Buffer) -> + BufferTail = Buffer + ; partial_string_last_tail(Buffer, BufferTail) + ) -> + ( at_end_of_stream(Stream) -> + BufferTail = [], + bb_put(BufferId, Buffer) + ; get_n_chars(Stream, 4096, Chars), + length(Chars, NChars), + partial_string(Chars, BufferTail, _), + bb_put(BufferId, Buffer), + BufferLen1 is BufferLen + NChars, + bb_put(BufferLenId, BufferLen1), + buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N) + ) + ; true + ) + ; true + ). + +partial_string_last_tail(PartialString, PartialStringTail) :- + partial_string_tail(PartialString, PartialStringTail0), + ( var(PartialStringTail0) -> + PartialStringTail = PartialStringTail0 + ; partial_string_last_tail(PartialStringTail0, PartialStringTail) + ). + +string_get_n_chars([], _, _, []). +string_get_n_chars([S|Ss], BufferPos, N, Chars) :- + ( BufferPos = 0 -> + string_get_n_chars_([S|Ss], N, Chars) + ; BufferPos1 is BufferPos - 1, + string_get_n_chars(Ss, BufferPos1, N, Chars) + ). + +string_get_n_chars_([], _, []). +string_get_n_chars_([S|Ss], N, Chars) :- + ( N = 0 -> + Chars = [] + ; N = 1 -> + % This case is needed to not break the tail of the partial string + Chars = [S] + ; Chars = [S|Cs], + N1 is N - 1, + string_get_n_chars_(Ss, N1, Cs) + ). + +stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId) :- + ( bb_get(streams_buffers, _) -> + true + ; bb_put(streams_buffers, []) + ), + bb_get(streams_buffers, StreamsBuffers), + ( member( + stream_buffer(Stream, BufferId, BufferPosId, BufferLenId), + StreamsBuffers + ) -> + true + ; gensym(buffer, BufferId), + gensym(buffer_pos, BufferPosId), + gensym(buffer_len, BufferLenId), + bb_put( + streams_buffers, + [stream_buffer(Stream, BufferId, BufferPosId, BufferLenId)|StreamsBuffers] + ), + bb_put(BufferId, _), + bb_put(BufferPosId, 0), + bb_put(BufferLenId, 0) + ). %% phrase_to_stream(+GRBody, +Stream) % From b4fab5a80646e3beee6f9a945209c50b78c98ec4 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sat, 23 Sep 2023 01:43:45 -0300 Subject: [PATCH 19/60] Use '$skip_max_list'/4 in string_get_n_chars/4 --- src/lib/pio.pl | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 781f14c8..8688e1c9 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -68,6 +68,9 @@ phrase_from_file(NT, File, Options) :- close(Stream)) ). +% How many chars to read from stream and buffer in each step +chars_to_read(4096). + stream_to_lazy_list(Stream, Xs) :- stream_property(Stream, reposition(Rep)), ( Rep = true -> @@ -83,7 +86,8 @@ reader_step_repositionable(Stream, Pos, Xs0) :- set_stream_position(Stream, Pos), ( at_end_of_stream(Stream) -> Xs0 = [] - ; get_n_chars(Stream, 4096, Cs), + ; chars_to_read(CharsToRead), + get_n_chars(Stream, CharsToRead, Cs), partial_string(Cs, Xs0, Xs), stream_to_lazy_list_repositionable(Stream, Xs) ). @@ -96,7 +100,8 @@ render_step_buffer(Stream, Pos, Ls) :- set_stream_buffer_position(Stream, Pos), ( buffer_at_end_of_stream(Stream) -> Ls = [] - ; buffer_get_n_chars(Stream, 4096, Chars), + ; chars_to_read(CharsToRead), + buffer_get_n_chars(Stream, CharsToRead, Chars), partial_string(Chars, Ls, Ls0), stream_to_lazy_list_buffer(Stream, Ls0) ). @@ -143,7 +148,8 @@ buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N) :- ( at_end_of_stream(Stream) -> BufferTail = [], bb_put(BufferId, Buffer) - ; get_n_chars(Stream, 4096, Chars), + ; chars_to_read(CharsToRead), + get_n_chars(Stream, CharsToRead, Chars), length(Chars, NChars), partial_string(Chars, BufferTail, _), bb_put(BufferId, Buffer), @@ -163,13 +169,16 @@ partial_string_last_tail(PartialString, PartialStringTail) :- ; partial_string_last_tail(PartialStringTail0, PartialStringTail) ). -string_get_n_chars([], _, _, []). -string_get_n_chars([S|Ss], BufferPos, N, Chars) :- - ( BufferPos = 0 -> - string_get_n_chars_([S|Ss], N, Chars) - ; BufferPos1 is BufferPos - 1, - string_get_n_chars(Ss, BufferPos1, N, Chars) - ). +string_get_n_chars(String, Pos, N, Chars) :- + chars_to_read(CharsToRead), + ( CharsToRead < Pos -> + % I have absolutely no idea why this is needed (maybe it's a bug?), + % but hey, it works. + '$skip_max_list'(_, Pos, String, String0), + '$skip_max_list'(_, CharsToRead, String0, String1) + ; '$skip_max_list'(_, Pos, String, String1) + ), + string_get_n_chars_(String1, N, Chars). string_get_n_chars_([], _, []). string_get_n_chars_([S|Ss], N, Chars) :- From 2fe79b5fc3343b6245bf4dde1dec748bfe3ef997 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sun, 24 Sep 2023 15:07:39 -0300 Subject: [PATCH 20/60] Fixed bug with '$skip_max_list'/4 --- src/lib/pio.pl | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 8688e1c9..b6fe7786 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -170,14 +170,7 @@ partial_string_last_tail(PartialString, PartialStringTail) :- ). string_get_n_chars(String, Pos, N, Chars) :- - chars_to_read(CharsToRead), - ( CharsToRead < Pos -> - % I have absolutely no idea why this is needed (maybe it's a bug?), - % but hey, it works. - '$skip_max_list'(_, Pos, String, String0), - '$skip_max_list'(_, CharsToRead, String0, String1) - ; '$skip_max_list'(_, Pos, String, String1) - ), + '$skip_max_list'(_, Pos, String, String1), string_get_n_chars_(String1, N, Chars). string_get_n_chars_([], _, []). From c50291cec8e462061bea65c98f5bce1fafe803d9 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sun, 24 Sep 2023 19:21:03 -0300 Subject: [PATCH 21/60] Better string_get_n_chars_/3 --- src/lib/pio.pl | 46 +++++++++------------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index b6fe7786..24070d73 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -22,7 +22,7 @@ :- use_module(library(iso_ext), [ bb_get/2, bb_put/2, setup_call_cleanup/3, partial_string/3, partial_string_tail/2 ]). -:- use_module(library(lists), [length/2, member/2, maplist/2]). +:- use_module(library(lists), [append/3, length/2, member/2, maplist/2]). :- use_module(library(charsio), [get_n_chars/3]). :- meta_predicate(phrase_from_file(2, ?)). @@ -71,39 +71,18 @@ phrase_from_file(NT, File, Options) :- % How many chars to read from stream and buffer in each step chars_to_read(4096). -stream_to_lazy_list(Stream, Xs) :- - stream_property(Stream, reposition(Rep)), - ( Rep = true -> - stream_to_lazy_list_repositionable(Stream, Xs) - ; stream_to_lazy_list_buffer(Stream, Xs) - ). - -stream_to_lazy_list_repositionable(Stream, Xs) :- - stream_property(Stream, position(Pos)), - freeze(Xs, reader_step_repositionable(Stream, Pos, Xs)). - -reader_step_repositionable(Stream, Pos, Xs0) :- - set_stream_position(Stream, Pos), - ( at_end_of_stream(Stream) - -> Xs0 = [] - ; chars_to_read(CharsToRead), - get_n_chars(Stream, CharsToRead, Cs), - partial_string(Cs, Xs0, Xs), - stream_to_lazy_list_repositionable(Stream, Xs) - ). - -stream_to_lazy_list_buffer(Stream, Ls) :- +stream_to_lazy_list(Stream, Ls) :- get_stream_buffer_position(Stream, Pos), - freeze(Ls, render_step_buffer(Stream, Pos, Ls)). + freeze(Ls, render_step(Stream, Pos, Ls)). -render_step_buffer(Stream, Pos, Ls) :- +render_step(Stream, Pos, Ls) :- set_stream_buffer_position(Stream, Pos), ( buffer_at_end_of_stream(Stream) -> Ls = [] ; chars_to_read(CharsToRead), buffer_get_n_chars(Stream, CharsToRead, Chars), partial_string(Chars, Ls, Ls0), - stream_to_lazy_list_buffer(Stream, Ls0) + stream_to_lazy_list(Stream, Ls1) ). buffer_at_end_of_stream(Stream) :- @@ -173,17 +152,10 @@ string_get_n_chars(String, Pos, N, Chars) :- '$skip_max_list'(_, Pos, String, String1), string_get_n_chars_(String1, N, Chars). -string_get_n_chars_([], _, []). -string_get_n_chars_([S|Ss], N, Chars) :- - ( N = 0 -> - Chars = [] - ; N = 1 -> - % This case is needed to not break the tail of the partial string - Chars = [S] - ; Chars = [S|Cs], - N1 is N - 1, - string_get_n_chars_(Ss, N1, Cs) - ). +string_get_n_chars_(String, N, Chars) :- + '$skip_max_list'(N1, N, String, _), + length(Chars, N1), + append(Chars, _, String). stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId) :- ( bb_get(streams_buffers, _) -> From 63bb993c02c372a243f07c9815c0ba111009fa3b Mon Sep 17 00:00:00 2001 From: bakaq Date: Sun, 24 Sep 2023 19:29:51 -0300 Subject: [PATCH 22/60] Inline string_get_n_chars_/3 --- src/lib/pio.pl | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 24070d73..1576ec9a 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -82,7 +82,7 @@ render_step(Stream, Pos, Ls) :- ; chars_to_read(CharsToRead), buffer_get_n_chars(Stream, CharsToRead, Chars), partial_string(Chars, Ls, Ls0), - stream_to_lazy_list(Stream, Ls1) + stream_to_lazy_list(Stream, Ls0) ). buffer_at_end_of_stream(Stream) :- @@ -150,12 +150,9 @@ partial_string_last_tail(PartialString, PartialStringTail) :- string_get_n_chars(String, Pos, N, Chars) :- '$skip_max_list'(_, Pos, String, String1), - string_get_n_chars_(String1, N, Chars). - -string_get_n_chars_(String, N, Chars) :- - '$skip_max_list'(N1, N, String, _), + '$skip_max_list'(N1, N, String1, _), length(Chars, N1), - append(Chars, _, String). + append(Chars, _, String1). stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId) :- ( bb_get(streams_buffers, _) -> From f644a76281557085b61bc81965955f8e441e9e5c Mon Sep 17 00:00:00 2001 From: bakaq Date: Mon, 25 Sep 2023 02:18:05 -0300 Subject: [PATCH 23/60] Remove reposition option from phrase_from_file/2 --- src/lib/pio.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 1576ec9a..f13c9b85 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -63,9 +63,11 @@ phrase_from_file(NT, File, Options) :- member(Type, [text,binary]) ; Type = text ), - setup_call_cleanup(open(File, read, Stream, [reposition(true)|Options]), - phrase_from_stream(NT, Stream), - close(Stream)) + setup_call_cleanup( + open(File, read, Stream, Options), + phrase_from_stream(NT, Stream), + close(Stream) + ) ). % How many chars to read from stream and buffer in each step From c04f1dea481617c059d8012923bb4f7b83b2924f Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 23 Sep 2023 18:32:32 -0600 Subject: [PATCH 24/60] fix off-by-1 bug in '$skip_max_list'/4 (#2037) --- src/machine/system_calls.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 9e2d9760..4a54ad91 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -180,12 +180,6 @@ impl BrentAlgState { } pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { - /* - if let Some(var) = heap[self.hare].as_var() { - return CycleSearchResult::PartialList(self.num_steps(), var); - } - */ - loop { read_heap_cell!(heap[self.hare], (HeapCellValueTag::PStrOffset) => { @@ -248,7 +242,7 @@ impl BrentAlgState { let cstr = PartialString::from(cstr_atom); let num_chars = cstr.as_str_from(offset).chars().count(); - if self.max_steps == -1 || self.num_steps() + num_chars < self.max_steps as usize { + if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { self.pstr_chars += num_chars; Some(CycleSearchResult::ProperList(self.num_steps())) } else { @@ -261,7 +255,7 @@ impl BrentAlgState { let pstr = PartialString::from(pstr_atom); let num_chars = pstr.as_str_from(offset).chars().count(); - if self.max_steps == -1 || self.num_steps() + num_chars < self.max_steps as usize { + if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { self.pstr_chars += num_chars - 1; self.step(h+1) } else { From 280ff8b5d08ae398c946fc123af11315c00a1e77 Mon Sep 17 00:00:00 2001 From: Mark Date: Mon, 25 Sep 2023 19:20:11 -0600 Subject: [PATCH 25/60] throw an error instead of allowing builtin modules to be overwritten (#2042) --- src/machine/load_state.rs | 20 +++++++++++++++++--- src/machine/loader.rs | 23 ++++++++++++++++++----- src/machine/machine_errors.rs | 32 ++++++++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index fd857f3d..308ddf4c 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -9,7 +9,7 @@ use crate::parser::ast::*; use fxhash::FxBuildHasher; use indexmap::IndexSet; -use ref_thread_local::RefThreadLocal; +pub use ref_thread_local::RefThreadLocal; use std::collections::VecDeque; use std::fs::File; @@ -1004,10 +1004,22 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } - pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { - self.reset_in_situ_module(module_decl.clone(), &listing_src); + pub(crate) fn add_module( + &mut self, + module_decl: ModuleDecl, + listing_src: ListingSource, + ) -> Result<(), SessionError> { let module_name = module_decl.name; + if let Some(module) = self.wam_prelude.indices.modules.get(&module_name) { + if let ListingSource::DynamicallyGenerated = module.listing_src { + } else { + LS::err_on_builtin_module_overwrite(module_name)?; + } + } + + self.reset_in_situ_module(module_decl.clone(), &listing_src); + let mut module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(mut module) => { module.listing_src = listing_src; @@ -1045,6 +1057,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } self.wam_prelude.indices.modules.insert(module_name, module); + + Ok(()) } pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> { diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 59db0208..467bfb80 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -265,6 +265,10 @@ pub trait LoadState<'a>: Sized { loader: &Loader<'a, Self>, key: PredicateKey, ) -> Result<(), SessionError>; + + fn err_on_builtin_module_overwrite(_module_name: Atom) -> Result<(), SessionError> { + Ok(()) + } } pub struct LiveLoadAndMachineState<'a> { @@ -353,6 +357,15 @@ impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> { Ok(()) } + + #[inline] + fn err_on_builtin_module_overwrite(module_name: Atom) -> Result<(), SessionError> { + if LIBRARIES.borrow().contains_key(&*module_name.as_str()) { + Err(SessionError::CannotOverwriteBuiltInModule(module_name)) + } else { + Ok(()) + } + } } impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { @@ -533,11 +546,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { self.add_meta_predicate_record(module_name, name, meta_specs); } Declaration::Module(module_decl) => { - self.payload.compilation_target = CompilationTarget::Module(module_decl.name); + let module_name = module_decl.name; + + self.payload.compilation_target = CompilationTarget::Module(module_name); self.payload.predicates.compilation_target = self.payload.compilation_target; let listing_src = self.payload.term_stream.listing_src().clone(); - self.add_module(module_decl, listing_src); + self.add_module(module_decl, listing_src)?; } Declaration::NonCountedBacktracking(name, arity) => { self.payload.non_counted_bt_preds.insert((name, arity)); @@ -1849,9 +1864,7 @@ impl Machine { 2, )?; - let path = cell_as_atom!(self - .machine_st - .store(self.machine_st.deref(self.machine_st.registers[2]))); + let path = cell_as_atom!(self.deref_register(2)); self.load_contexts .push(LoadContext::new(&*path.as_str(), stream)); diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 5b4e4479..b80620a9 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -161,6 +161,26 @@ pub(crate) trait PermissionError { ) -> MachineError; } +impl PermissionError for Atom { + fn permission_error( + self, + _machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError { + let stub = functor!( + atom!("permission_error"), + [atom(perm.as_atom()), atom(index_atom), cell(atom_as_cell!(self))] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Received, + } + } +} + impl PermissionError for HeapCellValue { fn permission_error( self, @@ -459,7 +479,6 @@ impl MachineState { pub(super) fn session_error(&mut self, err: SessionError) -> MachineError { match err { SessionError::CannotOverwriteBuiltIn(key) => { - // SessionError::CannotOverwriteImport(pred_atom) => { self.permission_error( Permission::Modify, atom!("static_procedure"), @@ -468,10 +487,14 @@ impl MachineState { .collect::(), ) } + SessionError::CannotOverwriteBuiltInModule(module) => { + self.permission_error( + Permission::Modify, + atom!("static_module"), + module, + ) + } SessionError::ExistenceError(err) => self.existence_error(err), - // SessionError::InvalidFileName(filename) => { - // Self::existence_error(h, ExistenceError::Module(filename)) - // } SessionError::ModuleDoesNotContainExport(..) => { let error_atom = atom!("module_does_not_contain_claimed_export"); @@ -977,6 +1000,7 @@ pub enum ExistenceError { pub enum SessionError { CompilationError(CompilationError), CannotOverwriteBuiltIn(PredicateKey), + CannotOverwriteBuiltInModule(Atom), ExistenceError(ExistenceError), ModuleDoesNotContainExport(Atom, PredicateKey), ModuleCannotImportSelf(Atom), From e8334f9b67505baea12ac8482bbaf9ac9dc8dee3 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Sep 2023 11:21:47 -0600 Subject: [PATCH 26/60] add predicate indicator sequences to loader:add_predicate_declaration (#1586) --- src/loader.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/loader.pl b/src/loader.pl index cf72820e..da37c17c 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -393,6 +393,9 @@ add_predicate_declaration(Handler, Module:Name/Arity) :- call(Handler, Module, Name, Arity). add_predicate_declaration(Handler, [PI|PIs]) :- maplist(loader:add_predicate_declaration(Handler), [PI|PIs]). +add_predicate_declaration(Handler, (PI, PIs)) :- + add_predicate_declaration(Handler, PI), + add_predicate_declaration(Handler, PIs). add_dynamic_predicate(Evacuable, Module, Name, Arity) :- '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). From 193bb313fd2785e852eeed85f9ad2c3c8ea406ff Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Sep 2023 11:22:56 -0600 Subject: [PATCH 27/60] correct OutOfFiles resource error (#1375) --- src/machine/machine_errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index b80620a9..971ef8e4 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -320,8 +320,8 @@ impl MachineState { } ResourceError::OutOfFiles => { functor!( - atom!("resource_atom"), - [atom(atom!("out_of_files"))] + atom!("resource_error"), + [atom(atom!("file_descriptors"))] ) } }; From 39934208c3d9a327c23917a10760ff242e0b3c1b Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Sep 2023 12:08:51 -0600 Subject: [PATCH 28/60] throw instantiation_error when appropriate from parse_write_options_ (5.5.12 of the standard, #1965) --- src/lib/builtins.pl | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index a1c913bd..4a0984a4 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -574,26 +574,30 @@ parse_write_options(Options, OptionValues, Stub) :- parse_write_options_(double_quotes(DoubleQuotes), double_quotes-DoubleQuotes) :- - ( nonvar(DoubleQuotes), - lists:member(DoubleQuotes, [true, false]), + ( var(DoubleQuotes) -> + throw(error(instantiation_error, _)) + ; lists:member(DoubleQuotes, [true, false]), ! ; throw(error(domain_error(write_option, double_quotes(DoubleQuotes)), _)) ). parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :- - ( nonvar(IgnoreOps), - lists:member(IgnoreOps, [true, false]), + ( var(IgnoreOps) -> + throw(error(instantiation_error, _)) + ; lists:member(IgnoreOps, [true, false]), ! ; throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _)) ). parse_write_options_(quoted(Quoted), quoted-Quoted) :- - ( nonvar(Quoted), - lists:member(Quoted, [true, false]), + ( var(Quoted) -> + throw(error(instantiation_error, _)) + ; lists:member(Quoted, [true, false]), ! ; throw(error(domain_error(write_option, quoted(Quoted)), _)) ). parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :- - ( nonvar(NumberVars), - lists:member(NumberVars, [true, false]), + ( var(NumberVars) -> + throw(error(instantiation_error, _)) + ; lists:member(NumberVars, [true, false]), ! ; throw(error(domain_error(write_option, numbervars(NumberVars)), _)) ). @@ -601,7 +605,9 @@ parse_write_options_(variable_names(VNNames), variable_names-VNNames) :- must_be_var_names_list(VNNames), !. parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :- - ( integer(MaxDepth), + ( var(MaxDepth) -> + throw(error(instantiation_error, _)) + ; integer(MaxDepth), MaxDepth >= 0, ! ; throw(error(domain_error(write_option, max_depth(MaxDepth)), _)) From 56992570d829566589babfb38844c28525d6ebdf Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Sep 2023 12:54:16 -0600 Subject: [PATCH 29/60] check for predicate_indicator list and sequence types in add_predicate_declaration (#1586) --- src/loader.pl | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index da37c17c..513caafd 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -379,23 +379,50 @@ remove_module(Module, Evacuable) :- ; domain_error(module_specifier, Module, use_module/2) ). + +predicate_indicator(PI) :- + ( var(PI) -> + throw(error(instantiation_error, _)) + ; PI = Name/Arity, + must_be(atom, Name), + must_be(integer, Arity), + Arity >= 0 + ). + +predicate_indicator_sequence(PI_Seq) :- + ( var(PI_Seq) -> + throw(error(instantiation_error, load/1)) + ; PI_Seq = (PI, PIs), + predicate_indicator(PI), + ( predicate_indicator(PIs) -> + true + ; predicate_indicator_sequence(PIs) + ) + ). + :- meta_predicate add_predicate_declaration(3, ?). add_predicate_declaration(Handler, Name/Arity) :- - must_be(atom, Name), - must_be(integer, Arity), + predicate_indicator(Name/Arity), prolog_load_context(module, Module), call(Handler, Module, Name, Arity). add_predicate_declaration(Handler, Module:Name/Arity) :- must_be(atom, Module), - must_be(atom, Name), - must_be(integer, Arity), + predicate_indicator(Name/Arity), call(Handler, Module, Name, Arity). add_predicate_declaration(Handler, [PI|PIs]) :- - maplist(loader:add_predicate_declaration(Handler), [PI|PIs]). + '$skip_max_list'(_, -1, PIs, Tail), + ( Tail == [], + maplist(loader:predicate_indicator, PIs) -> + maplist(loader:add_predicate_declaration(Handler), [PI|PIs]) + ; throw(error(type_error(predicate_indicator_list, [PI|PIs]), load/1)) + ). add_predicate_declaration(Handler, (PI, PIs)) :- - add_predicate_declaration(Handler, PI), - add_predicate_declaration(Handler, PIs). + ( predicate_indicator_sequence((PI, PIs)) -> + add_predicate_declaration(Handler, PI), + add_predicate_declaration(Handler, PIs) + ; throw(error(type_error(predicate_indicator_sequence, (PI, PIs)), load/1)) + ). add_dynamic_predicate(Evacuable, Module, Name, Arity) :- '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). From 2efe95f2fb84427bd827d5b84df8bb5230e5b848 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Sep 2023 13:46:21 -0600 Subject: [PATCH 30/60] filter our builtins from current_predicate/1 (#153) --- src/machine/system_calls.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 4a54ad91..34b26808 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3908,6 +3908,11 @@ impl Machine { } ); + if self.indices.builtin_property((name, arity)) { + self.machine_st.fail = true; + return; + } + self.machine_st.fail = self .indices .get_predicate_code_index(name, arity, module_name) @@ -3987,6 +3992,10 @@ impl Machine { }; for (name, arity) in code_dir.keys() { + if self.indices.builtin_property((*name, *arity)) { + continue; + } + if name_match(pred_atom, *name) && arity_match(pred_arity, *arity) { self.machine_st.heap.extend(functor!( atom!("/"), From a6535c28ea13bb2717fb30c0c1584a0a0bfa1454 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 26 Sep 2023 14:06:21 -0600 Subject: [PATCH 31/60] remove module_resolution_error (#2035) --- src/machine/machine_errors.rs | 35 +++++++++++++++-------------------- src/machine/mod.rs | 4 ++-- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 971ef8e4..9a9d6cbf 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -341,26 +341,6 @@ impl MachineState { culprit.type_error(self, valid_type) } - pub(super) fn module_resolution_error( - &mut self, - mod_name: Atom, - name: Atom, - arity: usize, - ) -> MachineError { - let h = self.heap.len(); - - let res_stub = functor!(atom!(":"), [atom(mod_name), atom(name)]); - let ind_stub = functor!(atom!("/"), [str(h + 2, 0), fixnum(arity)], [res_stub]); - - let stub = functor!(atom!("evaluation_error"), [str(h, 0)], [ind_stub]); - - MachineError { - stub, - location: None, - from: ErrorProvenance::Constructed, - } - } - pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError { match err { ExistenceError::Module(name) => { @@ -375,6 +355,20 @@ impl MachineState { from: ErrorProvenance::Received, } } + ExistenceError::QualifiedProcedure { module_name, name, arity } => { + let h = self.heap.len(); + + let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]); + let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]); + + let stub = functor!(atom!("existence_error"), [atom(atom!("procedure")), str(h, 0)], [res_stub]); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Constructed, + } + } ExistenceError::Procedure(name, arity) => { let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]); @@ -992,6 +986,7 @@ pub enum ExistenceError { Module(Atom), ModuleSource(ModuleSource), Procedure(Atom, usize), + QualifiedProcedure { module_name: Atom, name: Atom, arity: usize }, SourceSink(HeapCellValue), Stream(HeapCellValue), } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 0018610e..665366c3 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1167,7 +1167,7 @@ impl Machine { let stub = functor_stub(name, arity); let err = self .machine_st - .module_resolution_error(module_name, name, arity); + .existence_error(ExistenceError::QualifiedProcedure { module_name, name, arity }); Err(self.machine_st.error_form(err, stub)) } @@ -1195,7 +1195,7 @@ impl Machine { let stub = functor_stub(name, arity); let err = self .machine_st - .module_resolution_error(module_name, name, arity); + .existence_error(ExistenceError::QualifiedProcedure { module_name, name, arity }); Err(self.machine_st.error_form(err, stub)) } From 4163437d5ac561e1efbc27ac36101b36be6e1838 Mon Sep 17 00:00:00 2001 From: infogulch Date: Wed, 27 Sep 2023 00:31:08 -0500 Subject: [PATCH 32/60] Add ubuntu 22.04 --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 786defb1..e94e8107 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,10 @@ jobs: include: - { os: windows-latest, rust-version: stable, shell: 'msys2 {0}', target: 'x86_64-pc-windows-gnu'} - { os: macos-11, rust-version: stable, shell: bash, target: 'x86_64-apple-darwin' } - - { os: ubuntu-20.04, rust-version: stable, shell: bash, extra: true, target: 'x86_64-unknown-linux-gnu' } + - { os: ubuntu-22.04, rust-version: stable, shell: bash, target: 'x86_64-unknown-linux-gnu' } + - { os: ubuntu-20.04, rust-version: stable, shell: bash, target: 'x86_64-unknown-linux-gnu', extra: true } - { os: ubuntu-20.04, rust-version: stable, shell: bash, target: 'i686-unknown-linux-gnu' } - - { os: ubuntu-20.04, rust-version: "1.70", shell: bash, target: 'x86_64-unknown-linux-gnu'} + - { os: ubuntu-20.04, rust-version: "1.70", shell: bash, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-20.04, rust-version: beta, shell: bash, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-20.04, rust-version: nightly, shell: bash, target: 'x86_64-unknown-linux-gnu'} defaults: @@ -175,6 +176,7 @@ jobs: run: | zip scryer-prolog_macos-11.zip ./scryer-prolog_macos-11_x86_64-apple-darwin/scryer-prolog zip scryer-prolog_ubuntu-20.04.zip ./scryer-prolog_ubuntu-20.04_x86_64-unknown-linux-gnu/scryer-prolog + zip scryer-prolog_ubuntu-22.04.zip ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/scryer-prolog zip scryer-prolog_windows-latest.zip ./scryer-prolog_windows-latest_x86_64-pc-windows-gnu/scryer-prolog.exe zip -r scryer-prolog_unknown-wasm32.zip ./scryer-prolog_unknown_wasm32 - name: Release @@ -183,5 +185,6 @@ jobs: files: | scryer-prolog_macos-11.zip scryer-prolog_ubuntu-20.04.zip + scryer-prolog_ubuntu-22.04.zip scryer-prolog_windows-latest.zip scryer-prolog_unknown-wasm32.zip From a86db1bde8cc912ebc8c929a926ff483b1e5e696 Mon Sep 17 00:00:00 2001 From: infogulch Date: Wed, 27 Sep 2023 02:57:02 -0500 Subject: [PATCH 33/60] Build windows with msvc --- .github/workflows/ci.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e94e8107..91b91b48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: include: - - { os: windows-latest, rust-version: stable, shell: 'msys2 {0}', target: 'x86_64-pc-windows-gnu'} + - { os: windows-latest, rust-version: stable, shell: bash, target: 'x86_64-pc-windows-msvc'} - { os: macos-11, rust-version: stable, shell: bash, target: 'x86_64-apple-darwin' } - { os: ubuntu-22.04, rust-version: stable, shell: bash, target: 'x86_64-unknown-linux-gnu' } - { os: ubuntu-20.04, rust-version: stable, shell: bash, target: 'x86_64-unknown-linux-gnu', extra: true } @@ -31,7 +31,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master - if: "!contains(matrix.os,'windows')" id: toolchain with: toolchain: ${{ matrix.rust-version }} @@ -40,13 +39,6 @@ jobs: - name: Install i686 dependencies if: "contains(matrix.target,'i686')" run: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install libssl-dev:i386 gcc-multilib clang -y && echo "CC=clang" >> $GITHUB_ENV && echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV - - uses: msys2/setup-msys2@v2 - if: contains(matrix.os,'windows') - with: - update: true - install: >- - base-devel - mingw-w64-x86_64-rust - uses: actions/cache@v3 with: path: | @@ -177,7 +169,7 @@ jobs: zip scryer-prolog_macos-11.zip ./scryer-prolog_macos-11_x86_64-apple-darwin/scryer-prolog zip scryer-prolog_ubuntu-20.04.zip ./scryer-prolog_ubuntu-20.04_x86_64-unknown-linux-gnu/scryer-prolog zip scryer-prolog_ubuntu-22.04.zip ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/scryer-prolog - zip scryer-prolog_windows-latest.zip ./scryer-prolog_windows-latest_x86_64-pc-windows-gnu/scryer-prolog.exe + zip scryer-prolog_windows-latest.zip ./scryer-prolog_windows-latest_x86_64-pc-windows-msvc/scryer-prolog.exe zip -r scryer-prolog_unknown-wasm32.zip ./scryer-prolog_unknown_wasm32 - name: Release uses: softprops/action-gh-release@v1 From 93f46a41420ba317f31bf72c83d138bbc410bc5f Mon Sep 17 00:00:00 2001 From: infogulch Date: Wed, 27 Sep 2023 02:58:48 -0500 Subject: [PATCH 34/60] Tidy ci.yaml --- .github/workflows/ci.yml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91b91b48..27b4e9d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,17 +17,17 @@ jobs: fail-fast: false matrix: include: - - { os: windows-latest, rust-version: stable, shell: bash, target: 'x86_64-pc-windows-msvc'} - - { os: macos-11, rust-version: stable, shell: bash, target: 'x86_64-apple-darwin' } - - { os: ubuntu-22.04, rust-version: stable, shell: bash, target: 'x86_64-unknown-linux-gnu' } - - { os: ubuntu-20.04, rust-version: stable, shell: bash, target: 'x86_64-unknown-linux-gnu', extra: true } - - { os: ubuntu-20.04, rust-version: stable, shell: bash, target: 'i686-unknown-linux-gnu' } - - { os: ubuntu-20.04, rust-version: "1.70", shell: bash, target: 'x86_64-unknown-linux-gnu'} - - { os: ubuntu-20.04, rust-version: beta, shell: bash, target: 'x86_64-unknown-linux-gnu'} - - { os: ubuntu-20.04, rust-version: nightly, shell: bash, target: 'x86_64-unknown-linux-gnu'} + - { os: windows-latest, rust-version: stable, target: 'x86_64-pc-windows-msvc'} + - { os: macos-11, rust-version: stable, target: 'x86_64-apple-darwin' } + - { os: ubuntu-22.04, rust-version: stable, target: 'x86_64-unknown-linux-gnu' } + - { os: ubuntu-20.04, rust-version: stable, target: 'x86_64-unknown-linux-gnu', extra: true } + - { os: ubuntu-20.04, rust-version: stable, target: 'i686-unknown-linux-gnu' } + - { os: ubuntu-20.04, rust-version: "1.70", target: 'x86_64-unknown-linux-gnu'} + - { os: ubuntu-20.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'} + - { os: ubuntu-20.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu'} defaults: run: - shell: ${{ matrix.shell }} + shell: bash steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@master @@ -38,7 +38,12 @@ jobs: components: clippy, rustfmt - name: Install i686 dependencies if: "contains(matrix.target,'i686')" - run: sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install libssl-dev:i386 gcc-multilib clang -y && echo "CC=clang" >> $GITHUB_ENV && echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install libssl-dev:i386 gcc-multilib clang -y + echo "CC=clang" >> $GITHUB_ENV + echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV - uses: actions/cache@v3 with: path: | From 660860bccf1b000a8ba707a37579956deb1c208f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Arroyo=20Calle?= Date: Tue, 5 Sep 2023 20:40:58 +0200 Subject: [PATCH 35/60] Replace Hyper with Warp for HTTP server - Use Warp - Optimize clones - HTTPS server - Content-Length limit - HTTP Basic Auth - Stop server with Ctrl-C --- Cargo.lock | 476 +++++++++++++++++++++++---------- Cargo.toml | 5 +- README.md | 2 +- build/instructions_template.rs | 2 +- src/http.rs | 56 +--- src/lib/http/http_server.pl | 105 +++++++- src/machine/dispatch.rs | 11 + src/machine/streams.rs | 67 +++-- src/machine/system_calls.rs | 297 ++++++++++++-------- 9 files changed, 682 insertions(+), 339 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c383d82e..e054b9db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,9 +81,15 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "base64" -version = "0.21.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bit-set" @@ -188,9 +194,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byte-tools" @@ -206,9 +212,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" @@ -227,17 +233,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", - "time", "wasm-bindgen", - "winapi", + "windows-targets", ] [[package]] @@ -365,19 +370,19 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" dependencies = [ - "nix", + "nix 0.27.1", "windows-sys", ] [[package]] name = "dashmap" -version = "5.5.1" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.0", @@ -551,9 +556,9 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -699,7 +704,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -769,7 +774,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -832,6 +837,30 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.4", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.3.3" @@ -843,9 +872,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" @@ -903,29 +932,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-body" -version = "1.0.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951dfc2e32ac02d67c90c0d65bd27009a635dc9b381a2cc7d284ab01e3a0150d" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08ef12f041acdd397010e5fb6433270c147d3b8b2d0a840cd7fff8e531dca5c8" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body 1.0.0-rc.2", - "pin-project-lite", -] - [[package]] name = "httparse" version = "1.8.0" @@ -950,7 +956,7 @@ dependencies = [ "futures-util", "h2", "http", - "http-body 0.4.5", + "http-body", "httparse", "httpdate", "itoa", @@ -962,28 +968,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper" -version = "1.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75264b2003a3913f118d35c586e535293b3e22e41f074930762929d071e092" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body 1.0.0-rc.2", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "tokio", - "tracing", - "want", -] - [[package]] name = "hyper-tls" version = "0.5.0" @@ -991,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.27", + "hyper", "native-tls", "tokio", "tokio-native-tls", @@ -1119,9 +1103,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libffi" @@ -1154,9 +1138,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" [[package]] name = "lock_api" @@ -1214,9 +1198,9 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "mime" @@ -1224,6 +1208,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1253,7 +1247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys", ] @@ -1285,6 +1279,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + [[package]] name = "native-tls" version = "0.2.11" @@ -1320,9 +1332,20 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abbbc55ad7b13aac85f9401c796dcda1b864e07fcad40ad47792eaa8932ea502" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ "bitflags 2.4.0", "cfg-if", @@ -1374,9 +1397,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1416,7 +1439,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -1427,9 +1450,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.92" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7e971c2c2bba161b2d2fdf37080177eff520b3bc044787c7f1f5f9e78d869b" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -1582,6 +1605,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -1647,9 +1690,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -1756,15 +1799,15 @@ version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.3", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", "http", - "http-body 0.4.5", - "hyper 0.14.27", + "http-body", + "hyper", "hyper-tls", "ipnet", "js-sys", @@ -1796,7 +1839,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -1812,7 +1855,7 @@ dependencies = [ "getrandom", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -1846,9 +1889,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.9" +version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ "bitflags 2.4.0", "errno", @@ -1857,6 +1900,27 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64 0.21.4", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -1877,7 +1941,7 @@ dependencies = [ "libc", "log", "memchr", - "nix", + "nix 0.26.4", "radix_trie", "scopeguard", "unicode-segmentation", @@ -1910,6 +1974,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -1942,8 +2012,6 @@ dependencies = [ "getrandom", "git-version", "hostname", - "http-body-util", - "hyper 1.0.0-rc.3", "indexmap", "lazy_static", "lexical", @@ -1975,16 +2043,27 @@ dependencies = [ "static_assertions", "strum", "strum_macros", - "syn 2.0.32", + "syn 2.0.37", "to-syn-value", "to-syn-value_derive", "tokio", "walkdir", + "warp", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", ] +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -2047,14 +2126,14 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", @@ -2095,7 +2174,18 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", ] [[package]] @@ -2179,9 +2269,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "socket2" @@ -2195,9 +2285,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", "windows-sys", @@ -2209,6 +2299,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "static_assertions" version = "1.1.0" @@ -2291,9 +2387,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -2338,33 +2434,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "syn 2.0.37", ] [[package]] @@ -2388,7 +2473,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfcc684f2ceaec3b4e8689657c9e0944b07bf5e34563e0bd758c4d42c05c82ed" dependencies = [ - "syn 2.0.32", + "syn 2.0.37", "to-syn-value_derive", ] @@ -2400,7 +2485,7 @@ checksum = "3dfffda778de8443144ff3b042ddf14e8bc5445f0fd9fe937c3d252535dc9212" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -2417,7 +2502,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.4", "tokio-macros", "windows-sys", ] @@ -2430,7 +2515,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", ] [[package]] @@ -2444,10 +2529,44 @@ dependencies = [ ] [[package]] -name = "tokio-util" -version = "0.7.8" +name = "tokio-rustls" +version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -2470,6 +2589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", + "log", "pin-project-lite", "tracing-core", ] @@ -2490,10 +2610,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] -name = "typenum" -version = "1.16.0" +name = "tungstenite" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] [[package]] name = "unicode-bidi" @@ -2503,9 +2651,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2524,9 +2672,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "untrusted" @@ -2536,9 +2684,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -2580,9 +2728,9 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", @@ -2598,10 +2746,36 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +name = "warp" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "ba431ef570df1287f7f8b07e376491ad54f84d26ac473489427231e1718e1f69" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http", + "hyper", + "log", + "mime", + "mime_guess", + "multer", + "percent-encoding", + "pin-project", + "rustls-pemfile", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-tungstenite", + "tokio-util", + "tower-service", + "tracing", +] [[package]] name = "wasi" @@ -2630,7 +2804,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -2664,7 +2838,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2685,6 +2859,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2703,9 +2887,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 92b35ded..dbf7cfc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ ffi = ["dep:libffi"] repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"] hostname = ["dep:hostname"] tls = ["dep:native-tls"] -http = ["dep:hyper", "dep:reqwest"] +http = ["dep:warp", "dep:reqwest"] rust_beta_channel = [] crypto-full = [] @@ -66,7 +66,6 @@ ryu = "1.0.9" futures = "0.3" libloading = "0.7" derive_deref = "1.1.1" -http-body-util = "0.1.0-rc.2" bytes = "1" dashu = "0.4.0" num-order = { version = "1.2.0" } @@ -79,7 +78,7 @@ crossterm = { version = "0.20.0", optional = true } ctrlc = { version = "3.2.2", optional = true } rustyline = { version = "12.0.0", optional = true } native-tls = { version = "0.2.4", optional = true } -hyper = { version = "=1.0.0-rc.3", features = ["full"], optional = true } +warp = { version = "=0.3.5", features = ["tls"], optional = true } reqwest = { version = "0.11.18", features = ["blocking"], optional = true } tokio = { version = "1.28.2", features = ["full"] } diff --git a/README.md b/README.md index 4ba1f9d6..81236b65 100644 --- a/README.md +++ b/README.md @@ -624,7 +624,7 @@ The modules that ship with Scryer Prolog are also called Probabilistic predicates and random number generators. * [`http/http_open`](src/lib/http/http_open.pl) Open a stream to read answers from web servers. HTTPS is also supported. -* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Hyper](https://hyper.rs) as a backend. Supports some query and form handling. +* [`http/http_server`](src/lib/http/http_server.pl) Runs a HTTP/1.1 and HTTP/2.0 web server. Uses [Warp](https://github.com/seanmonstar/warp) as a backend. Supports some query and form handling. * [`sgml`](src/lib/sgml.pl) `load_html/3` and `load_xml/3` represent HTML and XML documents as Prolog terms for convenient and efficient reasoning. Use diff --git a/build/instructions_template.rs b/build/instructions_template.rs index f0a5a49f..894254c7 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -558,7 +558,7 @@ enum SystemClauseType { DeterministicLengthRundown, #[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))] HttpOpen, - #[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))] + #[strum_discriminants(strum(props(Arity = "5", Name = "$http_listen")))] HttpListen, #[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))] HttpAccept, diff --git a/src/http.rs b/src/http.rs index 13d6ff31..46888f12 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,55 +1,23 @@ -use bytes::Bytes; -use http_body_util::Full; -use hyper::service::Service; -use hyper::{body::Incoming as IncomingBody, Request, Response}; -use std::future::Future; -use std::pin::Pin; -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::{Arc, Mutex, Condvar}; +use std::io::BufRead; + +use warp::http; pub struct HttpListener { pub incoming: std::sync::mpsc::Receiver, } -#[derive(Debug)] pub struct HttpRequest { - pub request: Request, + pub request_data: HttpRequestData, pub response: HttpResponse, } -pub type HttpResponse = Arc<(Mutex, Mutex>>>, Condvar)>; +pub type HttpResponse = Arc<(Mutex, Mutex>, Condvar)>; -pub struct HttpService { - pub tx: std::sync::mpsc::SyncSender, -} - -impl Service> for HttpService { - type Response = Response>; - type Error = hyper::Error; - type Future = Pin> + Send>>; - - fn call(&mut self, req: Request) -> Self::Future { - // new connection! - // we send the Request info to Prolog - let response = Arc::new((Mutex::new(false), Mutex::new(None), Condvar::new())); - let http_request = HttpRequest { - request: req, - response: Arc::clone(&response), - }; - self.tx.send(http_request).unwrap(); - - // we wait for the Response info from Prolog - { - let (ready, _response, cvar) = &*response; - let mut ready = ready.lock().unwrap(); - while !*ready { - ready = cvar.wait(ready).unwrap(); - } - } - { - let (_, response, _) = &*response; - let response = response.lock().unwrap().take(); - let res = response.expect("Data race error in HTTP Server"); - Box::pin(async move { Ok(res) }) - } - } +pub struct HttpRequestData { + pub method: http::Method, + pub headers: http::HeaderMap, + pub path: String, + pub query: String, + pub body: Box, } diff --git a/src/lib/http/http_server.pl b/src/lib/http/http_server.pl index 381d5607..faa76ce5 100644 --- a/src/lib/http/http_server.pl +++ b/src/lib/http/http_server.pl @@ -6,8 +6,8 @@ */ /** This library provides an starting point to build HTTP server based applications. -It is based on [Hyper](https://hyper.rs/), which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However, -some advanced features that Hyper provides are still not accesible. +It is based on [Warp](https://github.com/seanmonstar/warp), which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However, +some advanced features that Warp provides are still not accesible. ## Usage @@ -46,7 +46,6 @@ recommeded to use the helper predicates, which are easier to understand and clea Some things that are still missing: - Read forms in multipart format - - HTTP Basic Auth - Session handling via cookies - HTML Templating (but you can use [Teruel](https://github.com/aarroyoc/teruel/), [Marquete](https://github.com/aarroyoc/marquete/) or [Djota](https://github.com/aarroyoc/djota) for that) */ @@ -54,14 +53,19 @@ Some things that are still missing: :- module(http_server, [ http_listen/2, + http_listen/3, http_headers/2, http_status_code/2, http_body/2, http_redirect/2, - http_query/3 + http_query/3, + http_basic_auth/4 ]). :- meta_predicate http_listen(?, :). +:- meta_predicate http_listen(?, :, ?). + +:- meta_predicate http_basic_auth(:, :, ?, ?). :- use_module(library(charsio)). :- use_module(library(crypto)). @@ -74,25 +78,58 @@ Some things that are still missing: %% http_listen(+Port, +Handlers). % -% Listens for HTTP connections on port Port. Each handler on the list Handlers should be of the form: `HttpVerb(PathUnification, Predicate)`. -% For example: `get(user/User, get_info(User))` will match an HTTP request that is a GET, the path unifies with /user/User (where User is a variable) -% and it will call `get_info` with three arguments: an `http_request` term, an `http_response` term and User. +% Equivalent to `http_listen(Port, Handlers, [])`. http_listen(Port, Module:Handlers0) :- must_be(integer, Port), must_be(list, Handlers0), maplist(module_qualification(Module), Handlers0, Handlers), - http_listen_(Port, Handlers). + http_listen_(Port, Handlers, []). + +%% http_listen(+Port, +Handlers, +Options). +% +% Listens for HTTP connections on port Port. Each handler on the list Handlers should be of the form: `HttpVerb(PathUnification, Predicate)`. +% For example: `get(user/User, get_info(User))` will match an HTTP request that is a GET, the path unifies with /user/User (where User is a variable) +% and it will call `get_info` with three arguments: an `http_request` term, an `http_response` term and User. +% +% The following options are supported: +% +% - `tls_key(+Key)` - a TLS key for HTTPS (string) +% - `tls_cert(+Cert)` - a TLS cert for HTTPS (string) +% - `content_length_limit(+Limit)` - maximum length (in bytes) for the incoming bodies. By default, 32KB. +% +% In order to have a HTTPS server (instead of plain HTTP), both `tls_key` and `tls_cert` options must be provided. +http_listen(Port, Module:Handlers0, Options) :- + must_be(integer, Port), + must_be(list, Handlers0), + must_be(list, Options), + maplist(module_qualification(Module), Handlers0, Handlers), + http_listen_(Port, Handlers, Options). module_qualification(M, H0, H) :- H0 =.. [Method, Path, Goal], H =.. [Method, Path, M:Goal]. -http_listen_(Port, Handlers) :- +http_listen_(Port, Handlers, Options) :- + parse_options(Options, TLSKey, TLSCert, ContentLengthLimit), phrase(format_("0.0.0.0:~d", [Port]), Addr), - '$http_listen'(Addr, HttpListener),!, + '$http_listen'(Addr, HttpListener, TLSKey, TLSCert, ContentLengthLimit),!, format("Listening at ~s\n", [Addr]), http_loop(HttpListener, Handlers). +parse_options(Options, TLSKey, TLSCert, ContentLengthLimit) :- + member_option_default(tls_key, Options, "", TLSKey), + member_option_default(tls_cert, Options, "", TLSCert), + member_option_default(content_length_limit, Options, 32768, ContentLengthLimit), + must_be(integer, ContentLengthLimit). + +member_option_default(Key, List, _Default, Value) :- + X =.. [Key, Value], + member(X, List). +member_option_default(Key, List, Default, Default) :- + X =.. [Key, _], + \+ member(X, List). + + http_loop(HttpListener, Handlers) :- '$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle), current_time(Time), @@ -114,7 +151,7 @@ http_loop(HttpListener, Handlers) :- ) ; ( '$http_answer'(ResponseHandle, 404, [], ResponseStream), - call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream))) + call_cleanup(format(ResponseStream, "Not Found", []), close(ResponseStream))) ), http_loop(HttpListener, Handlers). @@ -352,3 +389,49 @@ url_decode([Char|Chars]) --> url_decode(Chars). url_decode([]) --> []. + +%% http_basic_auth(+LoginPredicate, +Handler, +Request, -Response) +% +% Metapredicate that wraps an existing Handler with an HTTP Basic Auth flow. +% Checks if a given user + password is authorized to execute that handler, returning 401 +% if it's not satisfied. +% +% `LoginPredicate` must be a predicate of arity 2 that takes a User and a Password. +% `Handler` will have, in addition to the Request and Response arguments, a User argument +% containing the User given in the authentication. +% +% Example: +% +% ``` +% main :- +% http_listen(8800,[get('/', http_basic_auth(login, inside_handler("data")))]). +% +% login(User, Pass) :- +% User = "aarroyoc", +% Pass = "123456". +% +% inside_handler(Data, User, Request, Response) :- +% http_body(Response, text(User)). +% ``` +http_basic_auth(LoginPredicate, Handler, Request, Response) :- + http_headers(Request, Headers), + member("authorization"-AuthorizationStr, Headers), + append("Basic ", Coded, AuthorizationStr), + chars_base64(UserPass, Coded, []), + append(User, [':'|Password], UserPass), + ( + call(LoginPredicate, User, Password) -> + call(Handler, User, Request, Response) + ; http_basic_auth_unauthorized_response(Response) + ). + +http_basic_auth(_LoginPredicate, _Handler, Request, Response) :- + http_headers(Request, Headers), + \+ member("authorization"-_, Headers), + http_basic_auth_unauthorized_response(Response). + +http_basic_auth_unauthorized_response(Response) :- + http_status_code(Response, 401), + http_headers(Response, ["www-authenticate"-"Basic realm=\"Scryer Prolog\", charset=\"UTF-8\""]), + http_body(Response, text("Unauthorized")). + diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 89174091..1ac43189 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -5499,6 +5499,17 @@ impl Machine { if interruption { self.machine_st.throw_interrupt_exception(); self.machine_st.backtrack(); + + #[cfg(not(target_arch = "wasm32"))] + let runtime = tokio::runtime::Runtime::new().unwrap(); + #[cfg(target_arch = "wasm32")] + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + let old_runtime = std::mem::replace(&mut self.runtime, runtime); + old_runtime.shutdown_background(); } } Err(_) => unreachable!(), diff --git a/src/machine/streams.rs b/src/machine/streams.rs index b5632417..1dfbfaa9 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -30,6 +30,9 @@ use std::ptr; #[cfg(feature = "tls")] use native_tls::TlsStream; +#[cfg(feature = "http")] +use warp::hyper; + #[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] #[bits = 1] pub enum StreamType { @@ -290,9 +293,9 @@ impl Read for HttpReadStream { #[cfg(feature = "http")] pub struct HttpWriteStream { status_code: u16, - headers: hyper::HeaderMap, + headers: mem::ManuallyDrop, response: TypedArenaPtr, - buffer: Vec, + buffer: mem::ManuallyDrop>, } #[cfg(feature = "http")] @@ -312,24 +315,33 @@ impl Write for HttpWriteStream { #[inline] fn flush(&mut self) -> std::io::Result<()> { - let (ready, response, cvar) = &**self.response; - - let mut ready = ready.lock().unwrap(); - { - let mut response = response.lock().unwrap(); - - let bytes = bytes::Bytes::copy_from_slice(&self.buffer); - let mut response_ = hyper::Response::builder().status(self.status_code); - *response_.headers_mut().unwrap() = self.headers.clone(); - *response = Some(response_.body(http_body_util::Full::new(bytes)).unwrap()); - } - *ready = true; - cvar.notify_one(); - - Ok(()) + Ok(()) } } +#[cfg(feature = "http")] +impl HttpWriteStream { + fn drop(&mut self) { + let headers = unsafe { mem::ManuallyDrop::take(&mut self.headers) }; + let buffer = unsafe { mem::ManuallyDrop::take(&mut self.buffer) }; + + let (ready, response, cvar) = &**self.response; + + let mut ready = ready.lock().unwrap(); + { + let mut response = response.lock().unwrap(); + + let mut response_ = warp::http::Response::builder() + .status(self.status_code); + *response_.headers_mut().unwrap() = headers; + *response = Some(response_.body(warp::hyper::Body::from(buffer)).unwrap()); + } + *ready = true; + cvar.notify_one(); + } +} + + #[derive(Debug)] pub struct StandardOutputStream {} @@ -1243,15 +1255,15 @@ impl Stream { headers: hyper::HeaderMap, arena: &mut Arena, ) -> Self { - Stream::HttpWrite(arena_alloc!( - StreamLayout::new(CharReader::new(HttpWriteStream { - response, - status_code, - headers, - buffer: Vec::new(), - })), - arena - )) + Stream::HttpWrite(arena_alloc!( + StreamLayout::new(CharReader::new(HttpWriteStream { + response, + status_code, + headers: mem::ManuallyDrop::new(headers), + buffer: mem::ManuallyDrop::new(Vec::new()), + })), + arena + )) } #[inline] @@ -1299,7 +1311,8 @@ impl Stream { Ok(()) } #[cfg(feature = "http")] - Stream::HttpWrite(ref mut http_stream) => { + Stream::HttpWrite(ref mut http_stream) => { + http_stream.inner_mut().drop(); unsafe { http_stream.set_tag(ArenaHeaderTag::Dropped); std::ptr::drop_in_place(&mut http_stream.inner_mut().buffer as *mut _); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 34b26808..897dab67 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -14,7 +14,7 @@ use crate::forms::*; use crate::heap_iter::*; use crate::heap_print::*; #[cfg(feature = "http")] -use crate::http::{HttpListener, HttpResponse, HttpService}; +use crate::http::{HttpRequestData, HttpListener, HttpResponse, HttpRequest}; use crate::instructions::*; use crate::machine; use crate::machine::code_walker::*; @@ -44,14 +44,14 @@ pub(crate) use ref_thread_local::RefThreadLocal; use std::cell::Cell; use std::cmp::Ordering; -use std::collections::BTreeSet; +use std::collections::{BTreeSet}; use std::convert::TryFrom; use std::env; #[cfg(feature = "ffi")] use std::ffi::CString; use std::fs; use std::hash::{BuildHasher, BuildHasherDefault}; -use std::io::{ErrorKind, Read, Write}; +use std::io::{ErrorKind, Read, BufRead, Write}; use std::iter::{once, FromIterator}; use std::mem; use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs}; @@ -59,6 +59,7 @@ use std::num::NonZeroU32; use std::ops::Sub; use std::process; use std::str::FromStr; +use std::sync::{Mutex, Arc, Condvar}; use chrono::{offset::Local, DateTime}; #[cfg(not(target_arch = "wasm32"))] @@ -91,16 +92,15 @@ use base64; use roxmltree; use select; -use bytes::Buf; -use http_body_util::BodyExt; #[cfg(feature = "http")] -use hyper::header::{HeaderName, HeaderValue}; +use warp::hyper::header::{HeaderValue, HeaderName}; #[cfg(feature = "http")] -use hyper::server::conn::http1; +use warp::hyper::{HeaderMap, Method}; #[cfg(feature = "http")] -use hyper::{HeaderMap, Method}; +use warp::{Buf, Filter}; #[cfg(feature = "http")] use reqwest::Url; +use futures::future; #[cfg(feature = "repl")] pub(crate) fn get_key() -> KeyEvent { @@ -4412,54 +4412,119 @@ impl Machine { #[inline(always)] pub(crate) fn http_listen(&mut self) -> CallResult { let address_sink = self.deref_register(1); - if let Some(address_str) = self.machine_st.value_to_str_like(address_sink) { - let address_string = address_str.as_str(); - let addr: SocketAddr = match address_string - .to_socket_addrs() - .ok() - .and_then(|mut s| s.next()) - { - Some(addr) => addr, + let tls_key = self.deref_register(3); + let tls_cert = self.deref_register(4); + let content_length_limit = self.deref_register(5); + const CONTENT_LENGTH_LIMIT_DEFAULT: u64 = 32768; + let content_length_limit = match Number::try_from(content_length_limit) { + Ok(Number::Fixnum(n)) => if n.get_num() >= 0 { + n.get_num() as u64 + } else { + CONTENT_LENGTH_LIMIT_DEFAULT + }, + Ok(Number::Integer(n)) => { + let n: Result = (&*n).try_into(); + match n { + Ok(u) => u, + Err(_) => CONTENT_LENGTH_LIMIT_DEFAULT, + } + } + _ => CONTENT_LENGTH_LIMIT_DEFAULT, + }; + + let ssl_server: Option<(String,String)> = { + match self.machine_st.value_to_str_like(tls_key) { + Some(key) => { + match self.machine_st.value_to_str_like(tls_cert) { + Some(cert) => { + let key_str = key.as_str(); + let cert_str = cert.as_str(); + + if key_str.is_empty() || cert_str.is_empty() { + None + } else { + Some((key_str.to_string(), cert_str.to_string())) + } + } + None => None + } + } + None => None + } + }; + + if let Some(address_str) = self.machine_st.value_to_str_like(address_sink) { + let address_string = address_str.as_str(); + let addr: SocketAddr = match address_string.to_socket_addrs().ok().and_then(|mut s| s.next()) { + Some(addr) => addr, _ => { self.machine_st.fail = true; return Ok(()); } }; - let (tx, rx) = std::sync::mpsc::sync_channel(1024); + let (tx, rx) = std::sync::mpsc::sync_channel(1024); - let _guard = self.runtime.enter(); - let listener = match self - .runtime - .block_on(async { tokio::net::TcpListener::bind(addr).await }) - { - Ok(listener) => listener, - Err(_) => { - return Err(self.machine_st.open_permission_error( - address_sink, - atom!("http_listen"), - 2, - )); - } - }; + fn get_reader(body: impl Buf + Send + 'static) -> Box { + Box::new(body.reader()) + } - self.runtime.spawn(async move { - loop { - let tx = tx.clone(); - let (stream, _) = listener.accept().await.unwrap(); + let serve = warp::body::aggregate() + .and(warp::header::optional::(warp::http::header::CONTENT_LENGTH.as_str())) + .and(warp::method()) + .and(warp::header::headers_cloned()) + .and(warp::path::full()) + .and(warp::query::raw().or_else(|_| future::ready(Ok::<(String,), warp::Rejection>(("".to_string(),))))) + .map(move |body, content_length, method, headers: warp::http::HeaderMap, path: warp::filters::path::FullPath, query| { + if let Some(content_length) = content_length { + if content_length > content_length_limit { + return warp::http::Response::builder() + .status(413) + .body(warp::hyper::Body::empty()) + .unwrap(); + } + } + + let http_request_data = HttpRequestData { + method, + headers, + path: path.as_str().to_string(), + query, + body: get_reader(body), + }; + let response = Arc::new((Mutex::new(false), Mutex::new(None), Condvar::new())); + let http_request = HttpRequest { request_data: http_request_data, response: Arc::clone(&response) }; + // we send the request to http_accept + tx.send(http_request).unwrap(); - tokio::task::spawn(async move { - if let Err(err) = http1::Builder::new() - .serve_connection(stream, HttpService { tx }) - .await - { - eprintln!("Error serving connection: {:?}", err); - } - }); - } - }); - let http_listener = HttpListener { incoming: rx }; - let http_listener = arena_alloc!(http_listener, &mut self.machine_st.arena); + // we wait for the Response info from Prolog + { + let (ready, _response, cvar) = &*response; + let mut ready = ready.lock().unwrap(); + while !*ready { + ready = cvar.wait(ready).unwrap(); + } + } + { + let (_, response, _) = &*response; + let response = response.lock().unwrap().take(); + response.expect("Data race error in HTTP server") + } + }); + + self.runtime.spawn(async move { + match ssl_server { + Some((key, cert)) => { + warp::serve(serve).tls().key(key).cert(cert).run(addr).await + } + None => { + warp::serve(serve).run(addr).await + } + } + }); + + let http_listener = HttpListener { incoming: rx }; + let http_listener = arena_alloc!(http_listener, &mut self.machine_st.arena); let addr = self.deref_register(2); self.machine_st.bind( addr.as_var().unwrap(), @@ -4472,74 +4537,94 @@ impl Machine { #[cfg(feature = "http")] #[inline(always)] pub(crate) fn http_accept(&mut self) -> CallResult { - let culprit = self.deref_register(1); - let method = self.deref_register(2); - let path = self.deref_register(3); - let query = self.deref_register(5); - let stream_addr = self.deref_register(6); - let handle_addr = self.deref_register(7); - read_heap_cell!(culprit, - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::HttpListener, http_listener) => { - match http_listener.incoming.recv() { - Ok(request) => { - let method_atom = match *request.request.method() { - Method::GET => atom!("get"), - Method::POST => atom!("post"), - Method::PUT => atom!("put"), - Method::DELETE => atom!("delete"), - Method::PATCH => atom!("patch"), - Method::HEAD => atom!("head"), - _ => unreachable!(), - }; - let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, request.request.uri().path()); - let path_cell = atom_as_cstr_cell!(path_atom); - let headers: Vec = request.request.headers().iter().map(|(header_name, header_value)| { - let h = self.machine_st.heap.len(); + let culprit = self.deref_register(1); + let method = self.deref_register(2); + let path = self.deref_register(3); + let query = self.deref_register(5); + let stream_addr = self.deref_register(6); + let handle_addr = self.deref_register(7); + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::HttpListener, http_listener) => { + loop { + match http_listener.incoming.recv_timeout(std::time::Duration::from_millis(200)) { + Ok(request) => { + let method_atom = match request.request_data.method { + Method::GET => atom!("get"), + Method::POST => atom!("post"), + Method::PUT => atom!("put"), + Method::DELETE => atom!("delete"), + Method::PATCH => atom!("patch"), + Method::HEAD => atom!("head"), + Method::OPTIONS => atom!("options"), + Method::TRACE => atom!("trace"), + Method::CONNECT => atom!("connect"), + _ => atom!("unsupported_extension"), + }; + let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); + let path_cell = atom_as_cstr_cell!(path_atom); + let headers: Vec = request.request_data.headers.iter().map(|(header_name, header_value)| { + let h = self.machine_st.heap.len(); + let header_term = functor!(AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()), [cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))]); - let header_term = functor!( - AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()), - [cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))] - ); + self.machine_st.heap.extend(header_term.into_iter()); + str_loc_as_cell!(h) + }).collect(); - self.machine_st.heap.extend(header_term.into_iter()); - str_loc_as_cell!(h) - }).collect(); + let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter()); - let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter()); + let query_str = request.request_data.query; + let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &query_str); + let query_cell = string_as_cstr_cell!(query_atom); - let query_str = request.request.uri().query().unwrap_or(""); - let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, query_str); - let query_cell = string_as_cstr_cell!(query_atom); + let mut stream = Stream::from_http_stream( + path_atom, + request.request_data.body, + &mut self.machine_st.arena + ); + *stream.options_mut() = StreamOptions::default(); + stream.options_mut().set_stream_type(StreamType::Binary); + self.indices.streams.insert(stream); + let stream = stream_as_cell!(stream); - let hyper_req = request.request; - let buf = self.runtime.block_on(async {hyper_req.collect().await.unwrap().aggregate()}); - let reader = buf.reader(); + let handle = arena_alloc!(request.response, &mut self.machine_st.arena); - let mut stream = Stream::from_http_stream( - path_atom, - Box::new(reader), - &mut self.machine_st.arena - ); - *stream.options_mut() = StreamOptions::default(); - stream.options_mut().set_stream_type(StreamType::Binary); - self.indices.streams.insert(stream); - let stream = stream_as_cell!(stream); + self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom)); + self.machine_st.bind(path.as_var().unwrap(), path_cell); + unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]); + self.machine_st.bind(query.as_var().unwrap(), query_cell); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream); + self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle)); + break + } + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { + let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - let handle = arena_alloc!(request.response, &mut self.machine_st.arena); + match machine::INTERRUPT.compare_exchange( + interrupted, + false, + std::sync::atomic::Ordering::Relaxed, + std::sync::atomic::Ordering::Relaxed, + ) { + Ok(interruption) => { + if interruption { + self.machine_st.throw_interrupt_exception(); + self.machine_st.backtrack(); + let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); + old_runtime.shutdown_background(); + break + } + } + Err(_) => unreachable!(), + } - self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom)); - self.machine_st.bind(path.as_var().unwrap(), path_cell); - unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]); - self.machine_st.bind(query.as_var().unwrap(), query_cell); - self.machine_st.bind(stream_addr.as_var().unwrap(), stream); - self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle)); + } + Err(_) => { + self.machine_st.fail = true; + } + } } - Err(_) => { - self.machine_st.fail = true; - } - } } _ => { unreachable!(); From 750544dd2aa557aaee249eb88e229251bd373bd6 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 27 Sep 2023 13:34:11 -0600 Subject: [PATCH 36/60] fix max_depth settings for partial strings on lists (#1876) --- src/heap_print.rs | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index b02ef119..36afce78 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1237,14 +1237,24 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.iter.pop_stack(); } - if max_depth > 0 && pstr.chars().count() + 1 >= max_depth { + let non_trivial_end_cell = end_cell != empty_list_as_cell!(); + let non_trivial_end_cell_offset = non_trivial_end_cell as usize; + + let list_depth = pstr.chars().count() + non_trivial_end_cell_offset; + + if self.max_depth > 0 && list_depth >= max_depth { if tag != HeapCellValueTag::PStrOffset && tag != HeapCellValueTag::CStr { self.iter.pop_stack(); } - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - } else if end_cell != empty_list_as_cell!() { + if list_depth > max_depth { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + + if !self.max_depth_exhausted(max_depth) { + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + } + } + } else if non_trivial_end_cell { if tag == HeapCellValueTag::PStrOffset { self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); } @@ -1255,21 +1265,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let state_stack_len = self.state_stack.len(); - for (char_count, c) in pstr.chars().enumerate() { - if max_depth > 0 && char_count + 1 >= max_depth { - break; + if !self.max_depth_exhausted(max_depth) { + for (char_count, c) in pstr.chars().enumerate() { + if self.max_depth > 0 && char_count + 1 + non_trivial_end_cell_offset >= max_depth { + self.state_stack.push(TokenOrRedirect::Char(c)); + break; + } else { + self.state_stack.push(TokenOrRedirect::Char(c)); + self.state_stack.push(TokenOrRedirect::Comma); + } } + } - self.state_stack.push(TokenOrRedirect::Comma); - self.state_stack.push(TokenOrRedirect::Char(c)); + if let Some(TokenOrRedirect::Comma) = self.state_stack.last() { + self.state_stack.pop(); } self.state_stack[state_stack_len ..].reverse(); - - if let Some(TokenOrRedirect::Comma) = self.state_stack.last() { - self.state_stack.pop(); - } - self.open_list(switch); } ); @@ -1574,7 +1586,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { && !addr.is_compound(&self.iter.heap) && self.max_depth_exhausted(max_depth) { - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + if !(addr == atom_as_cell!(atom!("[]")) && self.at_cdr("")) { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + } + return; } From 0bfb08e464a16407ac899935961d84a9f3c925e2 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 27 Sep 2023 13:53:33 -0600 Subject: [PATCH 37/60] remove debug symbols from release builds (#2054) --- Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbf7cfc0..5fb0db69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,4 @@ predicates-core = "1.0.2" serial_test = "2.0.0" [patch.crates-io] -modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } - -[profile.release] -debug = true +modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } \ No newline at end of file From f630a8cc1ab279c917a348b3953c39719f751ac1 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 27 Sep 2023 17:55:15 -0600 Subject: [PATCH 38/60] fix add_predicate_declaration bug not correctly identifying lists of predicate indicators (#2049, #2050, #2051, #2052) --- src/loader.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loader.pl b/src/loader.pl index 513caafd..467644e0 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -411,7 +411,7 @@ add_predicate_declaration(Handler, Module:Name/Arity) :- predicate_indicator(Name/Arity), call(Handler, Module, Name, Arity). add_predicate_declaration(Handler, [PI|PIs]) :- - '$skip_max_list'(_, -1, PIs, Tail), + '$skip_max_list'(_, _, PIs, Tail), ( Tail == [], maplist(loader:predicate_indicator, PIs) -> maplist(loader:add_predicate_declaration(Handler), [PI|PIs]) From 035e214ef52917ca2fa994bf3988cf3d23c8b040 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 27 Sep 2023 18:16:23 -0600 Subject: [PATCH 39/60] check for ChildCloseList in print_struct on [] (#2039) --- src/heap_print.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 36afce78..b414a484 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1521,10 +1521,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let print_struct = |printer: &mut Self, name: Atom, arity: usize| { if name == atom!("[]") && arity == 0 { - if let Some(TokenOrRedirect::CloseList(_)) = printer.state_stack.last() { - if printer.at_cdr("") { - return; + match printer.state_stack.last() { + Some(TokenOrRedirect::CloseList(_) | TokenOrRedirect::ChildCloseList) => { + if printer.at_cdr("") { + return; + } } + _ => {} } append_str!(printer, "[]"); From 40d3345cd538b826bc91f3592562c4a32f69415e Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 27 Sep 2023 18:58:45 -0600 Subject: [PATCH 40/60] revert throwing domain errors for unexpected forms of read-options (#2015) --- src/lib/builtins.pl | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 4a0984a4..ec5a9968 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -124,7 +124,7 @@ call(_, _, _, _, _, _, _, _, _). % while others can be set with `set_prolog_flag/2`. % % The flags that Scryer Prolog support are: -% +% % * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 1023. Read only. % * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set % to `false` since it supports unbounded integer arithmethic. Read only. @@ -184,7 +184,7 @@ answer_write_options(Value) :- %% set_prolog_flag(Flag, Value). % % Sets the internal value of the flag. To see the list of flags supported by Scryer Prolog, -% check `current_prolog_flag/2`. The flags that are read only will fail if you try to change their values +% check `current_prolog_flag/2`. The flags that are read only will fail if you try to change their values set_prolog_flag(Flag, Value) :- (var(Flag) ; var(Value)), throw(error(instantiation_error, set_prolog_flag/2)). % 8.17.1.3 a, b @@ -721,30 +721,9 @@ parse_read_term_options(Options, OptionValues, Stub) :- parse_options_list(Options, builtins:parse_read_term_options_, DefaultOptions, OptionValues, Stub). -parse_read_term_options_(singletons(Vars), singletons-Vars) :- - ( ( var(Vars) - ; '$skip_max_list'(_, _, Vars, Rs), - Rs == [] - ) -> - ! - ; throw(error(domain_error(read_option, singletons(Vars)), read_term/2)) - ). -parse_read_term_options_(variables(Vars), variables-Vars) :- - ( ( var(Vars) - ; '$skip_max_list'(_, _, Vars, Rs), - Rs == [] - ) -> - ! - ; throw(error(domain_error(read_option, variables(Vars)), read_term/2)) - ). -parse_read_term_options_(variable_names(Vars), variable_names-Vars) :- - ( ( var(Vars) - ; '$skip_max_list'(_, _, Vars, Rs), - Rs == [] - ) -> - ! - ; throw(error(domain_error(read_option, variable_names(Vars)), read_term/2)) - ). +parse_read_term_options_(singletons(Vars), singletons-Vars) :- !. +parse_read_term_options_(variables(Vars), variables-Vars) :- !. +parse_read_term_options_(variable_names(Vars), variable_names-Vars) :- !. parse_read_term_options_(E,_) :- throw(error(domain_error(read_option, E), _)). @@ -754,7 +733,7 @@ parse_read_term_options_(E,_) :- % Read Term from the stream Stream. It supports several options: % * `variables(-Vars)` unifies Vars with a list of variables in the term. Similar to do `term_variables/2` with the new term. % * `variable_names(-Vars)` unifies Vars with a list `Name=Var` with Name describing the variable name and Var the variable itself that appears in Term. -% * `singletons` similar to `variable_names` but only reports variables occurring only once in Term. +% * `singletons` similar to `variable_names` but only reports variables occurring only once in Term. read_term(Stream, Term, Options) :- parse_read_term_options(Options, [Singletons, VariableNames, Variables], read_term/3), '$read_term'(Stream, Term, Singletons, Variables, VariableNames). @@ -1622,7 +1601,7 @@ atom_concat(Atom_1, Atom_2, Atom_12) :- %% sub_atom(+Atom, ?Before, ?Length, ?After, ?SubAtom). % % Relates an atom to a subatom inside with some key properties: -% +% % * SubAtom starts at Before characters (0-based) from Atom % * SubAtom has Length characters % * After SubAtom there are After characters in Atom From 11cd42379bd4959e29e5eb47f405f21b5fc75039 Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 28 Sep 2023 15:25:57 -0600 Subject: [PATCH 41/60] do not deref AttrVar binding in redo_attr_var_binding (#2059) --- src/machine/system_calls.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 897dab67..daa119fc 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -5659,7 +5659,9 @@ impl Machine { } #[inline(always)] pub(crate) fn redo_attr_var_binding(&mut self) { - let var = self.deref_register(1); + // registers[1] MUST NOT be dereferenced here. the original + // AttrVar binding site must be preserved. + let var = self.machine_st.registers[1]; let value = self.deref_register(2); debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag()); From ca2ddfeed036df1444b35fbaba3cd92ad044cea1 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 29 Sep 2023 01:00:14 -0600 Subject: [PATCH 42/60] improve max_depth write option (#1876, #2053) --- src/heap_print.rs | 102 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 26 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index b414a484..850f0023 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -233,6 +233,8 @@ enum TokenOrRedirect { OpenList(Rc>), CloseList(Rc>), HeadTailSeparator, + StackPop, + CommaSeparatedCharList { pstr: PartialString, offset: usize, num_chars: usize }, } pub(crate) fn requires_space(atom: &str, op: &str) -> bool { @@ -643,12 +645,26 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } else if self.check_max_depth(&mut max_depth) { - self.iter.pop_stack(); - self.iter.pop_stack(); + if is_xfy!(spec.get_spec()) { + let left_directed_op = DirectedOp::Left(name, spec); - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); - self.state_stack.push(TokenOrRedirect::Op(name, spec)); - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::CompositeRedirect( + 0, + left_directed_op, + )); + + self.state_stack.push(TokenOrRedirect::Op(name, spec)); + self.state_stack.push(TokenOrRedirect::StackPop); + } else { // is_yfx! + let right_directed_op = DirectedOp::Right(name, spec); + + self.state_stack.push(TokenOrRedirect::StackPop); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); + self.state_stack.push(TokenOrRedirect::CompositeRedirect( + 0, + right_directed_op, + )); + } } else { let left_directed_op = DirectedOp::Left(name, spec); let right_directed_op = DirectedOp::Right(name, spec); @@ -657,6 +673,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { max_depth, left_directed_op, )); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, @@ -835,7 +852,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { ) } - fn check_for_seen(&mut self) -> Option { + fn check_for_seen(&mut self, max_depth: usize) -> Option { if let Some(cell) = self.iter.next() { let is_cyclic = cell.get_forwarding_bit(); @@ -872,10 +889,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }); } None => { - // otherwise, contract it to an ellipsis. - push_space_if_amb!(self, "...", { - append_str!(self, "..."); - }); + if self.max_depth == 0 || max_depth == 0 { + // otherwise, contract it to an ellipsis. + push_space_if_amb!(self, "...", { + append_str!(self, "..."); + }); + } else { + debug_assert!(cell.is_ref()); + + let h = cell.get_value() as usize; + self.iter.push_stack(IterStackLoc::iterable_loc(h, HeapOrStackTag::Heap)); + return self.iter.next(); + } } } @@ -1227,7 +1252,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize); let pstr = cell_as_string!(self.iter.heap[h]); - let pstr = pstr.as_str_from(offset.get_num() as usize); + let offset = offset.get_num() as usize; + let pstr = pstr.as_str_from(offset); let tag = value.get_tag(); if tag == HeapCellValueTag::PStrOffset { @@ -1253,35 +1279,36 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if !self.max_depth_exhausted(max_depth) { self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } + } else if non_trivial_end_cell { + self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); + + self.state_stack.push(TokenOrRedirect::FunctorRedirect(1)); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } } else if non_trivial_end_cell { if tag == HeapCellValueTag::PStrOffset { self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); } - self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth.saturating_sub(list_depth - 1))); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } - let state_stack_len = self.state_stack.len(); - if !self.max_depth_exhausted(max_depth) { - for (char_count, c) in pstr.chars().enumerate() { - if self.max_depth > 0 && char_count + 1 + non_trivial_end_cell_offset >= max_depth { - self.state_stack.push(TokenOrRedirect::Char(c)); + let mut num_chars = 0; + + for (char_count, _c) in pstr.chars().enumerate() { + num_chars += 1; + + if self.max_depth > 0 && char_count + 1 >= max_depth { break; - } else { - self.state_stack.push(TokenOrRedirect::Char(c)); - self.state_stack.push(TokenOrRedirect::Comma); } } + + let pstr = cell_as_string!(self.iter.heap[h]); + self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList { pstr, offset, num_chars }); } - if let Some(TokenOrRedirect::Comma) = self.state_stack.last() { - self.state_stack.pop(); - } - - self.state_stack[state_stack_len ..].reverse(); self.open_list(switch); } ); @@ -1580,7 +1607,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } }; - let addr = match self.check_for_seen() { + let addr = match self.check_for_seen(max_depth) { Some(addr) => addr, None => return, }; @@ -1746,6 +1773,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { TokenOrRedirect::Space => push_char!(self, ' '), TokenOrRedirect::LeftCurly => push_char!(self, '{'), TokenOrRedirect::RightCurly => push_char!(self, '}'), + TokenOrRedirect::StackPop => { + self.iter.pop_stack(); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + } + TokenOrRedirect::CommaSeparatedCharList { pstr, offset, num_chars } => { + let pstr_str = pstr.as_str_from(offset); + + if let Some(c) = pstr_str.chars().next() { + let offset = offset + c.len_utf8(); + + if num_chars > 1 { + self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList { + pstr, + offset: offset, + num_chars: num_chars - 1, + }); + + self.state_stack.push(TokenOrRedirect::Comma); + } + + self.state_stack.push(TokenOrRedirect::Char(c)); + } + } } } From f33f641f1114d7968cd657caab1a464f6e5bbedc Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 29 Sep 2023 11:48:05 -0600 Subject: [PATCH 43/60] further max_depth improvements --- src/heap_print.rs | 153 +++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 850f0023..c4b38c03 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -208,6 +208,15 @@ impl NumberFocus { } } +#[derive(Debug, Clone, Copy)] +struct CommaSeparatedCharList { + pstr: PartialString, + offset: usize, + max_depth: usize, + end_cell: HeapCellValue, + end_h: Option, +} + #[derive(Debug, Clone)] enum TokenOrRedirect { Atom(Atom), @@ -234,7 +243,7 @@ enum TokenOrRedirect { CloseList(Rc>), HeadTailSeparator, StackPop, - CommaSeparatedCharList { pstr: PartialString, offset: usize, num_chars: usize }, + CommaSeparatedCharList(CommaSeparatedCharList), } pub(crate) fn requires_space(atom: &str, op: &str) -> bool { @@ -1115,10 +1124,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } // returns true if max_depth limit is reached and ellipsis is printed. - fn print_string_as_functor(&mut self, focus: usize, max_depth: usize) -> bool { + fn print_string_as_functor(&mut self, focus: usize, max_depth: &mut usize) -> bool { let iter = HeapPStrIter::new(self.iter.heap, focus); for (char_count, c) in iter.chars().enumerate() { + if self.check_max_depth(max_depth) { + if char_count > 0 { + self.state_stack.push(TokenOrRedirect::Close); + } + + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + return true; + } + append_str!(self, "'.'"); push_char!(self, '('); @@ -1126,16 +1144,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { push_char!(self, ','); self.state_stack.push(TokenOrRedirect::Close); - - if max_depth >= char_count + 1 { - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); - return true; - } } false } + // proper strings are terminal so there's no need for max_depth to + // be a mutable ref here. fn print_proper_string(&mut self, focus: usize, max_depth: usize) { push_char!(self, '"'); @@ -1223,16 +1238,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.at_cdr(","); self.remove_list_children(focus.value() as usize); - if !self.print_string_as_functor(focus.value() as usize, max_depth) { + if !self.print_string_as_functor(focus.value() as usize, &mut max_depth) { if end_cell == empty_list_as_cell!() { if !self.at_cdr("") { append_str!(self, "[]"); } } else { - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); - self.iter - .push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); } } } else { @@ -1250,63 +1263,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let switch = self.close_list(switch); let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize); - let pstr = cell_as_string!(self.iter.heap[h]); let offset = offset.get_num() as usize; - let pstr = pstr.as_str_from(offset); let tag = value.get_tag(); - if tag == HeapCellValueTag::PStrOffset { + let end_h = if tag == HeapCellValueTag::PStrOffset { // remove the fixnum offset from the iterator stack so we don't // print an extraneous number. pstr offset value cells are never // used by the iterator to mark cyclic terms so the removal is safe. self.iter.pop_stack(); - } - - let non_trivial_end_cell = end_cell != empty_list_as_cell!(); - let non_trivial_end_cell_offset = non_trivial_end_cell as usize; - - let list_depth = pstr.chars().count() + non_trivial_end_cell_offset; - - if self.max_depth > 0 && list_depth >= max_depth { - if tag != HeapCellValueTag::PStrOffset && tag != HeapCellValueTag::CStr { - self.iter.pop_stack(); - } - - if list_depth > max_depth { - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); - - if !self.max_depth_exhausted(max_depth) { - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - } - } else if non_trivial_end_cell { - self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); - - self.state_stack.push(TokenOrRedirect::FunctorRedirect(1)); - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - } - } else if non_trivial_end_cell { - if tag == HeapCellValueTag::PStrOffset { - self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); - } - - self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth.saturating_sub(list_depth - 1))); - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - } + Some(end_h) + } else { + None + }; if !self.max_depth_exhausted(max_depth) { - let mut num_chars = 0; - - for (char_count, _c) in pstr.chars().enumerate() { - num_chars += 1; - - if self.max_depth > 0 && char_count + 1 >= max_depth { - break; - } - } - let pstr = cell_as_string!(self.iter.heap[h]); - self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList { pstr, offset, num_chars }); + self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList { + pstr, offset, max_depth, end_cell, end_h, + })); + } else { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } self.open_list(switch); @@ -1538,6 +1515,46 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } + fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) { + let CommaSeparatedCharList { pstr, offset, max_depth, end_cell, end_h } = char_list; + let pstr_str = pstr.as_str_from(offset); + + if let Some(c) = pstr_str.chars().next() { + let offset = offset + c.len_utf8(); + + if !self.max_depth_exhausted(max_depth) { + self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList { + pstr, + offset, + max_depth: max_depth.saturating_sub(1), + end_cell, + end_h, + })); + + let max_depth_allows = self.max_depth == 0 || max_depth > 1; + + if max_depth_allows && pstr_str.chars().skip(1).next().is_some() { + self.state_stack.push(TokenOrRedirect::Comma); + } + + self.state_stack.push(TokenOrRedirect::Char(c)); + } else { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + } + } else if self.max_depth_exhausted(max_depth) { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + } else if end_cell != empty_list_as_cell!() { + if let Some(end_h) = end_h { + self.iter.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); + } + + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + } + } + fn handle_heap_term( &mut self, op: Option, @@ -1777,24 +1794,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.iter.pop_stack(); self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } - TokenOrRedirect::CommaSeparatedCharList { pstr, offset, num_chars } => { - let pstr_str = pstr.as_str_from(offset); - - if let Some(c) = pstr_str.chars().next() { - let offset = offset + c.len_utf8(); - - if num_chars > 1 { - self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList { - pstr, - offset: offset, - num_chars: num_chars - 1, - }); - - self.state_stack.push(TokenOrRedirect::Comma); - } - - self.state_stack.push(TokenOrRedirect::Char(c)); - } + TokenOrRedirect::CommaSeparatedCharList(char_list) => { + self.print_comma_separated_char_list(char_list); } } } From 9e713406d3007c7239be7c33d3f02fef640648cc Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 11:44:20 -0600 Subject: [PATCH 44/60] correct max_depth marking for lists --- src/heap_print.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index c4b38c03..3c331b84 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1355,11 +1355,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let switch = self.close_list(cell); - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.open_list(switch); } From 25afc111680abfff959ba20f1d85c7ffc0111673 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 15:24:30 -0600 Subject: [PATCH 45/60] correct skipping of not fully visited lists in stackful heap iterator (#2056, #2063, #2065) --- src/heap_iter.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/heap_iter.rs b/src/heap_iter.rs index fc5d3416..6005aa2e 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -127,9 +127,15 @@ impl<'a> StackfulPreOrderHeapIter<'a> { #[inline] fn forward_if_referent_marked(&mut self, loc: IterStackLoc) { - read_heap_cell!(self.read_cell(loc), + let cell = self.read_cell(loc); + + read_heap_cell!(cell, + (HeapCellValueTag::Lis, vh) => { + if cell.get_mark_bit() && self.heap[vh].get_mark_bit() { + self.read_cell_mut(loc).set_forwarding_bit(true); + } + } (HeapCellValueTag::Str | - HeapCellValueTag::Lis | HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::PStrLoc, vh) => { @@ -260,28 +266,27 @@ impl<'a> StackfulPreOrderHeapIter<'a> { (HeapCellValueTag::Lis, vh) => { let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); + self.forward_if_referent_marked(loc); self.push_if_unmarked(loc); self.stack.push(IterStackLoc::pending_mark_loc(vh + 1, HeapOrStackTag::Heap)); self.stack.push(IterStackLoc::mark_loc(vh, HeapOrStackTag::Heap)); - self.forward_if_referent_marked(loc); - return Some(self.read_cell(h)); } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, vh) => { let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); + self.forward_if_referent_marked(loc); self.push_if_unmarked(loc); self.stack.push(IterStackLoc::mark_loc(vh, HeapOrStackTag::Heap)); - self.forward_if_referent_marked(loc); } (HeapCellValueTag::StackVar, vs) => { let loc = IterStackLoc::iterable_loc(vs, HeapOrStackTag::Stack); + self.forward_if_referent_marked(loc); self.push_if_unmarked(loc); self.stack.push(IterStackLoc::mark_loc(vs, HeapOrStackTag::Stack)); - self.forward_if_referent_marked(loc); } (HeapCellValueTag::PStrOffset, offset) => { self.push_if_unmarked(IterStackLoc::iterable_loc(offset, HeapOrStackTag::Heap)); @@ -2059,6 +2064,10 @@ mod tests { ); assert_eq!(iter.next().unwrap(), cyclic_link); + assert_eq!(iter.next().unwrap(), cyclic_link); + + assert_eq!(iter.next().unwrap(), cyclic_link); + assert_eq!(iter.next(), None); } From 62c23166fa8b5456859610d052deff9144b600f7 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 16:00:15 -0600 Subject: [PATCH 46/60] implement ListElisionPolicy to restore previous printer behavior --- src/heap_iter.rs | 202 ++++++++++++++++------------ src/heap_print.rs | 6 +- src/machine/arithmetic_ops.rs | 3 +- src/machine/attributed_variables.rs | 3 +- src/machine/loader.rs | 3 +- src/machine/machine_state.rs | 2 +- src/machine/machine_state_impl.rs | 5 +- src/machine/system_calls.rs | 4 +- src/machine/unify.rs | 4 +- 9 files changed, 134 insertions(+), 98 deletions(-) diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 6005aa2e..ffb8df90 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -6,6 +6,7 @@ use crate::machine::heap::*; use crate::machine::stack::*; use crate::types::*; +use core::marker::PhantomData; use modular_bitfield::prelude::*; use std::ops::Deref; @@ -79,15 +80,40 @@ impl IterStackLoc { } } +pub trait ListElisionPolicy { + fn elide_lists() -> bool; +} + #[derive(Debug)] -pub struct StackfulPreOrderHeapIter<'a> { +pub struct ListElider {} + +impl ListElisionPolicy for ListElider { + #[inline(always)] + fn elide_lists() -> bool { + true + } +} + +#[derive(Debug)] +pub struct NonListElider {} + +impl ListElisionPolicy for NonListElider { + #[inline(always)] + fn elide_lists() -> bool { + false + } +} + +#[derive(Debug)] +pub struct StackfulPreOrderHeapIter<'a, ElideLists> { pub heap: &'a mut Vec, pub machine_stack: &'a mut Stack, stack: Vec, h: IterStackLoc, + _marker: PhantomData, } -impl<'a> Drop for StackfulPreOrderHeapIter<'a> { +impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> { fn drop(&mut self) { while let Some(h) = self.stack.pop() { let cell = self.read_cell_mut(h); @@ -104,59 +130,14 @@ pub trait FocusedHeapIter: Iterator { fn focus(&self) -> IterStackLoc; } -impl<'a> FocusedHeapIter for StackfulPreOrderHeapIter<'a> { +impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter for StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] fn focus(&self) -> IterStackLoc { self.h } } -impl<'a> StackfulPreOrderHeapIter<'a> { - #[inline] - fn new(heap: &'a mut Vec, stack: &'a mut Stack, cell: HeapCellValue) -> Self { - let h = IterStackLoc::iterable_loc(heap.len(), HeapOrStackTag::Heap); - heap.push(cell); - - Self { - heap, - h, - machine_stack: stack, - stack: vec![h], - } - } - - #[inline] - fn forward_if_referent_marked(&mut self, loc: IterStackLoc) { - let cell = self.read_cell(loc); - - read_heap_cell!(cell, - (HeapCellValueTag::Lis, vh) => { - if cell.get_mark_bit() && self.heap[vh].get_mark_bit() { - self.read_cell_mut(loc).set_forwarding_bit(true); - } - } - (HeapCellValueTag::Str | - HeapCellValueTag::AttrVar | - HeapCellValueTag::Var | - HeapCellValueTag::PStrLoc, vh) => { - if self.heap[vh].get_mark_bit() { - self.read_cell_mut(loc).set_forwarding_bit(true); - } - } - (HeapCellValueTag::StackVar, vs) => { - if self.machine_stack[vs].get_mark_bit() { - self.read_cell_mut(loc).set_forwarding_bit(true); - } - } - _ => {} - ); - } - - #[inline] - pub fn push_stack(&mut self, h: IterStackLoc) { - self.stack.push(h); - } - +impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue { match loc.heap_or_stack() { @@ -173,6 +154,11 @@ impl<'a> StackfulPreOrderHeapIter<'a> { } } + #[inline] + pub fn push_stack(&mut self, h: IterStackLoc) { + self.stack.push(h); + } + #[inline] pub fn stack_last(&self) -> Option { for h in self.stack.iter().rev() { @@ -228,6 +214,51 @@ impl<'a> StackfulPreOrderHeapIter<'a> { )); } } +} + +impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> { + #[inline] + fn new(heap: &'a mut Vec, stack: &'a mut Stack, cell: HeapCellValue) -> Self { + let h = IterStackLoc::iterable_loc(heap.len(), HeapOrStackTag::Heap); + heap.push(cell); + + Self { + heap, + h, + machine_stack: stack, + stack: vec![h], + _marker: PhantomData, + } + } + + #[inline] + fn forward_if_referent_marked(&mut self, loc: IterStackLoc) { + let cell = self.read_cell(loc); + + read_heap_cell!(cell, + (HeapCellValueTag::Lis, vh) => { + let forward = if ElideLists::elide_lists() { true } else { cell.get_mark_bit() }; + + if forward && self.heap[vh].get_mark_bit() { + self.read_cell_mut(loc).set_forwarding_bit(true); + } + } + (HeapCellValueTag::Str | + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::PStrLoc, vh) => { + if self.heap[vh].get_mark_bit() { + self.read_cell_mut(loc).set_forwarding_bit(true); + } + } + (HeapCellValueTag::StackVar, vs) => { + if self.machine_stack[vs].get_mark_bit() { + self.read_cell_mut(loc).set_forwarding_bit(true); + } + } + _ => {} + ); + } fn follow(&mut self) -> Option { while let Some(h) = self.stack.pop() { @@ -330,7 +361,7 @@ impl<'a> StackfulPreOrderHeapIter<'a> { } } -impl<'a> Iterator for StackfulPreOrderHeapIter<'a> { +impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a, ElideLists> { type Item = HeapCellValue; #[inline] @@ -349,11 +380,11 @@ pub(crate) fn stackless_preorder_iter( } #[inline(always)] -pub(crate) fn stackful_preorder_iter<'a>( +pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( heap: &'a mut Vec, stack: &'a mut Stack, cell: HeapCellValue, -) -> StackfulPreOrderHeapIter<'a> { +) -> StackfulPreOrderHeapIter<'a, ElideLists> { StackfulPreOrderHeapIter::new(heap, stack, cell) } @@ -460,9 +491,10 @@ impl PostOrderIterator { } } -pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator>; +pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> = + PostOrderIterator>; -impl<'a> LeftistPostOrderHeapIter<'a> { +impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists> { #[inline] pub fn pop_stack(&mut self) { if let Some((child_count, ..)) = self.parent_stack.last() { @@ -481,11 +513,11 @@ impl<'a> LeftistPostOrderHeapIter<'a> { } #[inline] -pub(crate) fn stackful_post_order_iter<'a>( +pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>( heap: &'a mut Heap, stack: &'a mut Stack, cell: HeapCellValue, -) -> LeftistPostOrderHeapIter<'a> { +) -> LeftistPostOrderHeapIter<'a, ElideLists> { PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, cell)) } @@ -1555,7 +1587,7 @@ mod tests { .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, str_loc_as_cell!(0), @@ -1590,7 +1622,7 @@ mod tests { )); for _ in 0..20 { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, str_loc_as_cell!(0), @@ -1622,7 +1654,7 @@ mod tests { { wam.machine_st.heap.push(heap_loc_as_cell!(0)); - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1649,7 +1681,7 @@ mod tests { wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1673,7 +1705,7 @@ mod tests { wam.machine_st.heap.push(empty_list_as_cell!()); { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1709,7 +1741,7 @@ mod tests { wam.machine_st.heap.push(heap_loc_as_cell!(0)); { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1741,7 +1773,7 @@ mod tests { } { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1780,7 +1812,7 @@ mod tests { let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1805,7 +1837,7 @@ mod tests { let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; { - let mut iter = stackful_preorder_iter( + let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1832,7 +1864,7 @@ mod tests { .push(fixnum_as_cell!(Fixnum::build_with(0i64))); { - let mut iter = stackful_preorder_iter( + let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, pstr_loc_as_cell!(0), @@ -1867,7 +1899,7 @@ mod tests { .push(fixnum_as_cell!(Fixnum::build_with(1i64))); { - let mut iter = stackful_preorder_iter( + let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, pstr_loc_as_cell!(0), @@ -1911,7 +1943,7 @@ mod tests { wam.machine_st.heap.extend(functor); { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -1974,7 +2006,7 @@ mod tests { wam.machine_st.heap[4] = list_loc_as_cell!(1); { - let mut iter = stackful_preorder_iter( + let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2043,7 +2075,7 @@ mod tests { wam.machine_st.heap.push(list_loc_as_cell!(1)); { - let mut iter = StackfulPreOrderHeapIter::new( + let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2079,7 +2111,7 @@ mod tests { wam.machine_st.heap.push(empty_list_as_cell!()); { - let mut iter = stackful_preorder_iter( + let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2111,7 +2143,7 @@ mod tests { wam.machine_st.heap.push(empty_list_as_cell!()); { - let mut iter = stackful_preorder_iter( + let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2149,7 +2181,7 @@ mod tests { .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, str_loc_as_cell!(0), @@ -2185,7 +2217,7 @@ mod tests { for _ in 0..20 { // 0000 { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, str_loc_as_cell!(0), @@ -2219,7 +2251,7 @@ mod tests { { wam.machine_st.heap.push(heap_loc_as_cell!(0)); - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2246,7 +2278,7 @@ mod tests { wam.machine_st.heap.push(heap_loc_as_cell!(1)); wam.machine_st.heap.push(heap_loc_as_cell!(0)); - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2270,7 +2302,7 @@ mod tests { wam.machine_st.heap.push(empty_list_as_cell!()); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2306,7 +2338,7 @@ mod tests { wam.machine_st.heap.push(heap_loc_as_cell!(0)); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2338,7 +2370,7 @@ mod tests { } { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2377,7 +2409,7 @@ mod tests { let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, pstr_loc_as_cell!(0), @@ -2401,7 +2433,7 @@ mod tests { let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, pstr_loc_as_cell!(0), @@ -2428,7 +2460,7 @@ mod tests { .push(fixnum_as_cell!(Fixnum::build_with(0i64))); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, pstr_loc_as_cell!(0), @@ -2455,7 +2487,7 @@ mod tests { .push(fixnum_as_cell!(Fixnum::build_with(1i64))); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, pstr_loc_as_cell!(0), @@ -2489,7 +2521,7 @@ mod tests { wam.machine_st.heap.extend(functor); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), @@ -2553,7 +2585,7 @@ mod tests { wam.machine_st.heap[4] = list_loc_as_cell!(1); { - let mut iter = stackful_post_order_iter( + let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, heap_loc_as_cell!(0), diff --git a/src/heap_print.rs b/src/heap_print.rs index 3c331b84..0e002c78 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -104,7 +104,7 @@ fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool { } } -impl<'a> StackfulPreOrderHeapIter<'a> { +impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { /* * descend into the subtree where the iterator is currently parked * and check that the leftmost leaf is a number, with every node @@ -407,7 +407,7 @@ fn is_numbered_var(name: Atom, arity: usize) -> bool { #[inline] fn negated_op_needs_bracketing( - iter: &StackfulPreOrderHeapIter, + iter: &StackfulPreOrderHeapIter, op_dir: &OpDir, op: &Option, ) -> bool { @@ -491,7 +491,7 @@ pub fn fmt_float(mut fl: f64) -> String { #[derive(Debug)] pub struct HCPrinter<'a, Outputter> { outputter: Outputter, - iter: StackfulPreOrderHeapIter<'a>, + iter: StackfulPreOrderHeapIter<'a, ListElider>, atom_tbl: Arc, op_dir: &'a OpDir, state_stack: Vec, diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 69e48cad..149338b5 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1208,7 +1208,8 @@ impl MachineState { value: HeapCellValue, ) -> Result { let stub_gen = || functor_stub(atom!("is"), 2); - let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, value); + let mut iter = stackful_post_order_iter:: + (&mut self.heap, &mut self.stack, value); while let Some(value) = iter.next() { if value.get_forwarding_bit() { diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 0b08e8bb..a09a790e 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -133,7 +133,8 @@ impl MachineState { let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; - let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, cell); + let mut iter = stackful_preorder_iter:: + (&mut self.heap, &mut self.stack, cell); while let Some(value) = iter.next() { read_heap_cell!(value, diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 467bfb80..07ba3078 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1418,7 +1418,8 @@ impl MachineState { term_addr: HeapCellValue, ) -> Term { let mut term_stack = vec![]; - let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, term_addr); + let mut iter = stackful_post_order_iter:: + (&mut self.heap, &mut self.stack, term_addr); while let Some(addr) = iter.next() { let addr = unmark_cell_bits!(addr); diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 0cb45e39..c09ba26b 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -588,7 +588,7 @@ impl MachineState { let mut singleton_var_set: IndexMap = IndexMap::new(); - for cell in stackful_preorder_iter(&mut self.heap, &mut self.stack, heap_loc) { + for cell in stackful_preorder_iter::(&mut self.heap, &mut self.stack, heap_loc) { let cell = unmark_cell_bits!(cell); if let Some(var) = cell.as_var() { diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 2c909937..1ee0e20d 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1135,7 +1135,8 @@ impl MachineState { return false; } - let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, value); + let mut iter = stackful_preorder_iter:: + (&mut self.heap, &mut self.stack, value); while let Some(value) = iter.next() { if value.get_forwarding_bit() { @@ -1633,7 +1634,7 @@ impl MachineState { } let mut visited = IndexSet::with_hasher(FxBuildHasher::default()); - let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, value); + let mut iter = stackful_preorder_iter::(&mut self.heap, &mut self.stack, value); let mut stack_len = 0; while let Some(value) = iter.next() { diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index daa119fc..cf1b060e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -583,7 +583,7 @@ impl MachineState { seen_set: &mut IndexSet, value: HeapCellValue, ) { - let mut iter = stackful_preorder_iter(&mut self.heap, &mut self.stack, value); + let mut iter = stackful_preorder_iter::(&mut self.heap, &mut self.stack, value); while let Some(value) = iter.next() { let value = unmark_cell_bits!(value); @@ -793,7 +793,7 @@ impl MachineState { let mut seen_set = IndexSet::new(); { - let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, term); + let mut iter = stackful_post_order_iter::(&mut self.heap, &mut self.stack, term); while let Some(value) = iter.next() { if iter.parent_stack_len() >= max_depth { diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 11e12654..f9c03189 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -1,6 +1,6 @@ use crate::arena::*; use crate::forms::*; -use crate::heap_iter::stackful_preorder_iter; +use crate::heap_iter::{NonListElider, stackful_preorder_iter}; use crate::machine::machine_state::*; use crate::machine::partial_string::*; use crate::machine::*; @@ -717,7 +717,7 @@ fn bind_with_occurs_check(unifier: &mut U, r: Ref, value: HeapCellVa if !value.is_constant() { let machine_st: &mut MachineState = unifier.deref_mut(); - for cell in stackful_preorder_iter(&mut machine_st.heap, &mut machine_st.stack, value) { + for cell in stackful_preorder_iter::(&mut machine_st.heap, &mut machine_st.stack, value) { let cell = unmark_cell_bits!(cell); if let Some(inner_r) = cell.as_var() { From 7d6ce119f59177b9c0992eba57f4e356b513a1ad Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 16:47:13 -0600 Subject: [PATCH 47/60] substitute names for cyclic variables permitted by max_depth > 0 in check_for_seen using a loop (#2057) --- src/heap_print.rs | 100 ++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 0e002c78..daf339c8 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -862,61 +862,67 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } fn check_for_seen(&mut self, max_depth: usize) -> Option { - if let Some(cell) = self.iter.next() { - let is_cyclic = cell.get_forwarding_bit(); + if let Some(mut orig_cell) = self.iter.next() { + loop { + let is_cyclic = orig_cell.get_forwarding_bit(); - let cell = heap_bound_store(self.iter.heap, heap_bound_deref(self.iter.heap, cell)); - let cell = unmark_cell_bits!(cell); + let cell = heap_bound_store(self.iter.heap, heap_bound_deref(self.iter.heap, orig_cell)); + let cell = unmark_cell_bits!(cell); - match self.var_names.get(&cell).cloned() { - Some(var) if cell.is_var() => { - // If cell is an unbound variable and maps to - // a name via heap_locs, append the name to - // the current output, and return None. None - // short-circuits handle_heap_term. - // self.iter.pop_stack(); + match self.var_names.get(&cell).cloned() { + Some(var) if cell.is_var() => { + // If cell is an unbound variable and maps to + // a name via heap_locs, append the name to + // the current output, and return None. None + // short-circuits handle_heap_term. + // self.iter.pop_stack(); - let var_str = var.borrow().to_string(); + let var_str = var.borrow().to_string(); - push_space_if_amb!(self, &var_str, { - append_str!(self, &var_str); - }); - - None - } - var_opt => { - if is_cyclic && cell.is_compound(self.iter.heap) { - // self-referential variables are marked "cyclic". - match var_opt { - Some(var) => { - // If the term is bound to a named variable, - // print the variable's name to output. - let var_str = var.borrow().to_string(); - - push_space_if_amb!(self, &var_str, { - append_str!(self, &var_str); - }); - } - None => { - if self.max_depth == 0 || max_depth == 0 { - // otherwise, contract it to an ellipsis. - push_space_if_amb!(self, "...", { - append_str!(self, "..."); - }); - } else { - debug_assert!(cell.is_ref()); - - let h = cell.get_value() as usize; - self.iter.push_stack(IterStackLoc::iterable_loc(h, HeapOrStackTag::Heap)); - return self.iter.next(); - } - } - } + push_space_if_amb!(self, &var_str, { + append_str!(self, &var_str); + }); return None; } + var_opt => { + if is_cyclic && cell.is_compound(self.iter.heap) { + // self-referential variables are marked "cyclic". + match var_opt { + Some(var) => { + // If the term is bound to a named variable, + // print the variable's name to output. + let var_str = var.borrow().to_string(); - Some(cell) + push_space_if_amb!(self, &var_str, { + append_str!(self, &var_str); + }); + } + None => { + if self.max_depth == 0 || max_depth == 0 { + // otherwise, contract it to an ellipsis. + push_space_if_amb!(self, "...", { + append_str!(self, "..."); + }); + } else { + debug_assert!(cell.is_ref()); + + let h = cell.get_value() as usize; + self.iter.push_stack(IterStackLoc::iterable_loc(h, HeapOrStackTag::Heap)); + + if let Some(cell) = self.iter.next() { + orig_cell = cell; + continue; + } + } + } + } + + return None; + } + + return Some(cell); + } } } } else { From b065e1cd53752248e326ec358983d0e48d69fca6 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 17:15:20 -0600 Subject: [PATCH 48/60] correct depth calculation for lists that are their own car (#1876) --- src/heap_print.rs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index daf339c8..1ad88f29 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -861,7 +861,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { ) } - fn check_for_seen(&mut self, max_depth: usize) -> Option { + fn check_for_seen(&mut self, max_depth: &mut usize) -> Option { if let Some(mut orig_cell) = self.iter.next() { loop { let is_cyclic = orig_cell.get_forwarding_bit(); @@ -899,7 +899,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }); } None => { - if self.max_depth == 0 || max_depth == 0 { + if self.max_depth == 0 || *max_depth == 0 { // otherwise, contract it to an ellipsis. push_space_if_amb!(self, "...", { append_str!(self, "..."); @@ -907,6 +907,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } else { debug_assert!(cell.is_ref()); + // as usual, the WAM's + // optimization of the Lis tag + // (conflating the location of + // the list and that of its + // first element) needs + // special consideration here + // lest we find ourselves in + // an infinite loop. + if cell.get_tag() == HeapCellValueTag::Lis { + *max_depth -= 1; + } + let h = cell.get_value() as usize; self.iter.push_stack(IterStackLoc::iterable_loc(h, HeapOrStackTag::Heap)); @@ -1363,7 +1375,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar - self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); self.open_list(switch); } @@ -1563,10 +1575,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { &mut self, op: Option, is_functor_redirect: bool, - max_depth: usize, + mut max_depth: usize, ) { let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op); + let addr = match self.check_for_seen(&mut max_depth) { + Some(addr) => addr, + None => return, + }; + let print_struct = |printer: &mut Self, name: Atom, arity: usize| { if name == atom!("[]") && arity == 0 { match printer.state_stack.last() { @@ -1628,11 +1645,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } }; - let addr = match self.check_for_seen(max_depth) { - Some(addr) => addr, - None => return, - }; - if !addr.is_var() && !addr.is_compound(&self.iter.heap) && self.max_depth_exhausted(max_depth) From 21c61b6e3a808fb8034ab72dfb0444a786f2a74b Mon Sep 17 00:00:00 2001 From: bakaq Date: Sat, 30 Sep 2023 21:33:42 -0300 Subject: [PATCH 49/60] Add tests for #2056 --- src/tests/dif.pl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tests/dif.pl b/src/tests/dif.pl index bb1c76d6..752f1405 100644 --- a/src/tests/dif.pl +++ b/src/tests/dif.pl @@ -196,6 +196,17 @@ test("scryer-prolog#1956",( Res = [] )). +% https://github.com/mthom/scryer-prolog/issues/2056 +test("scryer-prolog#2056",( + set_prolog_flag(occurs_check, false), + C=[D|E], + D=[C], + A=[A], + dif(A,[D]), + + \+ E=[] +)). + main :- findall(test(Name, Goal), test(Name, Goal), Tests), run_tests(Tests, Failed), From 6fa00b5b550ab28ef73b9e0b2cb75e071b198237 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 22:20:50 -0600 Subject: [PATCH 50/60] get rid of inference_limit_exceeded(B) as an error term (#2023) --- build/instructions_template.rs | 4 + src/lib/iso_ext.pl | 54 ++--- src/machine/dispatch.rs | 383 ++++++------------------------ src/machine/machine_state.rs | 26 +- src/machine/machine_state_impl.rs | 2 +- src/machine/system_calls.rs | 14 +- 6 files changed, 125 insertions(+), 358 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 894254c7..15881bfd 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -601,6 +601,8 @@ enum SystemClauseType { Name = "$keysort_with_constant_var_ordering" )))] KeySortWithConstantVarOrdering, + #[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))] + InferenceLimitExceeded, REPL(REPLCodePtr), } @@ -1727,6 +1729,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallUnattributedVar | &Instruction::CallGetDBRefs | &Instruction::CallKeySortWithConstantVarOrdering | + &Instruction::CallInferenceLimitExceeded | &Instruction::CallFetchGlobalVar | &Instruction::CallFirstStream | &Instruction::CallFlushOutput | @@ -1960,6 +1963,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteUnattributedVar | &Instruction::ExecuteGetDBRefs | &Instruction::ExecuteKeySortWithConstantVarOrdering | + &Instruction::ExecuteInferenceLimitExceeded | &Instruction::ExecuteFetchGlobalVar | &Instruction::ExecuteFirstStream | &Instruction::ExecuteFlushOutput | diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index d53ff47b..5096bfb9 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -214,27 +214,6 @@ run_cleaners_without_handling(Cp) :- % call_with_inference_limit -:- non_counted_backtracking end_block/4. - -end_block(_, Bb, NBb, _L) :- - '$clean_up_block'(NBb), - '$reset_block'(Bb). -end_block(B, _Bb, NBb, L) :- - '$install_inference_counter'(B, L, _), - '$reset_block'(NBb), - '$fail'. - -:- non_counted_backtracking handle_ile/3. - -handle_ile(B, inference_limit_exceeded(B), R) :- - !, - R = inference_limit_exceeded, - '$pop_ball_stack'. -handle_ile(B, _, _) :- - '$remove_call_policy_check'(B), - '$pop_from_ball_stack', - '$unwind_stack'. - :- meta_predicate(call_with_inference_limit(0, ?, ?)). :- non_counted_backtracking call_with_inference_limit/3. @@ -257,8 +236,6 @@ call_with_inference_limit(G, L, R) :- call_with_inference_limit(G, L, R, Bb, B), '$remove_call_policy_check'(B). -install_inference_counter(B, L, Count0) :- - '$install_inference_counter'(B, L, Count0). :- meta_predicate(call_with_inference_limit(0,?,?,?,?)). @@ -266,23 +243,34 @@ install_inference_counter(B, L, Count0) :- call_with_inference_limit(G, L, R, Bb, B) :- '$install_new_block'(NBb), - '$install_inference_counter'(B, L, Count0), + '$install_inference_counter'(NBb, L, Count0), '$call_with_inference_counting'(call(G)), '$inference_level'(R, B), - '$remove_inference_counter'(B, Count1), + '$remove_inference_counter'(NBb, Count1), Diff is L - (Count1 - Count0), - end_block(B, Bb, NBb, Diff). + ( '$clean_up_block'(NBb), + '$reset_block'(Bb) + ; '$install_inference_counter'(NBb, Diff, _), + '$reset_block'(NBb), + '$fail' + ). call_with_inference_limit(_, _, R, Bb, B) :- + ( '$inference_limit_exceeded' -> + R = inference_limit_exceeded + ; true + ), + '$get_current_block'(NBb), + '$remove_inference_counter'(NBb, _), '$reset_block'(Bb), - '$remove_inference_counter'(B, _), - ( '$get_ball'(Ball), + '$remove_call_policy_check'(B), + ( '$get_ball'(_), '$push_ball_stack', '$get_cp'(Cp), - '$set_cp_by_default'(Cp) - ; '$remove_call_policy_check'(B), - '$fail' - ), - handle_ile(B, Ball, R). + '$set_cp_by_default'(Cp), + '$pop_from_ball_stack', + '$unwind_stack' + ; nonvar(R) + ). %% partial_string(String, L, L0) % diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 1ac43189..23fe7c02 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -34,6 +34,15 @@ macro_rules! try_or_throw { }}; } +macro_rules! increment_call_count { + ($s:expr) => {{ + if !($s.increment_call_count_fn)(&mut $s) { + $s.backtrack(); + continue; + } + }}; +} + macro_rules! try_or_throw_gen { ($s:expr, $e:expr) => {{ match $e { @@ -1096,12 +1105,7 @@ impl Machine { self.trust_me(); } - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } } } @@ -1174,12 +1178,7 @@ impl Machine { self.trust_me(); } - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } } } @@ -1205,19 +1204,11 @@ impl Machine { } &Instruction::RetryMeElse(offset) => { self.retry_me_else(offset); - - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + increment_call_count!(self.machine_st); } &Instruction::TrustMe(_) => { self.trust_me(); - - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + increment_call_count!(self.machine_st); } &Instruction::NeckCut => { self.machine_st.neck_cut(); @@ -1521,11 +1512,7 @@ impl Machine { if self.machine_st.is_cyclic_term(addr) { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1535,11 +1522,7 @@ impl Machine { if self.machine_st.is_cyclic_term(addr) { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1549,11 +1532,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1563,11 +1542,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1577,11 +1552,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1591,11 +1562,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1605,11 +1572,7 @@ impl Machine { if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } else { self.machine_st.backtrack(); @@ -1621,11 +1584,7 @@ impl Machine { if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); @@ -1636,11 +1595,7 @@ impl Machine { let a2 = self.machine_st.registers[2]; if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } else { self.machine_st.backtrack(); @@ -1651,11 +1606,7 @@ impl Machine { let a2 = self.machine_st.registers[2]; if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); @@ -1667,11 +1618,7 @@ impl Machine { match compare_term_test!(self.machine_st, a1, a2) { Some(Ordering::Greater | Ordering::Equal) => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -1685,11 +1632,7 @@ impl Machine { match compare_term_test!(self.machine_st, a1, a2) { Some(Ordering::Greater | Ordering::Equal) => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -1703,11 +1646,7 @@ impl Machine { match compare_term_test!(self.machine_st, a1, a2) { Some(Ordering::Less | Ordering::Equal) => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -1721,11 +1660,7 @@ impl Machine { match compare_term_test!(self.machine_st, a1, a2) { Some(Ordering::Less | Ordering::Equal) => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -1739,11 +1674,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1753,11 +1684,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1768,11 +1695,7 @@ impl Machine { if self.machine_st.eq_test(a1, a2) { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1783,11 +1706,7 @@ impl Machine { if self.machine_st.eq_test(a1, a2) { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1795,11 +1714,7 @@ impl Machine { if self.machine_st.ground_test() { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1807,11 +1722,7 @@ impl Machine { if self.machine_st.ground_test() { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1821,11 +1732,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1835,11 +1742,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1850,11 +1753,7 @@ impl Machine { if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1865,11 +1764,7 @@ impl Machine { if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1879,11 +1774,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1893,11 +1784,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1910,11 +1797,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1927,11 +1810,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1944,11 +1823,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1961,11 +1836,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -1975,11 +1846,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -1989,11 +1856,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -2003,11 +1866,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -2017,11 +1876,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -2039,10 +1894,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + increment_call_count!(self.machine_st); } } &Instruction::ExecuteN(arity) => { @@ -2059,10 +1911,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + increment_call_count!(self.machine_st); } } &Instruction::DefaultCallN(arity) => { @@ -2101,11 +1950,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Less | Ordering::Equal => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -2119,11 +1964,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Less | Ordering::Equal => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -2137,11 +1978,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Equal => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -2155,11 +1992,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Equal => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -2176,11 +2009,7 @@ impl Machine { self.machine_st.backtrack(); } _ => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } } @@ -2194,11 +2023,7 @@ impl Machine { self.machine_st.backtrack(); } _ => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } @@ -2209,11 +2034,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Greater | Ordering::Equal => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -2227,11 +2048,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Greater | Ordering::Equal => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -2245,11 +2062,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Greater => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -2263,11 +2076,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Greater => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -2281,11 +2090,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Less => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { @@ -2299,11 +2104,7 @@ impl Machine { match n1.cmp(&n2) { Ordering::Less => { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - + increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { @@ -2878,10 +2679,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + increment_call_count!(self.machine_st); } } &Instruction::ExecuteNamed(arity, name, ref idx) => { @@ -2892,10 +2690,7 @@ impl Machine { if self.machine_st.fail { self.machine_st.backtrack(); } else { - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + increment_call_count!(self.machine_st); } } &Instruction::DefaultCallNamed(arity, name, ref idx) => { @@ -3224,26 +3019,14 @@ impl Machine { } &IndexedChoiceInstruction::Retry(l) => { self.retry(l); - - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } &IndexedChoiceInstruction::DefaultRetry(l) => { self.retry(l); } &IndexedChoiceInstruction::Trust(l) => { self.trust(l); - - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } &IndexedChoiceInstruction::DefaultTrust(l) => { self.trust(l); @@ -3318,38 +3101,16 @@ impl Machine { // this is true iff ii + 1 < len. Some(_) => { self.retry(offset); - - try_or_throw!( - self.machine_st, - (self - .machine_st - .increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } _ => { self.trust(offset); - - try_or_throw!( - self.machine_st, - (self - .machine_st - .increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } } } else { self.trust(offset); - - try_or_throw!( - self.machine_st, - (self.machine_st.increment_call_count_fn)( - &mut self.machine_st - ) - ); + increment_call_count!(self.machine_st); } } } @@ -5484,6 +5245,14 @@ impl Machine { self.get_db_refs(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallInferenceLimitExceeded => { + self.inference_limit_exceeded(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteInferenceLimitExceeded => { + self.inference_limit_exceeded(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index c09ba26b..55a09ef5 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -96,7 +96,7 @@ pub struct MachineState { pub(crate) unify_fn: fn(&mut MachineState), pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool, - pub(crate) increment_call_count_fn: fn(&mut MachineState) -> CallResult, + pub(crate) increment_call_count_fn: fn(&mut MachineState) -> bool, } impl fmt::Debug for MachineState { @@ -412,22 +412,24 @@ impl MachineState { self.fail = false; } - pub(crate) fn increment_call_count(&mut self) -> CallResult { + pub(crate) fn increment_call_count(&mut self) -> bool { if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 { - return Ok(()); + return true; } - if let Some(&(ref limit, bp)) = self.cwil.limits.last() { + if let Some(&(ref limit, block)) = self.cwil.limits.last() { if self.cwil.count == *limit { self.cwil.inference_limit_exceeded = true; + self.block = block; + self.unwind_stack(); - return Err(functor!(atom!("inference_limit_exceeded"), [fixnum(bp)])); + return false; } else { self.cwil.count += 1; } } - Ok(()) + true } #[allow(dead_code)] @@ -945,7 +947,7 @@ impl MachineState { pub(crate) struct CWIL { count: Integer, limits: Vec<(Integer, usize)>, - inference_limit_exceeded: bool, + pub(crate) inference_limit_exceeded: bool, } impl CWIL { @@ -957,22 +959,22 @@ impl CWIL { } } - pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer { + pub(crate) fn add_limit(&mut self, limit: usize, block: usize) -> &Integer { let mut limit = Integer::from(limit); limit += &self.count; match self.limits.last() { Some((ref inner_limit, _)) if *inner_limit <= limit => {} - _ => self.limits.push((limit, b)), + _ => self.limits.push((limit, block)), }; &self.count } #[inline(always)] - pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { - if let Some((_, bp)) = self.limits.last() { - if bp == &b { + pub(crate) fn remove_limit(&mut self, block: usize) -> &Integer { + if let Some((_, bl)) = self.limits.last() { + if bl == &block { self.limits.pop(); } } diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 1ee0e20d..34b9d55a 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -60,7 +60,7 @@ impl MachineState { unify_fn: MachineState::unify, bind_fn: MachineState::bind, run_cleaners_fn: |_| false, - increment_call_count_fn: |_| Ok(()), + increment_call_count_fn: |_| true, } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index cf1b060e..5029fcb8 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -5695,7 +5695,7 @@ impl Machine { if bp == self.machine_st.b && self.machine_st.cwil.is_empty() { self.machine_st.cwil.reset(); - self.machine_st.increment_call_count_fn = |_| Ok(()); + self.machine_st.increment_call_count_fn = |_| true; } } @@ -5704,11 +5704,10 @@ impl Machine { let a1 = self.deref_register(1); let a2 = self.deref_register(2); - let bp = cell_as_fixnum!(a1).get_num() as usize; - - let count = self.machine_st.cwil.remove_limit(bp).clone(); - + let block = cell_as_fixnum!(a1).get_num() as usize; + let count = self.machine_st.cwil.remove_limit(block).clone(); let result = count.clone().try_into(); + if let Ok(value) = result{ self.machine_st.unify_fixnum(Fixnum::build_with(value), a2); } else { @@ -5875,6 +5874,11 @@ impl Machine { } } + #[inline(always)] + pub(crate) fn inference_limit_exceeded(&mut self) { + self.machine_st.fail = !self.machine_st.cwil.inference_limit_exceeded; + } + #[inline(always)] pub(crate) fn clean_up_block(&mut self) { let nb = self.deref_register(1); From 4a8aa0acbdd9e9e17875f2c652385fb649dc7255 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 30 Sep 2023 22:22:01 -0600 Subject: [PATCH 51/60] throw instantiation_error from error/2 if Error_term uninstantiated (#2060) --- src/lib/builtins.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index ec5a9968..b7b60df9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -2226,4 +2226,7 @@ nl(Stream) :- % % Throws an exception of the following structure: `error(ErrorTerm, ImpDef)`. error(Error_term, Imp_def) :- - throw(error(Error_term, Imp_def)). + ( var(Error_term) -> + throw(error(instantiation_error, error/2)) + ; throw(error(Error_term, Imp_def)) + ). From a1ceeb697ac3c005898eb9ffe1cee61aeb0786cb Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 1 Oct 2023 17:11:26 -0600 Subject: [PATCH 52/60] consider an '$aux' a relation of the unexpanded goal's variables in compile_inline_or_expanded_goal (#2062) --- build/instructions_template.rs | 2 +- src/loader.pl | 2 +- src/machine/system_calls.rs | 13 ++++++------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 15881bfd..0aca72f6 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -574,7 +574,7 @@ enum SystemClauseType { PredicateDefined, #[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))] StripModule, - #[strum_discriminants(strum(props(Arity = "4", Name = "$compile_inline_or_expanded_goal")))] + #[strum_discriminants(strum(props(Arity = "5", Name = "$compile_inline_or_expanded_goal")))] CompileInlineOrExpandedGoal, #[strum_discriminants(strum(props(Arity = "arity", Name = "$fast_call")))] FastCallN(usize), diff --git a/src/loader.pl b/src/loader.pl index 467644e0..d0fb65a8 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -739,7 +739,7 @@ expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars) :- expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars) ; ExpandedGoals0 = UnexpandedGoals4 ), - '$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1), + '$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1, UnexpandedGoals0), expand_module_name(ExpandedGoals1, MS, Module1, ExpandedGoals). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 5029fcb8..40881c54 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1411,7 +1411,6 @@ impl Machine { is_simple_goal: bool, goal: HeapCellValue, key: PredicateKey, - expanded_vars: IndexSet>, supp_vars: IndexSet>, } @@ -1436,7 +1435,7 @@ impl Machine { // insertion as well as the previous // supp_vars.len() argument's variables being // disjoint from them. if they are not, the - // expanded goal are not simple. + // expanded goal is not simple. let post_supp_args = self.machine_st.heap[s+arity-supp_vars.len()+1 .. s+arity+1] .iter() @@ -1482,7 +1481,6 @@ impl Machine { is_simple_goal, goal, key: (name, arity), - expanded_vars, supp_vars } } @@ -1496,7 +1494,6 @@ impl Machine { is_simple_goal: true, goal: str_loc_as_cell!(h), key: (name, 0), - expanded_vars: IndexSet::with_hasher(FxBuildHasher::default()), supp_vars, } } @@ -1510,7 +1507,6 @@ impl Machine { is_simple_goal: true, goal: str_loc_as_cell!(h), key: (name, 0), - expanded_vars: IndexSet::with_hasher(FxBuildHasher::default()), supp_vars, } } @@ -1532,9 +1528,12 @@ impl Machine { .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); result.goal } else { + let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default()); + self.machine_st.variable_set(&mut unexpanded_vars, self.machine_st.registers[5]); + // all supp_vars must appear later! let vars = IndexSet::>::from_iter( - result.expanded_vars.difference(&result.supp_vars).cloned(), + unexpanded_vars.difference(&result.supp_vars).cloned(), ); let vars: Vec<_> = vars @@ -1556,7 +1555,7 @@ impl Machine { self.machine_st.heap.push(atom_as_cell!(atom!("$aux"), 0)); - for value in result.expanded_vars.difference(&result.supp_vars).cloned() { + for value in unexpanded_vars.difference(&result.supp_vars).cloned() { self.machine_st.heap.push(value); } From 27b971cbfa92f8f2ab9fac054998094fd28338b0 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 1 Oct 2023 18:55:31 -0600 Subject: [PATCH 53/60] add registers to inlined instruction functors --- build/instructions_template.rs | 42 ++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 0aca72f6..8aa4d837 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -1660,29 +1660,31 @@ fn generate_instruction_preface() -> TokenStream { let (name, arity) = self.to_name_and_arity(); functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) } - &Instruction::CallIsAtom(_) | - &Instruction::CallIsAtomic(_) | - &Instruction::CallIsCompound(_) | - &Instruction::CallIsInteger(_) | - &Instruction::CallIsNumber(_) | - &Instruction::CallIsRational(_) | - &Instruction::CallIsFloat(_) | - &Instruction::CallIsNonVar(_) | - &Instruction::CallIsVar(_) => { + &Instruction::CallIsAtom(r) | + &Instruction::CallIsAtomic(r) | + &Instruction::CallIsCompound(r) | + &Instruction::CallIsInteger(r) | + &Instruction::CallIsNumber(r) | + &Instruction::CallIsRational(r) | + &Instruction::CallIsFloat(r) | + &Instruction::CallIsNonVar(r) | + &Instruction::CallIsVar(r) => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("call"), [atom(name), fixnum(arity)]) + let rt_stub = reg_type_into_functor(r); + functor!(atom!("call"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub]) } - &Instruction::ExecuteIsAtom(_) | - &Instruction::ExecuteIsAtomic(_) | - &Instruction::ExecuteIsCompound(_) | - &Instruction::ExecuteIsInteger(_) | - &Instruction::ExecuteIsNumber(_) | - &Instruction::ExecuteIsRational(_) | - &Instruction::ExecuteIsFloat(_) | - &Instruction::ExecuteIsNonVar(_) | - &Instruction::ExecuteIsVar(_) => { + &Instruction::ExecuteIsAtom(r) | + &Instruction::ExecuteIsAtomic(r) | + &Instruction::ExecuteIsCompound(r) | + &Instruction::ExecuteIsInteger(r) | + &Instruction::ExecuteIsNumber(r) | + &Instruction::ExecuteIsRational(r) | + &Instruction::ExecuteIsFloat(r) | + &Instruction::ExecuteIsNonVar(r) | + &Instruction::ExecuteIsVar(r) => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("execute"), [atom(name), fixnum(arity)]) + let rt_stub = reg_type_into_functor(r); + functor!(atom!("execute"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub]) } // &Instruction::CallAtomChars | From f3b848537aef601b13bd525df09ee74f5bbeeae9 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Mon, 2 Oct 2023 23:17:06 +0200 Subject: [PATCH 54/60] FIXED: corrections to expansion_simpler/2 Example: ?- X = 0, Y = 0, Z #= X-1 + Y-1. X = 0, Y = 0, Z = -2. This addresses #2064. See ca5a5b4392bfbed8cfdbb3b2e7dbaa42ea193007 for a previous issue in this logic. --- src/lib/clpz.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index f438043d..c4ba62fa 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -3099,13 +3099,13 @@ expansion_simpler(Var is Expr0, Goal) :- ground(Expr0), !, phrase(expr_conds(Expr0, Expr), Gs), ( maplist(call, Gs) -> Value is Expr, Goal = (Var = Value) - ; Goal = false + ; Goal = (Var is Expr0) ). expansion_simpler(Var =:= Expr0, Goal) :- ground(Expr0), !, phrase(expr_conds(Expr0, Expr), Gs), ( maplist(call, Gs) -> Value is Expr, Goal = (Var =:= Value) - ; Goal = false + ; Goal = (Var =:= Expr0) ). expansion_simpler(between:between(L,U,V), Goal) :- maplist(integer, [L,U,V]), From 93ff049e54d3dafce4193729d22281d88718e2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Arroyo=20Calle?= Date: Mon, 2 Oct 2023 23:49:09 +0200 Subject: [PATCH 55/60] Improved version of url_decode --- src/lib/http/http_server.pl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib/http/http_server.pl b/src/lib/http/http_server.pl index faa76ce5..4c22e497 100644 --- a/src/lib/http/http_server.pl +++ b/src/lib/http/http_server.pl @@ -300,25 +300,21 @@ http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries parse_queries([Key-Value|Queries]) --> string_without("=", Key0), - { - phrase(url_decode(Key), Key0) - }, "=", string_without("&", Value0), - { - phrase(url_decode(Value), Value0) - }, "&", - parse_queries(Queries). + parse_queries(Queries), + { + phrase(url_decode(Key), Key0), + phrase(url_decode(Value), Value0) + }. parse_queries([Key-Value]) --> string_without("=", Key0), - { - phrase(url_decode(Key), Key0) - }, "=", string_without(" ", Value0), { + phrase(url_decode(Key), Key0), phrase(url_decode(Value), Value0) }. @@ -329,9 +325,13 @@ parse_queries([]) --> url_decode([Char|Chars]) --> [Char], { - Char \= '%' + Char \= '%', + Char \= (+) }, url_decode(Chars). +url_decode([' '|Chars]) --> + "+", + url_decode(Chars). url_decode([Char|Chars]) --> "%", [A], From 7c10683e4628ab77f9ca7133d6f41f5f2a217d37 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 3 Oct 2023 19:15:17 +0200 Subject: [PATCH 56/60] Revert "FIXED: corrections to expansion_simpler/2" This reverts commit f3b848537aef601b13bd525df09ee74f5bbeeae9. The root cause of this problem is a mistake in ground/1. See #2073. --- src/lib/clpz.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index c4ba62fa..f438043d 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -3099,13 +3099,13 @@ expansion_simpler(Var is Expr0, Goal) :- ground(Expr0), !, phrase(expr_conds(Expr0, Expr), Gs), ( maplist(call, Gs) -> Value is Expr, Goal = (Var = Value) - ; Goal = (Var is Expr0) + ; Goal = false ). expansion_simpler(Var =:= Expr0, Goal) :- ground(Expr0), !, phrase(expr_conds(Expr0, Expr), Gs), ( maplist(call, Gs) -> Value is Expr, Goal = (Var =:= Value) - ; Goal = (Var =:= Expr0) + ; Goal = false ). expansion_simpler(between:between(L,U,V), Goal) :- maplist(integer, [L,U,V]), From fd14869ddc1f75361d043b6843badd96435f6249 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 3 Oct 2023 12:04:10 -0600 Subject: [PATCH 57/60] correct cycle detection in ground/1 (#2073) --- src/machine/machine_state_impl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 34b9d55a..c8d7a4dc 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1648,7 +1648,7 @@ impl MachineState { } } - if value.is_compound(iter.heap) { + if value.is_ref() { if visited.contains(&value) { for _ in stack_len..iter.stack_len() { iter.pop_stack(); @@ -1686,7 +1686,7 @@ impl MachineState { }, Ok(Number::Integer(n)) => { let b: u8 = (&*n).try_into().unwrap(); - + bytes.push(b); } _ => {} From f9d44c93fd87ea570e00e9262714aa0a0443e4fc Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 3 Oct 2023 15:31:01 -0600 Subject: [PATCH 58/60] check for free variables in locations removed from iterator stack in ground_test (#2075) --- src/machine/machine_state_impl.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index c8d7a4dc..75c3deb2 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1637,21 +1637,33 @@ impl MachineState { let mut iter = stackful_preorder_iter::(&mut self.heap, &mut self.stack, value); let mut stack_len = 0; - while let Some(value) = iter.next() { - let mut value = unmark_cell_bits!(value); + let is_var = |heap: &Heap, value: HeapCellValue| -> bool { + let value = unmark_cell_bits!(value); if value.is_var() { - value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value)); + let value = heap_bound_store(heap, heap_bound_deref(heap, value)); if value.is_var() { return true; } } + false + }; + + while let Some(value) = iter.next() { + if is_var(iter.heap, value) { + return true; + } + if value.is_ref() { if visited.contains(&value) { - for _ in stack_len..iter.stack_len() { - iter.pop_stack(); + while iter.stack_len() > stack_len { + if let Some(value) = iter.pop_stack() { + if is_var(iter.heap, value) { + return true; + } + } } } else { visited.insert(value); From c070fbec62d0104f66a407d90217e964d57cf250 Mon Sep 17 00:00:00 2001 From: infogulch Date: Tue, 3 Oct 2023 20:51:50 -0500 Subject: [PATCH 59/60] Pin logtalk to version before scryer support was removed --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27b4e9d5..ad9d2598 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,6 +117,7 @@ jobs: name: scryer-prolog_unknown_wasm32 logtalk-test: + # if: false # uncomment to disable job runs-on: ubuntu-20.04 needs: [build-test] steps: @@ -130,7 +131,7 @@ jobs: - name: Install Logtalk uses: logtalk-actions/setup-logtalk@master with: - logtalk-version: git + logtalk-version: "3.70.0" logtalk-tool-dependencies: false # Run logtalk tests. From 1e60eeef3450cdb6817f8f626fb32be6018d83c2 Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 4 Oct 2023 00:26:44 -0600 Subject: [PATCH 60/60] consider Str, PStrLoc in ElideLists of StackfulHeapIterator (#2075) --- src/heap_iter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/heap_iter.rs b/src/heap_iter.rs index ffb8df90..0bfbd465 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -236,17 +236,17 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> let cell = self.read_cell(loc); read_heap_cell!(cell, - (HeapCellValueTag::Lis, vh) => { + (HeapCellValueTag::Lis | + HeapCellValueTag::Str | + HeapCellValueTag::PStrLoc, vh) => { let forward = if ElideLists::elide_lists() { true } else { cell.get_mark_bit() }; if forward && self.heap[vh].get_mark_bit() { self.read_cell_mut(loc).set_forwarding_bit(true); } } - (HeapCellValueTag::Str | - HeapCellValueTag::AttrVar | - HeapCellValueTag::Var | - HeapCellValueTag::PStrLoc, vh) => { + (HeapCellValueTag::AttrVar | + HeapCellValueTag::Var, vh) => { if self.heap[vh].get_mark_bit() { self.read_cell_mut(loc).set_forwarding_bit(true); }