11 Commits

Author SHA1 Message Date
Mark Thom
4e7d9f9010 update README.md
Some checks failed
CI / style (push) Has been cancelled
CI / read-msrv (push) Has been cancelled
CI / build-test (--no-default-features --features=all-simple-cross, miri, true, ubuntu-22.04, nightly, s390x-unknown-linux-gnu, --no-run --no-default-features --features=all-simple-cross) (push) Has been cancelled
CI / build-test (--no-default-features, ubuntu-22.04, true, nightly, wasm32-unknown-unknown, --no-run --no-default-features, true) (push) Has been cancelled
CI / build-test (miri, true, ubuntu-22.04, nightly, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (true, macos-latest, true, stable, x86_64-apple-darwin) (push) Has been cancelled
CI / build-test (true, ubuntu-22.04, true, stable, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (true, windows-latest, true, stable, x86_64-pc-windows-msvc) (push) Has been cancelled
CI / build-test (ubuntu-22.04, ${{ needs.read-msrv.outputs.msrv }}, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, beta, x86_64-unknown-linux-gnu) (push) Has been cancelled
CI / build-test (ubuntu-22.04, true, stable, i686-unknown-linux-gnu) (push) Has been cancelled
CI / logtalk-test (push) Has been cancelled
CI / report (push) Has been cancelled
CI / release (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
2026-07-21 23:51:19 -07:00
Mark Thom
d3edffb7fc update README.md 2026-07-21 23:48:56 -07:00
Mark Thom
295a642034 Merge pull request #3372 from triska/global_cardinality
FIXED: Correct global_cardinality/2 propagation with reified constraints.
2026-06-30 17:25:30 -07:00
Mark Thom
ae0999a3bb Merge pull request #3398 from Skgland/fix-3320
fix incorrect missing feature errors
2026-06-30 17:25:02 -07:00
Mark Thom
11fd39bbaf Merge pull request #3275 from abmclin/Issue-3223-migrate-to-Rust-edition-2024
Issue 3223 migrate to rust edition 2024
2026-06-30 17:22:27 -07:00
Skgland
eb06f19c32 fix incorrect missing feature errors
this was accidentally introduced in mthom/scryer-prolog#3320

fixes mthom/scryer-prolog#3397
2026-06-29 20:13:10 +02:00
Alexander McLin
ea88ca552d Issue 3223: reformat via cargo fmt 2026-06-16 21:18:49 -04:00
Alexander McLin
eabbf67e86 Issue 3223: add more unsafe scopes 2026-06-16 21:14:43 -04:00
Alexander McLin
7a636b0394 Issue 3223: trying again repair for the failing wasm32 build
Removed `mut` modifier completely.
2026-06-16 21:05:12 -04:00
Alexander McLin
71ea74a077 Issue 3223: repair for the failing wasm32 build
Removed `ref` modifier due to not being allowed when implicitly borrowing.
2026-06-16 21:05:12 -04:00
Markus Triska
9b73536cdd FIXED: Correct global_cardinality/2 propagation with reified constraints.
This issue was found by @david-sitsky in a Prolog formulation of an
interesting scheduling task:

    https://github.com/mthom/scryer-prolog/discussions/3341

See also the filed issue:

    https://github.com/mthom/scryer-prolog/issues/3369

Thank you a lot!

This issue needs more analysis to find out what exactly happened here,
whether other cases like it exist, and whether it can be addressed in
a better way. I would greatly appreciate any help!
2026-06-10 20:31:20 +02:00
5 changed files with 120 additions and 146 deletions

View File

@@ -73,9 +73,10 @@ Extend Scryer Prolog to include the following, among other features:
- [ ] Inlining all built-ins and system call instructions.
- [x] Greatly reducing the number of instructions used to compile disjunctives.
- [x] Storing short atoms to heap cells without writing them to the atom table.
- [ ] Configurable JIT/on-demand indexing over all arguments
(documented in "[Demand-Driven Indexing of Prolog Clauses](https://user.it.uu.se/~kostis/Papers/iclp07.pdf)"). (_in progress_)
- [ ] A compacting garbage collector satisfying the five properties of
"[Precise Garbage Collection in Prolog](https://www.complang.tuwien.ac.at/ulrich/papers/PDF/2008-ciclops.pdf)." (_in progress_)
- [ ] Mode declarations.
## Phase 3
@@ -103,8 +104,6 @@ Gustafson's book "[The End of Error](http://www.johngustafson.net/unums.html)."
3. Add concurrent tables to manage shared references to atoms and
strings.
4. Add some form of JIT predicate indexing.
## Installing Scryer Prolog
### Binaries

View File

@@ -3,7 +3,7 @@
Author: Markus Triska
E-mail: triska@metalevel.at
WWW: https://www.metalevel.at
Copyright (C): 2016-2024 Markus Triska
Copyright (C): 2016-2026 Markus Triska
This library provides CLP():
@@ -6844,6 +6844,22 @@ gcc_global(Vs, KNs) -->
% the propagator of tuples_in/2). Hence: We need this only if
% an example shows it, ideally found by a systematic search
% that can be used to test the implementation.
%
% UPDATE: A case that requires gcc_check//1 was recently found,
% see: https://github.com/mthom/scryer-prolog/issues/3369.
%
% We need to study carefully what exactly happens in this case.
% The example involves reified constraints, which post constraints
% in their propagators. The example also involves multiple queues,
% because not all reified constraints use variables_same_queue/1
% (for instance (#==>)/2 does not), and variables_same_queue/1 would
% in fact need changes to handle cases where variables no longer
% have a clpz attribute attached. Such cases arise for variables
% involved in entailed reified constraints.
gcc_check(KNs), % see comment above.
do_queue, % is this needed? this (also) needs more analysis.
{ with_local_attributes(Vs,
(gcc_arcs(KNs, S, Vals),
variables_with_num_occurrences(Vs, VNs),

View File

@@ -7915,7 +7915,7 @@ impl Machine {
#[cfg(not(feature = "crypto-full"))]
{
let stub_gen = || functor_stub(atom!("crypto_random_byte"), 1);
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let err = self.machine_st.missing_feature_error(atom!("crypto-full"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
@@ -8079,7 +8079,7 @@ impl Machine {
#[cfg(not(feature = "crypto-full"))]
{
let stub_gen = || functor_stub(atom!("crypto_data_hash"), 1);
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let err = self.machine_st.missing_feature_error(atom!("crypto-full"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
return;
@@ -8132,7 +8132,7 @@ impl Machine {
#[cfg(not(feature = "crypto-full"))]
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let err = self.machine_st.missing_feature_error(atom!("crypto-full"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
@@ -8215,7 +8215,7 @@ impl Machine {
#[cfg(not(feature = "crypto-full"))]
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let err = self.machine_st.missing_feature_error(atom!("crypto-full"));
let exception = self.machine_st.error_form(err, stub1_gen());
self.machine_st.throw_exception(exception);
}
@@ -8283,7 +8283,7 @@ impl Machine {
#[cfg(not(feature = "crypto-full"))]
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let err = self.machine_st.missing_feature_error(atom!("crypto-full"));
let exception = self.machine_st.error_form(err, stub1_gen());
self.machine_st.throw_exception(exception);
}
@@ -8409,152 +8409,111 @@ impl Machine {
pub(crate) fn crypto_curve_scalar_mult(&mut self) {
let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 4);
{
let scalar_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[2], stub_gen);
let point_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
let scalar_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[2], stub_gen);
let point_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
let mut point = secp256k1::Point::decode(&point_bytes).unwrap();
let scalar = secp256k1::Scalar::decode_reduce(&scalar_bytes);
point *= scalar;
let mut point = secp256k1::Point::decode(&point_bytes).unwrap();
let scalar = secp256k1::Scalar::decode_reduce(&scalar_bytes);
point *= scalar;
let uncompressed = step_or_resource_error!(
self.machine_st,
self.u8s_to_string(&point.encode_uncompressed())
);
let uncompressed = step_or_resource_error!(
self.machine_st,
self.u8s_to_string(&point.encode_uncompressed())
);
unify!(self.machine_st, self.machine_st.registers[4], uncompressed);
}
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
unify!(self.machine_st, self.machine_st.registers[4], uncompressed);
}
#[inline(always)]
pub(crate) fn ed25519_seed_to_public_key(&mut self) {
let stub_gen = || functor_stub(atom!("ed25519_seed_keypair"), 2);
{
let seed_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
let seed_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
let complete_string = step_or_resource_error!(
self.machine_st,
self.u8s_to_string(skey.public_key.encoded.as_ref())
);
let complete_string = step_or_resource_error!(
self.machine_st,
self.u8s_to_string(skey.public_key.encoded.as_ref())
);
unify!(
self.machine_st,
self.machine_st.registers[2],
complete_string
);
}
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
unify!(
self.machine_st,
self.machine_st.registers[2],
complete_string
);
}
#[inline(always)]
pub(crate) fn ed25519_sign_raw(&mut self) {
let stub_gen = || functor_stub(atom!("ed25519_sign"), 4);
{
let seed_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
let seed_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
let encoding = cell_as_atom!(self.deref_register(3));
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
let encoding = cell_as_atom!(self.deref_register(3));
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
let sig = skey.sign_raw(&data);
let sig_list = step_or_resource_error!(
self.machine_st,
sized_iter_to_heap_list(
&mut self.machine_st.heap,
sig.as_ref().len(),
sig.as_ref()
.iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
)
);
let sig = skey.sign_raw(&data);
let sig_list = step_or_resource_error!(
self.machine_st,
sized_iter_to_heap_list(
&mut self.machine_st.heap,
sig.as_ref().len(),
sig.as_ref()
.iter()
.map(|b| fixnum_as_cell!(Fixnum::build_with(*b)))
)
);
unify!(self.machine_st, self.machine_st.registers[4], sig_list);
}
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
unify!(self.machine_st, self.machine_st.registers[4], sig_list);
}
#[inline(always)]
pub(crate) fn ed25519_verify_raw(&mut self) {
let stub_gen = || functor_stub(atom!("ed25519_verify"), 4);
{
let key_bytes =
self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
let pkey = ed25519::PublicKey::decode(&key_bytes).unwrap();
let key_bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
let pkey = ed25519::PublicKey::decode(&key_bytes).unwrap();
let encoding = cell_as_atom!(self.deref_register(3));
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
let encoding = cell_as_atom!(self.deref_register(3));
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
let signature = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
let signature = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
self.machine_st.fail = !pkey.verify_raw(&signature, &data);
}
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
self.machine_st.fail = !pkey.verify_raw(&signature, &data);
}
#[inline(always)]
pub(crate) fn curve25519_scalar_mult(&mut self) {
let stub_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
{
let scalar_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
let point_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[2], stub_gen);
let scalar_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
let point_bytes = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[2], stub_gen);
let result = x25519::x25519(
&<[u8; 32]>::try_from(&point_bytes[..]).unwrap(),
&<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap(),
);
let result = x25519::x25519(
&<[u8; 32]>::try_from(&point_bytes[..]).unwrap(),
&<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap(),
);
let string = step_or_resource_error!(self.machine_st, self.u8s_to_string(&result[..]));
let string = step_or_resource_error!(self.machine_st, self.u8s_to_string(&result[..]));
unify!(self.machine_st, self.machine_st.registers[3], string);
}
{
let err = self.machine_st.missing_feature_error(atom!("crypto"));
let exception = self.machine_st.error_form(err, stub_gen());
self.machine_st.throw_exception(exception);
}
unify!(self.machine_st, self.machine_st.registers[3], string);
}
#[inline(always)]

View File

@@ -212,32 +212,34 @@ impl<T: RawBlockTraits> SerialOffsetTable<T> {
}
unsafe fn build_with(&mut self, value: T) -> usize {
let mut ptr;
unsafe {
let mut ptr;
loop {
ptr = self.block.alloc(size_of::<T>());
loop {
ptr = self.block.alloc(size_of::<T>());
if ptr.is_null() {
let new_block = self.block.grow_new().unwrap();
self.block = new_block;
} else {
break;
if ptr.is_null() {
let new_block = self.block.grow_new().unwrap();
self.block = new_block;
} else {
break;
}
}
}
ptr::write(ptr as *mut T, value);
// SAFETY: `ptr` was obtained from `self.block.alloc()`
self.block.get_offset(ptr)
ptr::write(ptr as *mut T, value);
// SAFETY: `ptr` was obtained from `self.block.alloc()`
self.block.get_offset(ptr)
}
}
#[inline]
unsafe fn lookup(&self, offset: usize) -> &T {
&*self.block.get_unchecked(offset).cast::<T>()
unsafe { &*self.block.get_unchecked(offset).cast::<T>() }
}
#[inline]
unsafe fn lookup_mut(&mut self, offset: usize) -> &mut T {
&mut *self.block.get_unchecked(offset).cast::<T>().cast_mut()
unsafe { &mut *self.block.get_unchecked(offset).cast::<T>().cast_mut() }
}
#[allow(clippy::wrong_self_convention)]

View File

@@ -129,23 +129,21 @@ impl WasmQueryState {
let mut error = None;
let mut to_drop = false;
match &mut self.inner {
Some(ref mut inner) => {
inner.with_query_state_mut(|query_state| match query_state.next() {
Some(Ok(leaf_answer)) => {
js_sys::Reflect::set(&ret, &"value".into(), &leaf_answer.into()).unwrap();
js_sys::Reflect::set(&ret, &"done".into(), &false.into()).unwrap();
}
Some(Err(error_term)) => {
let js_error = js_sys::Error::new("Prolog error");
js_error.set_cause(&error_term.into());
error = Some(js_error);
}
None => {
js_sys::Reflect::set(&ret, &"done".into(), &true.into()).unwrap();
to_drop = true;
}
})
}
Some(inner) => inner.with_query_state_mut(|query_state| match query_state.next() {
Some(Ok(leaf_answer)) => {
js_sys::Reflect::set(&ret, &"value".into(), &leaf_answer.into()).unwrap();
js_sys::Reflect::set(&ret, &"done".into(), &false.into()).unwrap();
}
Some(Err(error_term)) => {
let js_error = js_sys::Error::new("Prolog error");
js_error.set_cause(&error_term.into());
error = Some(js_error);
}
None => {
js_sys::Reflect::set(&ret, &"done".into(), &true.into()).unwrap();
to_drop = true;
}
}),
None => return Err(js_sys::Error::new("This query was already dropped").into()),
}