Merge branch 'master' into library-use-case
This commit is contained in:
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -63,10 +63,11 @@ jobs:
|
|||||||
|
|
||||||
# Build and test.
|
# Build and test.
|
||||||
- name: Build library
|
- name: Build library
|
||||||
run: cargo rustc --lib --target ${{ matrix.target }} ${{ matrix.args }} --verbose
|
continue-on-error: ${{ contains(matrix.target,'wasm32') }} # allow wasm builds to fail tests for now
|
||||||
|
run: cargo build --all-targets --target ${{ matrix.target }} ${{ matrix.args }} --verbose
|
||||||
- name: Test
|
- name: Test
|
||||||
continue-on-error: ${{ contains(matrix.target,'wasm32') }} # allow wasm builds to fail tests for now
|
continue-on-error: ${{ contains(matrix.target,'wasm32') }} # allow wasm builds to fail tests for now
|
||||||
run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all --verbose
|
run: cargo test --target ${{ matrix.target }} ${{ matrix.args }} --all
|
||||||
|
|
||||||
# On stable rust builds, build a binary and publish as a github actions
|
# On stable rust builds, build a binary and publish as a github actions
|
||||||
# artifact. These binaries could be useful for testing the pipeline but
|
# artifact. These binaries could be useful for testing the pipeline but
|
||||||
|
|||||||
908
Cargo.lock
generated
908
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@@ -71,6 +71,7 @@ bytes = "1"
|
|||||||
dashu = "0.4.0"
|
dashu = "0.4.0"
|
||||||
num-order = { version = "1.2.0" }
|
num-order = { version = "1.2.0" }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
ring = { version = "0.17.5", features = ["wasm32_unknown_unknown_js"] }
|
||||||
|
|
||||||
serde_json = "1.0.95"
|
serde_json = "1.0.95"
|
||||||
serde = "1.0.159"
|
serde = "1.0.159"
|
||||||
@@ -83,7 +84,7 @@ ctrlc = { version = "3.2.2", optional = true }
|
|||||||
rustyline = { version = "12.0.0", optional = true }
|
rustyline = { version = "12.0.0", optional = true }
|
||||||
native-tls = { version = "0.2.4", optional = true }
|
native-tls = { version = "0.2.4", optional = true }
|
||||||
warp = { version = "=0.3.5", features = ["tls"], optional = true }
|
warp = { version = "=0.3.5", features = ["tls"], optional = true }
|
||||||
reqwest = { version = "0.11.18", features = ["blocking"], optional = true }
|
reqwest = { version = "0.11.18", optional = true }
|
||||||
tokio = { version = "1.28.2", features = ["full"] }
|
tokio = { version = "1.28.2", features = ["full"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
@@ -104,12 +105,6 @@ serde-wasm-bindgen = "0.5"
|
|||||||
web-sys = { version = "0.3", features = ["Document", "Window", "Element", "Performance"] }
|
web-sys = { version = "0.3", features = ["Document", "Window", "Element", "Performance"] }
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_os = "wasi")'.dependencies]
|
|
||||||
ring-wasi = { version = "0.16.25" }
|
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "wasi"))'.dependencies]
|
|
||||||
ring = { version = "0.16.13" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "1.0.3"
|
assert_cmd = "1.0.3"
|
||||||
predicates-core = "1.0.2"
|
predicates-core = "1.0.2"
|
||||||
@@ -117,6 +112,7 @@ maplit = "1.0.2"
|
|||||||
serial_test = "2.0.0"
|
serial_test = "2.0.0"
|
||||||
iai-callgrind = { git = "https://github.com/iai-callgrind/iai-callgrind.git", rev = "c77bc3c83d7f4e976cc42d4597236a8db259e772" }
|
iai-callgrind = { git = "https://github.com/iai-callgrind/iai-callgrind.git", rev = "c77bc3c83d7f4e976cc42d4597236a8db259e772" }
|
||||||
criterion = "0.5.1"
|
criterion = "0.5.1"
|
||||||
|
trycmd = "0.14.19"
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "windows"))'.dev-dependencies]
|
[target.'cfg(not(target_os = "windows"))'.dev-dependencies]
|
||||||
pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] }
|
pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] }
|
||||||
|
|||||||
29
README.md
29
README.md
@@ -316,6 +316,35 @@ To quit Scryer Prolog, use the standard predicate `halt/0`:
|
|||||||
?- halt.
|
?- halt.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Starting Scryer Prolog
|
||||||
|
|
||||||
|
Scryer Prolog can be started from the command line by specifying
|
||||||
|
options, files and additional arguments. All components are optional:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
scryer-prolog [OPTIONS] [FILES] [-- ARGUMENTS]
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The supported options are:
|
||||||
|
|
||||||
|
```
|
||||||
|
-h, --help Display help message
|
||||||
|
-v, --version Print version information and exit
|
||||||
|
-g, --goal GOAL Run the query GOAL after consulting files
|
||||||
|
-f Fast startup. Do not load initialization file (~/.scryerrc)
|
||||||
|
--no-add-history Prevent adding input to history file (~/.scryer_history)
|
||||||
|
```
|
||||||
|
|
||||||
|
All specified Prolog files are consulted.
|
||||||
|
|
||||||
|
After Prolog files, application-specific arguments can be specified on
|
||||||
|
the command line. These arguments can be accessed from within Prolog
|
||||||
|
applications with the predicate `argv/1`, which yields the list
|
||||||
|
of arguments represented as strings.
|
||||||
|
|
||||||
|
Prolog files can also be turned into *shell scripts* as explained in
|
||||||
|
https://github.com/mthom/scryer-prolog/issues/2170#issuecomment-1821713993.
|
||||||
|
|
||||||
### Dynamic operators
|
### Dynamic operators
|
||||||
|
|
||||||
Scryer supports dynamic operators. Using the built-in
|
Scryer supports dynamic operators. Using the built-in
|
||||||
|
|||||||
@@ -511,18 +511,12 @@ enum SystemClauseType {
|
|||||||
#[cfg(feature = "crypto-full")]
|
#[cfg(feature = "crypto-full")]
|
||||||
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
|
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
|
||||||
CryptoDataDecrypt,
|
CryptoDataDecrypt,
|
||||||
#[cfg(feature = "crypto-full")]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign_raw")))]
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
|
Ed25519SignRaw,
|
||||||
Ed25519Sign,
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify_raw")))]
|
||||||
#[cfg(feature = "crypto-full")]
|
Ed25519VerifyRaw,
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_seed_to_public_key")))]
|
||||||
Ed25519Verify,
|
Ed25519SeedToPublicKey,
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
|
|
||||||
Ed25519NewKeyPair,
|
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
|
|
||||||
Ed25519KeyPairPublicKey,
|
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
|
||||||
FirstNonOctet,
|
FirstNonOctet,
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
|
||||||
@@ -610,6 +604,8 @@ enum SystemClauseType {
|
|||||||
KeySortWithConstantVarOrdering,
|
KeySortWithConstantVarOrdering,
|
||||||
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
|
#[strum_discriminants(strum(props(Arity = "0", Name = "$inference_limit_exceeded")))]
|
||||||
InferenceLimitExceeded,
|
InferenceLimitExceeded,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$argv")))]
|
||||||
|
Argv,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,8 +792,8 @@ enum InstructionTemplate {
|
|||||||
#[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))]
|
#[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))]
|
||||||
InstallVerifyAttr,
|
InstallVerifyAttr,
|
||||||
// call verify_attrs.
|
// call verify_attrs.
|
||||||
#[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "verify_attr_interrupt")))]
|
||||||
VerifyAttrInterrupt,
|
VerifyAttrInterrupt(usize),
|
||||||
// procedures
|
// procedures
|
||||||
CallClause(ClauseType, usize, usize, bool, bool), // ClauseType,
|
CallClause(ClauseType, usize, usize, bool, bool), // ClauseType,
|
||||||
// arity,
|
// arity,
|
||||||
@@ -1157,6 +1153,33 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
pub type CodeDeque = VecDeque<Instruction>;
|
pub type CodeDeque = VecDeque<Instruction>;
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
|
#[inline]
|
||||||
|
pub fn registers(&self) -> Vec<RegType> {
|
||||||
|
match self {
|
||||||
|
&Instruction::GetConstant(_, _, r) => vec![r],
|
||||||
|
&Instruction::GetList(_, r) => vec![r],
|
||||||
|
&Instruction::GetPartialString(_, _, r, _) => vec![r],
|
||||||
|
&Instruction::GetStructure(_, _, _, r) => vec![r],
|
||||||
|
&Instruction::GetVariable(r, t) => vec![r, temp_v!(t)],
|
||||||
|
&Instruction::GetValue(r, t) => vec![r, temp_v!(t)],
|
||||||
|
&Instruction::UnifyLocalValue(r) => vec![r],
|
||||||
|
&Instruction::UnifyVariable(r) => vec![r],
|
||||||
|
&Instruction::PutConstant(_, _, r) => vec![r],
|
||||||
|
&Instruction::PutList(_, r) => vec![r],
|
||||||
|
&Instruction::PutPartialString(_, _, r, _) => vec![r],
|
||||||
|
&Instruction::PutStructure(_, _, r) => vec![r],
|
||||||
|
&Instruction::PutValue(r, t) => vec![r, temp_v!(t)],
|
||||||
|
&Instruction::PutVariable(r, t) => vec![r, temp_v!(t)],
|
||||||
|
&Instruction::SetLocalValue(r) => vec![r],
|
||||||
|
&Instruction::SetVariable(r) => vec![r],
|
||||||
|
&Instruction::SetValue(r) => vec![r],
|
||||||
|
&Instruction::GetLevel(r) => vec![r],
|
||||||
|
&Instruction::GetPrevLevel(r) => vec![r],
|
||||||
|
&Instruction::GetCutPoint(r) => vec![r],
|
||||||
|
_ => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec<IndexingLine>> {
|
pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec<IndexingLine>> {
|
||||||
match self {
|
match self {
|
||||||
@@ -1199,7 +1222,10 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
Instruction::SetLocalValue(..) |
|
Instruction::SetLocalValue(..) |
|
||||||
Instruction::SetVariable(..) |
|
Instruction::SetVariable(..) |
|
||||||
Instruction::SetValue(..) |
|
Instruction::SetValue(..) |
|
||||||
Instruction::SetVoid(..))
|
Instruction::SetVoid(..) |
|
||||||
|
Instruction::GetLevel(..) |
|
||||||
|
Instruction::GetPrevLevel(..) |
|
||||||
|
Instruction::GetCutPoint(..))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enqueue_functors(
|
pub fn enqueue_functors(
|
||||||
@@ -1244,8 +1270,8 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::InstallVerifyAttr => {
|
&Instruction::InstallVerifyAttr => {
|
||||||
functor!(atom!("install_verify_attr"))
|
functor!(atom!("install_verify_attr"))
|
||||||
}
|
}
|
||||||
&Instruction::VerifyAttrInterrupt => {
|
&Instruction::VerifyAttrInterrupt(arity) => {
|
||||||
functor!(atom!("verify_attr_interrupt"))
|
functor!(atom!("verify_attr_interrupt"), [fixnum(arity)])
|
||||||
}
|
}
|
||||||
&Instruction::DynamicElse(birth, death, next_or_fail) => {
|
&Instruction::DynamicElse(birth, death, next_or_fail) => {
|
||||||
match (death, next_or_fail) {
|
match (death, next_or_fail) {
|
||||||
@@ -1874,18 +1900,18 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallFlushTermQueue |
|
&Instruction::CallFlushTermQueue |
|
||||||
&Instruction::CallRemoveModuleExports |
|
&Instruction::CallRemoveModuleExports |
|
||||||
&Instruction::CallAddNonCountedBacktracking |
|
&Instruction::CallAddNonCountedBacktracking |
|
||||||
&Instruction::CallPopCount => {
|
&Instruction::CallPopCount |
|
||||||
|
&Instruction::CallArgv |
|
||||||
|
&Instruction::CallEd25519SignRaw |
|
||||||
|
&Instruction::CallEd25519VerifyRaw |
|
||||||
|
&Instruction::CallEd25519SeedToPublicKey => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
#[cfg(feature = "crypto-full")]
|
#[cfg(feature = "crypto-full")]
|
||||||
&Instruction::CallCryptoDataEncrypt |
|
&Instruction::CallCryptoDataEncrypt |
|
||||||
&Instruction::CallCryptoDataDecrypt |
|
&Instruction::CallCryptoDataDecrypt => {
|
||||||
&Instruction::CallEd25519Sign |
|
|
||||||
&Instruction::CallEd25519Verify |
|
|
||||||
&Instruction::CallEd25519NewKeyPair |
|
|
||||||
&Instruction::CallEd25519KeyPairPublicKey => {
|
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
@@ -2110,18 +2136,18 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteFlushTermQueue |
|
&Instruction::ExecuteFlushTermQueue |
|
||||||
&Instruction::ExecuteRemoveModuleExports |
|
&Instruction::ExecuteRemoveModuleExports |
|
||||||
&Instruction::ExecuteAddNonCountedBacktracking |
|
&Instruction::ExecuteAddNonCountedBacktracking |
|
||||||
&Instruction::ExecutePopCount => {
|
&Instruction::ExecutePopCount |
|
||||||
|
&Instruction::ExecuteArgv |
|
||||||
|
&Instruction::ExecuteEd25519SignRaw |
|
||||||
|
&Instruction::ExecuteEd25519VerifyRaw |
|
||||||
|
&Instruction::ExecuteEd25519SeedToPublicKey => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
#[cfg(feature = "crypto-full")]
|
#[cfg(feature = "crypto-full")]
|
||||||
&Instruction::ExecuteCryptoDataEncrypt |
|
&Instruction::ExecuteCryptoDataEncrypt |
|
||||||
&Instruction::ExecuteCryptoDataDecrypt |
|
&Instruction::ExecuteCryptoDataDecrypt => {
|
||||||
&Instruction::ExecuteEd25519Sign |
|
|
||||||
&Instruction::ExecuteEd25519Verify |
|
|
||||||
&Instruction::ExecuteEd25519NewKeyPair |
|
|
||||||
&Instruction::ExecuteEd25519KeyPairPublicKey => {
|
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,40 +53,5 @@ pub(crate) trait Allocator {
|
|||||||
fn reset_contents(&mut self);
|
fn reset_contents(&mut self);
|
||||||
|
|
||||||
fn advance_arg(&mut self);
|
fn advance_arg(&mut self);
|
||||||
|
|
||||||
/*
|
|
||||||
fn bindings(&self) -> &AllocVarDict;
|
|
||||||
fn bindings_mut(&mut self) -> &mut AllocVarDict;
|
|
||||||
fn take_bindings(self) -> AllocVarDict;
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn max_reg_allocated(&self) -> usize;
|
fn max_reg_allocated(&self) -> usize;
|
||||||
|
|
||||||
// TODO: wha.. why?? grrr. it drains the VarStatus data from vs (which it owns!)
|
|
||||||
// into self.bindings and perm_vs after all is computed (i.e. vs.populate_restricting_sets()
|
|
||||||
// and vs.set_perm_vals(has_deep_cut) have both been called).
|
|
||||||
/*
|
|
||||||
fn drain_var_data<'a>(
|
|
||||||
&mut self,
|
|
||||||
vs: VariableFixtures,
|
|
||||||
num_of_chunks: usize,
|
|
||||||
) -> VariableFixtures {
|
|
||||||
let mut perm_vs = VariableFixtures::new();
|
|
||||||
|
|
||||||
for (var, var_status) in vs.into_iter() {
|
|
||||||
match var_status {
|
|
||||||
VarStatus::Temp(chunk_num, tvd) => {
|
|
||||||
self.bindings_mut()
|
|
||||||
.insert(var.clone(), VarAlloc::Temp(chunk_num, 0, tvd));
|
|
||||||
}
|
|
||||||
VarStatus::Perm(_) => {
|
|
||||||
self.bindings_mut().insert(var.clone(), VarAlloc::Perm(0));
|
|
||||||
perm_vs.insert(var, var_status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
perm_vs
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -821,9 +821,9 @@ impl AllocSlab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn payload_offset<T>(&self) -> *mut T {
|
fn payload_offset<T>(&self) -> *mut T {
|
||||||
let mut ptr = (self as *const AllocSlab) as usize;
|
// This looks really scary, should this method be marked as unsafe?
|
||||||
ptr += mem::size_of::<AllocSlab>();
|
// Also, this seems to cause UB.
|
||||||
ptr as *mut T
|
unsafe { (self as *const AllocSlab).add(1) as *mut T }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,6 +864,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn heap_cell_value_const_cast() {
|
fn heap_cell_value_const_cast() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
@@ -907,6 +908,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on arena.rs UB")]
|
||||||
fn heap_put_literal_tests() {
|
fn heap_put_literal_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ impl Atom {
|
|||||||
} else if let Some(ptr) = self.as_ptr() {
|
} else if let Some(ptr) = self.as_ptr() {
|
||||||
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| {
|
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| {
|
||||||
let header =
|
let header =
|
||||||
|
// Miri seems to hit this line a lot
|
||||||
unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
|
unsafe { ptr::read::<AtomHeader>(ptr as *const u8 as *const AtomHeader) };
|
||||||
let len = header.len() as usize;
|
let len = header.len() as usize;
|
||||||
let buf = unsafe { (ptr as *const u8).add(mem::size_of::<AtomHeader>()) };
|
let buf = unsafe { (ptr as *const u8).add(mem::size_of::<AtomHeader>()) };
|
||||||
@@ -265,7 +266,7 @@ impl Atom {
|
|||||||
|
|
||||||
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
|
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
|
||||||
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
|
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
|
||||||
let str_ptr = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
|
let str_ptr = ptr.add(mem::size_of::<AtomHeader>());
|
||||||
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr, string.len());
|
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr, string.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ fn main() -> std::process::ExitCode {
|
|||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let mut wam = machine::Machine::new(Default::default());
|
let mut wam = machine::Machine::new(Default::default());
|
||||||
wam.run_top_level(atom!("$toplevel"), (atom!("$repl"), 1))
|
wam.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 0))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -860,6 +860,9 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
self.marker.mark_safe_var_unconditionally(var_num);
|
self.marker.mark_safe_var_unconditionally(var_num);
|
||||||
compile_expr!(self, &terms[1], term_loc, code)
|
compile_expr!(self, &terms[1], term_loc, code)
|
||||||
} else {
|
} else {
|
||||||
|
self.marker
|
||||||
|
.mark_anon_var::<QueryInstruction>(Level::Shallow, term_loc, code);
|
||||||
|
|
||||||
if let Term::Var(ref vr, ref var) = &terms[1] {
|
if let Term::Var(ref vr, ref var) = &terms[1] {
|
||||||
let var_num = var.to_var_num().unwrap();
|
let var_num = var.to_var_num().unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -604,16 +604,9 @@ impl DebrayAllocator {
|
|||||||
Target::unsafe_argument_to_value(r, arg_c)
|
Target::unsafe_argument_to_value(r, arg_c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VarAlloc::Temp { ref mut safety, .. } => {
|
VarAlloc::Temp { .. } => {
|
||||||
if self
|
debug_assert!(matches!(r, RegType::Temp(_)));
|
||||||
.branch_stack
|
|
||||||
.safety_unneeded_in_branch(safety, &branch_designator)
|
|
||||||
{
|
|
||||||
Target::argument_to_value(r, arg_c)
|
Target::argument_to_value(r, arg_c)
|
||||||
} else {
|
|
||||||
*safety = VarSafetyStatus::GloballyUnneeded;
|
|
||||||
Target::unsafe_argument_to_value(r, arg_c)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> {
|
|||||||
let var_value = self.heap[h];
|
let var_value = self.heap[h];
|
||||||
self.heap[h].set_mark_bit(self.mark_phase);
|
self.heap[h].set_mark_bit(self.mark_phase);
|
||||||
|
|
||||||
if !(self.heap[h].is_var() && self.heap[h].get_value() as usize == h) {
|
if var_value.get_mark_bit() || !(self.heap[h].is_var() && self.heap[h].get_value() as usize == h) {
|
||||||
self.iter_stack.push(var_value);
|
self.iter_stack.push(var_value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -125,13 +125,14 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = self.heap[h+1];
|
|
||||||
|
|
||||||
self.heap[h].set_mark_bit(self.mark_phase);
|
self.heap[h].set_mark_bit(self.mark_phase);
|
||||||
self.heap[h+1].set_mark_bit(self.mark_phase);
|
|
||||||
|
|
||||||
|
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
||||||
|
let value = self.heap[h+1];
|
||||||
|
self.heap[h+1].set_mark_bit(self.mark_phase);
|
||||||
self.iter_stack.push(value);
|
self.iter_stack.push(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -685,6 +686,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "it takes too long to run")]
|
||||||
fn heap_stackless_iter_tests() {
|
fn heap_stackless_iter_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
@@ -1756,6 +1758,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")]
|
||||||
fn heap_stackful_iter_tests() {
|
fn heap_stackful_iter_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
@@ -2348,6 +2351,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")]
|
||||||
fn heap_stackful_post_order_iter() {
|
fn heap_stackful_post_order_iter() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
@@ -2831,6 +2835,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")]
|
||||||
fn heap_stackless_post_order_iter() {
|
fn heap_stackless_post_order_iter() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
|||||||
@@ -1444,7 +1444,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
|
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
|
||||||
let (ip, port) = if let Ok(addr) = tcp_listener.local_addr() {
|
let (ip, port) = if let Ok(addr) = tcp_listener.local_addr() {
|
||||||
(addr.ip(), addr.port())
|
(addr.ip(), addr.port())
|
||||||
@@ -1727,6 +1726,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
(ArenaHeaderTag::Stream, stream) => {
|
(ArenaHeaderTag::Stream, stream) => {
|
||||||
self.print_stream(stream, max_depth);
|
self.print_stream(stream, max_depth);
|
||||||
}
|
}
|
||||||
|
(ArenaHeaderTag::TcpListener, listener) => {
|
||||||
|
self.print_tcp_listener(&*listener, max_depth);
|
||||||
|
}
|
||||||
(ArenaHeaderTag::Dropped, _value) => {
|
(ArenaHeaderTag::Dropped, _value) => {
|
||||||
self.print_impromptu_atom(atom!("$dropped_value"));
|
self.print_impromptu_atom(atom!("$dropped_value"));
|
||||||
}
|
}
|
||||||
@@ -1833,6 +1835,7 @@ mod tests {
|
|||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn term_printing_tests() {
|
fn term_printing_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
:- module(atts, [op(1199, fx, attribute),
|
:- module(atts, [op(1199, fx, attribute),
|
||||||
call_residue_vars/2,
|
|
||||||
term_attributed_variables/2]).
|
term_attributed_variables/2]).
|
||||||
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(error)).
|
||||||
:- use_module(library(terms)).
|
:- use_module(library(terms)).
|
||||||
|
|
||||||
/* represent the list of attributes belonging to a variable,
|
/* represent the list of attributes belonging to a variable,
|
||||||
@@ -110,12 +110,5 @@ user:goal_expansion(Term, M:get_atts(Var, Attr)) :-
|
|||||||
nonvar(Term),
|
nonvar(Term),
|
||||||
Term = get_atts(Var, M, Attr).
|
Term = get_atts(Var, M, Attr).
|
||||||
|
|
||||||
:- meta_predicate call_residue_vars(0, ?).
|
|
||||||
|
|
||||||
call_residue_vars(Goal, Vars) :-
|
|
||||||
'$get_attr_var_queue_delim'(B),
|
|
||||||
call(Goal),
|
|
||||||
'$get_attr_var_queue_beyond'(B, Vars).
|
|
||||||
|
|
||||||
term_attributed_variables(Term, Vars) :-
|
term_attributed_variables(Term, Vars) :-
|
||||||
'$term_attributed_variables'(Term, Vars).
|
'$term_attributed_variables'(Term, Vars).
|
||||||
|
|||||||
@@ -1239,7 +1239,10 @@ call_retract_helper(Head, Body, P, Module) :-
|
|||||||
; ClauseQualifier = Module
|
; ClauseQualifier = Module
|
||||||
),
|
),
|
||||||
ClauseQualifier:'$clause'(Head, Body),
|
ClauseQualifier:'$clause'(Head, Body),
|
||||||
'$get_clause_p'(Head, P, Module).
|
% ensure '$get_clause_p'/3 is not the last clause so it can
|
||||||
|
% recover the choice point of '$clause' if necessary.
|
||||||
|
'$get_clause_p'(Head, P, Module),
|
||||||
|
true.
|
||||||
|
|
||||||
call_retract(Head, Body, Name, Arity, Module) :-
|
call_retract(Head, Body, Name, Arity, Module) :-
|
||||||
findall(P, builtins:call_retract_helper(Head, Body, P, Module), Ps),
|
findall(P, builtins:call_retract_helper(Head, Body, P, Module), Ps),
|
||||||
|
|||||||
@@ -189,18 +189,18 @@ A _Boolean expression_ is one of:
|
|||||||
| `1` | true |
|
| `1` | true |
|
||||||
| _variable_ | unknown truth value |
|
| _variable_ | unknown truth value |
|
||||||
| _atom_ | universally quantified variable |
|
| _atom_ | universally quantified variable |
|
||||||
| ~ _Expr_ | logical NOT |
|
| `~` _Expr_ | logical NOT |
|
||||||
| _Expr_ + _Expr_ | logical OR |
|
| _Expr_ `+` _Expr_ | logical OR |
|
||||||
| _Expr_ * _Expr_ | logical AND |
|
| _Expr_ `*` _Expr_ | logical AND |
|
||||||
| _Expr_ # _Expr_ | exclusive OR |
|
| _Expr_ `#` _Expr_ | exclusive OR |
|
||||||
| _Var_ ^ _Expr_ | existential quantification |
|
| _Var_ `^` _Expr_ | existential quantification |
|
||||||
| _Expr_ =:= _Expr_ | equality |
|
| _Expr_ `=:=` _Expr_ | equality |
|
||||||
| _Expr_ =\= _Expr_ | disequality (same as #) |
|
| _Expr_ `=\=` _Expr_ | disequality (same as #) |
|
||||||
| _Expr_ =< _Expr_ | less or equal (implication) |
|
| _Expr_ `=<` _Expr_ | less or equal (implication) |
|
||||||
| _Expr_ >= _Expr_ | greater or equal |
|
| _Expr_ `>=` _Expr_ | greater or equal |
|
||||||
| _Expr_ < _Expr_ | less than |
|
| _Expr_ `<` _Expr_ | less than |
|
||||||
| _Expr_ > _Expr_ | greater than |
|
| _Expr_ `>` _Expr_ | greater than |
|
||||||
| card(Is,Exprs) | cardinality constraint (_see below_) |
|
| `card(Is,Exprs)` | cardinality constraint (_see below_) |
|
||||||
| `+(Exprs)` | n-fold disjunction (_see below_) |
|
| `+(Exprs)` | n-fold disjunction (_see below_) |
|
||||||
| `*(Exprs)` | n-fold conjunction (_see below_) |
|
| `*(Exprs)` | n-fold conjunction (_see below_) |
|
||||||
|
|
||||||
@@ -1251,7 +1251,7 @@ bdd_restriction_(Node, VI, Value, Res) -->
|
|||||||
node_id(Node, ID) },
|
node_id(Node, ID) },
|
||||||
( { I0 =:= VI } ->
|
( { I0 =:= VI } ->
|
||||||
( { Value =:= 0 } -> { Res = Low }
|
( { Value =:= 0 } -> { Res = Low }
|
||||||
; { Value =:= 1 } -> { Res = High }
|
; { Res = High }
|
||||||
)
|
)
|
||||||
; { I0 > VI } -> { Res = Node }
|
; { I0 > VI } -> { Res = Node }
|
||||||
; state(G0), { get_assoc(ID, G0, Res) } -> []
|
; state(G0), { get_assoc(ID, G0, Res) } -> []
|
||||||
|
|||||||
246
src/lib/clpz.pl
246
src/lib/clpz.pl
@@ -3,7 +3,7 @@
|
|||||||
Author: Markus Triska
|
Author: Markus Triska
|
||||||
E-mail: triska@metalevel.at
|
E-mail: triska@metalevel.at
|
||||||
WWW: https://www.metalevel.at
|
WWW: https://www.metalevel.at
|
||||||
Copyright (C): 2016-2023 Markus Triska
|
Copyright (C): 2016-2024 Markus Triska
|
||||||
|
|
||||||
This library provides CLP(ℤ):
|
This library provides CLP(ℤ):
|
||||||
|
|
||||||
@@ -1015,6 +1015,9 @@ X in inf..sup.
|
|||||||
needed to schedule the propagators!
|
needed to schedule the propagators!
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
:- meta_predicate(duophrase(4, ?, ?)).
|
||||||
|
:- meta_predicate(duophrase(4, ?, ?, ?, ?)).
|
||||||
|
|
||||||
duophrase(NT, As, Bs) :-
|
duophrase(NT, As, Bs) :-
|
||||||
duophrase(NT, As, [], Bs, []).
|
duophrase(NT, As, [], Bs, []).
|
||||||
|
|
||||||
@@ -1735,7 +1738,7 @@ intervals_to_domain(Is, D) :-
|
|||||||
% _Lower_ must be an integer or the atom *inf*, which
|
% _Lower_ must be an integer or the atom *inf*, which
|
||||||
% denotes negative infinity. _Upper_ must be an integer or
|
% denotes negative infinity. _Upper_ must be an integer or
|
||||||
% the atom *sup*, which denotes positive infinity.
|
% the atom *sup*, which denotes positive infinity.
|
||||||
% * Domain1 \/ Domain2
|
% * Domain1 `\/` Domain2
|
||||||
% The union of Domain1 and Domain2.
|
% The union of Domain1 and Domain2.
|
||||||
|
|
||||||
Var in Dom :- clpz_in(Var, Dom).
|
Var in Dom :- clpz_in(Var, Dom).
|
||||||
@@ -2409,22 +2412,22 @@ sum_finite_domains([C|Cs], [V|Vs], Inf0, Sup0, Inf, Sup) ++>
|
|||||||
),
|
),
|
||||||
sum_finite_domains(Cs, Vs, Inf2, Sup2, Inf, Sup).
|
sum_finite_domains(Cs, Vs, Inf2, Sup2, Inf, Sup).
|
||||||
|
|
||||||
remove_dist_upper_lower([], _, _, _).
|
remove_dist_upper_lower([], _, _, _) --> [].
|
||||||
remove_dist_upper_lower([C|Cs], [V|Vs], D1, D2) :-
|
remove_dist_upper_lower([C|Cs], [V|Vs], D1, D2) -->
|
||||||
( fd_get(V, VD, VPs) ->
|
( { fd_get(V, VD, VPs) } ->
|
||||||
( C < 0 ->
|
( C < 0 ->
|
||||||
domain_supremum(VD, n(Sup)),
|
{ domain_supremum(VD, n(Sup)),
|
||||||
L is Sup + D1//C,
|
L is Sup + D1//C,
|
||||||
domain_remove_smaller_than(VD, L, VD1),
|
domain_remove_smaller_than(VD, L, VD1),
|
||||||
domain_infimum(VD1, n(Inf)),
|
domain_infimum(VD1, n(Inf)),
|
||||||
G is Inf - D2//C,
|
G is Inf - D2//C,
|
||||||
domain_remove_greater_than(VD1, G, VD2)
|
domain_remove_greater_than(VD1, G, VD2) }
|
||||||
; domain_infimum(VD, n(Inf)),
|
; { domain_infimum(VD, n(Inf)),
|
||||||
G is Inf + D1//C,
|
G is Inf + D1//C,
|
||||||
domain_remove_greater_than(VD, G, VD1),
|
domain_remove_greater_than(VD, G, VD1),
|
||||||
domain_supremum(VD1, n(Sup)),
|
domain_supremum(VD1, n(Sup)),
|
||||||
L is Sup - D2//C,
|
L is Sup - D2//C,
|
||||||
domain_remove_smaller_than(VD1, L, VD2)
|
domain_remove_smaller_than(VD1, L, VD2) }
|
||||||
),
|
),
|
||||||
fd_put(V, VD2, VPs)
|
fd_put(V, VD2, VPs)
|
||||||
; true
|
; true
|
||||||
@@ -2432,16 +2435,16 @@ remove_dist_upper_lower([C|Cs], [V|Vs], D1, D2) :-
|
|||||||
remove_dist_upper_lower(Cs, Vs, D1, D2).
|
remove_dist_upper_lower(Cs, Vs, D1, D2).
|
||||||
|
|
||||||
|
|
||||||
remove_dist_upper_leq([], _, _).
|
remove_dist_upper_leq([], _, _) --> [].
|
||||||
remove_dist_upper_leq([C|Cs], [V|Vs], D1) :-
|
remove_dist_upper_leq([C|Cs], [V|Vs], D1) -->
|
||||||
( fd_get(V, VD, VPs) ->
|
( { fd_get(V, VD, VPs) } ->
|
||||||
( C < 0 ->
|
( C < 0 ->
|
||||||
domain_supremum(VD, n(Sup)),
|
{ domain_supremum(VD, n(Sup)),
|
||||||
L is Sup + D1//C,
|
L is Sup + D1//C,
|
||||||
domain_remove_smaller_than(VD, L, VD1)
|
domain_remove_smaller_than(VD, L, VD1) }
|
||||||
; domain_infimum(VD, n(Inf)),
|
; { domain_infimum(VD, n(Inf)),
|
||||||
G is Inf + D1//C,
|
G is Inf + D1//C,
|
||||||
domain_remove_greater_than(VD, G, VD1)
|
domain_remove_greater_than(VD, G, VD1) }
|
||||||
),
|
),
|
||||||
fd_put(V, VD1, VPs)
|
fd_put(V, VD1, VPs)
|
||||||
; true
|
; true
|
||||||
@@ -2449,18 +2452,18 @@ remove_dist_upper_leq([C|Cs], [V|Vs], D1) :-
|
|||||||
remove_dist_upper_leq(Cs, Vs, D1).
|
remove_dist_upper_leq(Cs, Vs, D1).
|
||||||
|
|
||||||
|
|
||||||
remove_dist_upper([], _).
|
remove_dist_upper([], _) --> [].
|
||||||
remove_dist_upper([C*V|CVs], D) :-
|
remove_dist_upper([C*V|CVs], D) -->
|
||||||
( fd_get(V, VD, VPs) ->
|
( { fd_get(V, VD, VPs) } ->
|
||||||
( C < 0 ->
|
( C < 0 ->
|
||||||
( domain_supremum(VD, n(Sup)) ->
|
( { domain_supremum(VD, n(Sup)) } ->
|
||||||
L is Sup + D//C,
|
{ L is Sup + D//C,
|
||||||
domain_remove_smaller_than(VD, L, VD1)
|
domain_remove_smaller_than(VD, L, VD1) }
|
||||||
; VD1 = VD
|
; VD1 = VD
|
||||||
)
|
)
|
||||||
; ( domain_infimum(VD, n(Inf)) ->
|
; ( { domain_infimum(VD, n(Inf)) } ->
|
||||||
G is Inf + D//C,
|
{ G is Inf + D//C,
|
||||||
domain_remove_greater_than(VD, G, VD1)
|
domain_remove_greater_than(VD, G, VD1) }
|
||||||
; VD1 = VD
|
; VD1 = VD
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@@ -2469,18 +2472,18 @@ remove_dist_upper([C*V|CVs], D) :-
|
|||||||
),
|
),
|
||||||
remove_dist_upper(CVs, D).
|
remove_dist_upper(CVs, D).
|
||||||
|
|
||||||
remove_dist_lower([], _).
|
remove_dist_lower([], _) --> [].
|
||||||
remove_dist_lower([C*V|CVs], D) :-
|
remove_dist_lower([C*V|CVs], D) -->
|
||||||
( fd_get(V, VD, VPs) ->
|
( { fd_get(V, VD, VPs) } ->
|
||||||
( C < 0 ->
|
( C < 0 ->
|
||||||
( domain_infimum(VD, n(Inf)) ->
|
( { domain_infimum(VD, n(Inf)) } ->
|
||||||
G is Inf - D//C,
|
{ G is Inf - D//C,
|
||||||
domain_remove_greater_than(VD, G, VD1)
|
domain_remove_greater_than(VD, G, VD1) }
|
||||||
; VD1 = VD
|
; VD1 = VD
|
||||||
)
|
)
|
||||||
; ( domain_supremum(VD, n(Sup)) ->
|
; ( { domain_supremum(VD, n(Sup)) } ->
|
||||||
L is Sup - D//C,
|
{ L is Sup - D//C,
|
||||||
domain_remove_smaller_than(VD, L, VD1)
|
domain_remove_smaller_than(VD, L, VD1) }
|
||||||
; VD1 = VD
|
; VD1 = VD
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@@ -2489,26 +2492,26 @@ remove_dist_lower([C*V|CVs], D) :-
|
|||||||
),
|
),
|
||||||
remove_dist_lower(CVs, D).
|
remove_dist_lower(CVs, D).
|
||||||
|
|
||||||
remove_upper([], _).
|
remove_upper([], _) --> [].
|
||||||
remove_upper([C*X|CXs], Max) :-
|
remove_upper([C*X|CXs], Max) -->
|
||||||
( fd_get(X, XD, XPs) ->
|
( { fd_get(X, XD, XPs) } ->
|
||||||
D is Max//C,
|
D is Max//C,
|
||||||
( C < 0 ->
|
( C < 0 ->
|
||||||
domain_remove_smaller_than(XD, D, XD1)
|
{ domain_remove_smaller_than(XD, D, XD1) }
|
||||||
; domain_remove_greater_than(XD, D, XD1)
|
; { domain_remove_greater_than(XD, D, XD1) }
|
||||||
),
|
),
|
||||||
fd_put(X, XD1, XPs)
|
fd_put(X, XD1, XPs)
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
remove_upper(CXs, Max).
|
remove_upper(CXs, Max).
|
||||||
|
|
||||||
remove_lower([], _).
|
remove_lower([], _) --> [].
|
||||||
remove_lower([C*X|CXs], Min) :-
|
remove_lower([C*X|CXs], Min) -->
|
||||||
( fd_get(X, XD, XPs) ->
|
( { fd_get(X, XD, XPs) } ->
|
||||||
D is -Min//C,
|
D is -Min//C,
|
||||||
( C < 0 ->
|
( C < 0 ->
|
||||||
domain_remove_greater_than(XD, D, XD1)
|
{ domain_remove_greater_than(XD, D, XD1) }
|
||||||
; domain_remove_smaller_than(XD, D, XD1)
|
; { domain_remove_smaller_than(XD, D, XD1) }
|
||||||
),
|
),
|
||||||
fd_put(X, XD1, XPs)
|
fd_put(X, XD1, XPs)
|
||||||
; true
|
; true
|
||||||
@@ -2747,20 +2750,24 @@ propagator_init_trigger(Vs, P) :-
|
|||||||
prop_init(Prop, V) :- init_propagator(V, Prop).
|
prop_init(Prop, V) :- init_propagator(V, Prop).
|
||||||
|
|
||||||
geq(A, B) :-
|
geq(A, B) :-
|
||||||
( fd_get(A, AD, APs) ->
|
new_queue(Q),
|
||||||
domain_infimum(AD, AI),
|
phrase((geq(A, B),do_queue), [Q], _).
|
||||||
( fd_get(B, BD, _) ->
|
|
||||||
domain_supremum(BD, BS),
|
geq(A, B) -->
|
||||||
( AI cis_geq BS -> true
|
( { fd_get(A, AD, APs) } ->
|
||||||
; propagator_init_trigger(pgeq(A,B))
|
{ domain_infimum(AD, AI) },
|
||||||
|
( { fd_get(B, BD, _) } ->
|
||||||
|
{ domain_supremum(BD, BS) },
|
||||||
|
( { AI cis_geq BS } -> true
|
||||||
|
; { propagator_init_trigger(pgeq(A,B)) }
|
||||||
)
|
)
|
||||||
; ( AI cis_geq n(B) -> true
|
; ( { AI cis_geq n(B) } -> true
|
||||||
; domain_remove_smaller_than(AD, B, AD1),
|
; { domain_remove_smaller_than(AD, B, AD1) },
|
||||||
fd_put(A, AD1, APs)
|
fd_put(A, AD1, APs)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
; fd_get(B, BD, BPs) ->
|
; { fd_get(B, BD, BPs) } ->
|
||||||
domain_remove_greater_than(BD, A, BD1),
|
{ domain_remove_greater_than(BD, A, BD1) },
|
||||||
fd_put(B, BD1, BPs)
|
fd_put(B, BD1, BPs)
|
||||||
; A >= B
|
; A >= B
|
||||||
).
|
).
|
||||||
@@ -4164,6 +4171,7 @@ var(V) --> { var(V) }.
|
|||||||
ground(T) --> { ground(T) }.
|
ground(T) --> { ground(T) }.
|
||||||
|
|
||||||
true --> [].
|
true --> [].
|
||||||
|
false --> { false }.
|
||||||
|
|
||||||
X >= Y --> { X >= Y }.
|
X >= Y --> { X >= Y }.
|
||||||
X =< Y --> { X =< Y }.
|
X =< Y --> { X =< Y }.
|
||||||
@@ -4221,10 +4229,7 @@ activate_propagator(propagator(P,State)) -->
|
|||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
enable_queue :- true. % NOP
|
%do_queue --> print_queue, false.
|
||||||
disable_queue :- true. % NOP
|
|
||||||
|
|
||||||
%do_queue --> print_queue, { false }.
|
|
||||||
do_queue -->
|
do_queue -->
|
||||||
( queue_enabled ->
|
( queue_enabled ->
|
||||||
( queue_get_goal(Goal) -> { call(Goal) }, do_queue
|
( queue_get_goal(Goal) -> { call(Goal) }, do_queue
|
||||||
@@ -4507,13 +4512,13 @@ run_propagator(pelement(N, Is, V), MState) -->
|
|||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
run_propagator(pgcc_single(Vs, Pairs), _) --> { gcc_global(Vs, Pairs) }.
|
run_propagator(pgcc_single(Vs, Pairs), _) --> gcc_global(Vs, Pairs).
|
||||||
|
|
||||||
run_propagator(pgcc_check_single(Pairs), _) --> { gcc_check(Pairs) }.
|
run_propagator(pgcc_check_single(Pairs), _) --> gcc_check(Pairs).
|
||||||
|
|
||||||
run_propagator(pgcc_check(Pairs), _) --> { gcc_check(Pairs) }.
|
run_propagator(pgcc_check(Pairs), _) --> gcc_check(Pairs).
|
||||||
|
|
||||||
run_propagator(pgcc(Vs, _, Pairs), _) --> { gcc_global(Vs, Pairs) }.
|
run_propagator(pgcc(Vs, _, Pairs), _) --> gcc_global(Vs, Pairs).
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
@@ -4588,7 +4593,7 @@ run_propagator(pserialized(S_I, D_I, S_J, D_J, _), MState) -->
|
|||||||
kill(MState),
|
kill(MState),
|
||||||
( S_I + D_I =< S_J -> []
|
( S_I + D_I =< S_J -> []
|
||||||
; S_J + D_J =< S_I -> []
|
; S_J + D_J =< S_I -> []
|
||||||
; { false }
|
; false
|
||||||
)
|
)
|
||||||
; serialize_lower_upper(S_I, D_I, S_J, D_J, MState),
|
; serialize_lower_upper(S_I, D_I, S_J, D_J, MState),
|
||||||
serialize_lower_upper(S_J, D_J, S_I, D_I, MState)
|
serialize_lower_upper(S_J, D_J, S_I, D_I, MState)
|
||||||
@@ -4661,7 +4666,7 @@ run_propagator(x_eq_abs_plus_v(X,V), MState) -->
|
|||||||
( nonvar(V) ->
|
( nonvar(V) ->
|
||||||
( V =:= 0 -> kill(MState), { X in 0..sup }
|
( V =:= 0 -> kill(MState), { X in 0..sup }
|
||||||
; V < 0 -> kill(MState), { X #= V / 2 }
|
; V < 0 -> kill(MState), { X #= V / 2 }
|
||||||
; V > 0 -> { false }
|
; false % V > 0
|
||||||
)
|
)
|
||||||
; nonvar(X) ->
|
; nonvar(X) ->
|
||||||
kill(MState),
|
kill(MState),
|
||||||
@@ -4753,10 +4758,10 @@ run_propagator(scalar_product_neq(Cs0,Vs0,P0), MState) -->
|
|||||||
) }.
|
) }.
|
||||||
|
|
||||||
run_propagator(scalar_product_leq(Cs0,Vs0,P0), MState) -->
|
run_propagator(scalar_product_leq(Cs0,Vs0,P0), MState) -->
|
||||||
{ coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I),
|
{ coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I) },
|
||||||
P is P0 - I,
|
P is P0 - I,
|
||||||
( Vs = [] -> kill(MState), P >= 0
|
( Vs = [] -> kill(MState), P >= 0
|
||||||
; duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups),
|
; { duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups) },
|
||||||
D1 is P - Inf,
|
D1 is P - Inf,
|
||||||
disable_queue,
|
disable_queue,
|
||||||
( Infs == [], Sups == [] ->
|
( Infs == [], Sups == [] ->
|
||||||
@@ -4769,27 +4774,27 @@ run_propagator(scalar_product_leq(Cs0,Vs0,P0), MState) -->
|
|||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
enable_queue
|
enable_queue
|
||||||
) }.
|
).
|
||||||
|
|
||||||
run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) -->
|
run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) -->
|
||||||
{ coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I),
|
{ coeffs_variables_const(Cs0, Vs0, Cs, Vs, 0, I) },
|
||||||
P is P0 - I,
|
P is P0 - I,
|
||||||
( Vs = [] -> kill(MState), P =:= 0
|
( Vs = [] -> kill(MState), P =:= 0
|
||||||
; Vs = [V], Cs = [C] -> kill(MState), P mod C =:= 0, V is P // C
|
; Vs = [V], Cs = [C] -> kill(MState), P mod C =:= 0, V is P // C
|
||||||
; Cs == [1,1] -> kill(MState), Vs = [A,B], A + B #= P
|
; Cs == [1,1] -> kill(MState), Vs = [A,B], { A + B #= P }
|
||||||
; Cs == [1,-1] -> kill(MState), Vs = [A,B], A #= P + B
|
; Cs == [1,-1] -> kill(MState), Vs = [A,B], { A #= P + B }
|
||||||
; Cs == [-1,1] -> kill(MState), Vs = [A,B], B #= P + A
|
; Cs == [-1,1] -> kill(MState), Vs = [A,B], { B #= P + A }
|
||||||
; Cs == [-1,-1] -> kill(MState), Vs = [A,B], P1 is -P, A + B #= P1
|
; Cs == [-1,-1] -> kill(MState), Vs = [A,B], P1 is -P, { A + B #= P1 }
|
||||||
; P =:= 0, Cs == [1,1,-1] -> kill(MState), Vs = [A,B,C], A + B #= C
|
; P =:= 0, Cs == [1,1,-1] -> kill(MState), Vs = [A,B,C], { A + B #= C }
|
||||||
; P =:= 0, Cs == [1,-1,1] -> kill(MState), Vs = [A,B,C], A + C #= B
|
; P =:= 0, Cs == [1,-1,1] -> kill(MState), Vs = [A,B,C], { A + C #= B }
|
||||||
; P =:= 0, Cs == [-1,1,1] -> kill(MState), Vs = [A,B,C], B + C #= A
|
; P =:= 0, Cs == [-1,1,1] -> kill(MState), Vs = [A,B,C], { B + C #= A }
|
||||||
; duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups),
|
; { duophrase(sum_finite_domains(Cs, Vs, 0, 0, Inf, Sup), Infs, Sups) },
|
||||||
% nl, writeln(Infs-Sups-Inf-Sup),
|
% { nl, writeln(Infs-Sups-Inf-Sup) },
|
||||||
D1 is P - Inf,
|
D1 is P - Inf,
|
||||||
D2 is Sup - P,
|
D2 is Sup - P,
|
||||||
disable_queue,
|
disable_queue,
|
||||||
( Infs == [], Sups == [] ->
|
( Infs == [], Sups == [] ->
|
||||||
between(Inf, Sup, P),
|
{ between(Inf, Sup, P) },
|
||||||
remove_dist_upper_lower(Cs, Vs, D1, D2)
|
remove_dist_upper_lower(Cs, Vs, D1, D2)
|
||||||
; Sups = [] -> P =< Sup, remove_dist_lower(Infs, D2)
|
; Sups = [] -> P =< Sup, remove_dist_lower(Infs, D2)
|
||||||
; Infs = [] -> Inf =< P, remove_dist_upper(Sups, D1)
|
; Infs = [] -> Inf =< P, remove_dist_upper(Sups, D1)
|
||||||
@@ -4801,7 +4806,7 @@ run_propagator(scalar_product_eq(Cs0,Vs0,P0), MState) -->
|
|||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
enable_queue
|
enable_queue
|
||||||
) }.
|
).
|
||||||
|
|
||||||
% X + Y = Z
|
% X + Y = Z
|
||||||
run_propagator(pplus(X,Y,Z,Morph), MState) -->
|
run_propagator(pplus(X,Y,Z,Morph), MState) -->
|
||||||
@@ -5048,8 +5053,8 @@ run_propagator(ptzdiv(X,Y,Z,Morph), MState) -->
|
|||||||
%% % Z = X mod Y
|
%% % Z = X mod Y
|
||||||
|
|
||||||
run_propagator(pmod(X,Y,Z), MState) -->
|
run_propagator(pmod(X,Y,Z), MState) -->
|
||||||
( Y == 0 -> { false }
|
( Y == 0 -> false
|
||||||
; Y == Z -> { false }
|
; Y == Z -> false
|
||||||
; X == Y -> kill(MState), queue_goal(Z = 0)
|
; X == Y -> kill(MState), queue_goal(Z = 0)
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
@@ -5058,7 +5063,7 @@ run_propagator(pmod(X,Y,Z), MState) -->
|
|||||||
Z is X mod Y
|
Z is X mod Y
|
||||||
; nonvar(Y), nonvar(Z) ->
|
; nonvar(Y), nonvar(Z) ->
|
||||||
( Y > 0 -> Z >= 0, Z < Y
|
( Y > 0 -> Z >= 0, Z < Y
|
||||||
; Y < 0 -> Z =< 0, Z > Y
|
; Z =< 0, Z > Y % Y < 0
|
||||||
),
|
),
|
||||||
( { fd_get(X, _, n(XL), _, _) } ->
|
( { fd_get(X, _, n(XL), _, _) } ->
|
||||||
( (XL - Z) mod Y =\= 0 ->
|
( (XL - Z) mod Y =\= 0 ->
|
||||||
@@ -5127,7 +5132,7 @@ run_propagator(pmodz(X,Y,Z), MState) -->
|
|||||||
fd_put(Z, ZD2, ZPs)
|
fd_put(Z, ZD2, ZPs)
|
||||||
% queue_goal(Z #=< X)
|
% queue_goal(Z #=< X)
|
||||||
)
|
)
|
||||||
; X < 0 ->
|
; X < 0,
|
||||||
( { fd_get(Y, _, _, n(YU), _), YU < X } ->
|
( { fd_get(Y, _, _, n(YU), _), YU < X } ->
|
||||||
kill(MState),
|
kill(MState),
|
||||||
queue_goal(Z = X)
|
queue_goal(Z = X)
|
||||||
@@ -5167,7 +5172,7 @@ run_propagator(pmodz(X,Y,Z), MState) -->
|
|||||||
fd_put(Z, ZD5, ZPs)
|
fd_put(Z, ZD5, ZPs)
|
||||||
% queue_goal(Z in ZMin..0)
|
% queue_goal(Z in ZMin..0)
|
||||||
)
|
)
|
||||||
; Y > 0 ->
|
; Y > 0,
|
||||||
( { fd_get(X, _, n(XL), n(XU), _), XL >= 0, Y > XU } ->
|
( { fd_get(X, _, n(XL), n(XU), _), XL >= 0, Y > XU } ->
|
||||||
kill(MState),
|
kill(MState),
|
||||||
queue_goal(Z = X)
|
queue_goal(Z = X)
|
||||||
@@ -5378,8 +5383,9 @@ run_propagator(pmax(X,Y,Z), MState) -->
|
|||||||
; nonvar(Z) ->
|
; nonvar(Z) ->
|
||||||
( Z =:= X -> kill(MState), queue_goal(X #>= Y)
|
( Z =:= X -> kill(MState), queue_goal(X #>= Y)
|
||||||
; Z > X -> queue_goal(Z = Y)
|
; Z > X -> queue_goal(Z = Y)
|
||||||
; { false } % Z < X
|
; false % Z < X
|
||||||
)
|
)
|
||||||
|
; Y == Z -> kill(MState), queue_goal(Y #>= X)
|
||||||
; { fd_get(Y, _, YInf, YSup, _) },
|
; { fd_get(Y, _, YInf, YSup, _) },
|
||||||
( { YInf cis_gt n(X) } -> queue_goal(Z = Y)
|
( { YInf cis_gt n(X) } -> queue_goal(Z = Y)
|
||||||
; { YSup cis_lt n(X) } -> queue_goal(Z = X)
|
; { YSup cis_lt n(X) } -> queue_goal(Z = X)
|
||||||
@@ -5394,7 +5400,7 @@ run_propagator(pmax(X,Y,Z), MState) -->
|
|||||||
; { fd_get(Z, ZD, ZPs) } ->
|
; { fd_get(Z, ZD, ZPs) } ->
|
||||||
{ fd_get(X, _, XInf, XSup, _),
|
{ fd_get(X, _, XInf, XSup, _),
|
||||||
fd_get(Y, _, YInf, YSup, _) },
|
fd_get(Y, _, YInf, YSup, _) },
|
||||||
( { YInf cis_gt YSup } -> kill(MState), queue_goal(Z = Y)
|
( { YInf cis_gt XSup } -> kill(MState), queue_goal(Z = Y)
|
||||||
; { YSup cis_lt XInf } -> kill(MState), queue_goal(Z = X)
|
; { YSup cis_lt XInf } -> kill(MState), queue_goal(Z = X)
|
||||||
; { n(M) cis max(XSup, YSup) } ->
|
; { n(M) cis max(XSup, YSup) } ->
|
||||||
{ domain_remove_greater_than(ZD, M, ZD1) },
|
{ domain_remove_greater_than(ZD, M, ZD1) },
|
||||||
@@ -5413,8 +5419,9 @@ run_propagator(pmin(X,Y,Z), MState) -->
|
|||||||
; nonvar(Z) ->
|
; nonvar(Z) ->
|
||||||
( Z =:= X -> kill(MState), { X #=< Y }
|
( Z =:= X -> kill(MState), { X #=< Y }
|
||||||
; Z < X -> Z = Y
|
; Z < X -> Z = Y
|
||||||
; { false } % Z > X
|
; false % Z > X
|
||||||
)
|
)
|
||||||
|
; Y == Z -> kill(MState), queue_goal(Y #=< X)
|
||||||
; { fd_get(Y, _, YInf, YSup, _) },
|
; { fd_get(Y, _, YInf, YSup, _) },
|
||||||
( { YSup cis_lt n(X) } -> Z = Y
|
( { YSup cis_lt n(X) } -> Z = Y
|
||||||
; { YInf cis_gt n(X) } -> Z = X
|
; { YInf cis_gt n(X) } -> Z = X
|
||||||
@@ -5429,7 +5436,7 @@ run_propagator(pmin(X,Y,Z), MState) -->
|
|||||||
; { fd_get(Z, ZD, ZPs) } ->
|
; { fd_get(Z, ZD, ZPs) } ->
|
||||||
{ fd_get(X, _, XInf, XSup, _),
|
{ fd_get(X, _, XInf, XSup, _),
|
||||||
fd_get(Y, _, YInf, YSup, _) },
|
fd_get(Y, _, YInf, YSup, _) },
|
||||||
( { YSup cis_lt YInf } -> kill(MState), Z = Y
|
( { YSup cis_lt XInf } -> kill(MState), Z = Y
|
||||||
; { YInf cis_gt XSup } -> kill(MState), Z = X
|
; { YInf cis_gt XSup } -> kill(MState), Z = X
|
||||||
; { n(M) cis min(XInf, YInf) } ->
|
; { n(M) cis min(XInf, YInf) } ->
|
||||||
{ domain_remove_smaller_than(ZD, M, ZD1) },
|
{ domain_remove_smaller_than(ZD, M, ZD1) },
|
||||||
@@ -5448,6 +5455,7 @@ run_propagator(pexp(X,Y,Z,Morph), MState) -->
|
|||||||
morph_into_propagator(MState, [Y,Z], reified_eq(1,Y,1,0,[],Z), Morph)
|
morph_into_propagator(MState, [Y,Z], reified_eq(1,Y,1,0,[],Z), Morph)
|
||||||
; Y == 0 -> kill(MState), Z = 1
|
; Y == 0 -> kill(MState), Z = 1
|
||||||
; Y == 1 -> kill(MState), Z = X
|
; Y == 1 -> kill(MState), Z = X
|
||||||
|
; Y == Z -> kill(MState), X = Y, queue_goal(X in -1\/1)
|
||||||
; nonvar(X) ->
|
; nonvar(X) ->
|
||||||
( nonvar(Y) ->
|
( nonvar(Y) ->
|
||||||
( Y >= 0 -> true ; X =:= -1 ),
|
( Y >= 0 -> true ; X =:= -1 ),
|
||||||
@@ -5536,7 +5544,7 @@ run_propagator(pexp(X,Y,Z,Morph), MState) -->
|
|||||||
fd_put(Z, ZD2, ZPs),
|
fd_put(Z, ZD2, ZPs),
|
||||||
{ ( even(Y), ZU = n(Num) ->
|
{ ( even(Y), ZU = n(Num) ->
|
||||||
integer_kth_root_leq(Num, Y, RU),
|
integer_kth_root_leq(Num, Y, RU),
|
||||||
( XL cis_geq n(0), ZL = n(Num1) ->
|
( XL cis_geq n(0), ZL = n(Num1), Num1 >= 0 ->
|
||||||
integer_kth_root_leq(Num1, Y, RL0),
|
integer_kth_root_leq(Num1, Y, RL0),
|
||||||
( RL0^Y < Num1 -> RL is RL0 + 1
|
( RL0^Y < Num1 -> RL is RL0 + 1
|
||||||
; RL = RL0
|
; RL = RL0
|
||||||
@@ -5726,8 +5734,7 @@ run_propagator(reified_fd(V,B), MState) -->
|
|||||||
B = 1
|
B = 1
|
||||||
; { B == 0 } ->
|
; { B == 0 } ->
|
||||||
( { fd_inf(V, inf) } -> []
|
( { fd_inf(V, inf) } -> []
|
||||||
; { fd_sup(V, sup) } -> []
|
; { fd_sup(V, sup) }
|
||||||
; { false }
|
|
||||||
)
|
)
|
||||||
; []
|
; []
|
||||||
).
|
).
|
||||||
@@ -6788,13 +6795,20 @@ gcc_pairs([Key-Num0|KNs], Vs, [Key-Num|Rest]) :-
|
|||||||
Constraint", AAAI-96 Portland, OR, USA, pp 209--215, 1996
|
Constraint", AAAI-96 Portland, OR, USA, pp 209--215, 1996
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
gcc_global(Vs, KNs) :-
|
gcc_global(Vs, KNs) -->
|
||||||
gcc_check(KNs),
|
% at this point, all elements of clpz_gcc_vs must be
|
||||||
% previously: call do_queue/0 (now a NOP) here to reach a
|
% variables, which a previously scheduled and called
|
||||||
% fix-point: all elements of clpz_gcc_vs must be variables. We
|
% gcc_check//1 ensures. Note that gcc_check//1 disables the
|
||||||
% must ensure this holds if gcc_check/1 is later rewritten to
|
% queue and accumulates constraints in the queue. Do we need
|
||||||
% actually disable the queue.
|
% to insert a call of do_queue//0 here to reach a fixpoint? I
|
||||||
with_local_attributes(Vs,
|
% think not, because verify_attributes/3 gives each variable
|
||||||
|
% that is involved in a unification an opportunity to schedule
|
||||||
|
% its propagators, even if the unifications happen
|
||||||
|
% simultaneously (such as [A,B] = [0,1], which can happen in
|
||||||
|
% 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.
|
||||||
|
{ with_local_attributes(Vs,
|
||||||
(gcc_arcs(KNs, S, Vals),
|
(gcc_arcs(KNs, S, Vals),
|
||||||
variables_with_num_occurrences(Vs, VNs),
|
variables_with_num_occurrences(Vs, VNs),
|
||||||
maplist(target_to_v(T), VNs),
|
maplist(target_to_v(T), VNs),
|
||||||
@@ -6805,9 +6819,9 @@ gcc_global(Vs, KNs) :-
|
|||||||
gcc_consistent(T),
|
gcc_consistent(T),
|
||||||
scc(Vals, gcc_successors),
|
scc(Vals, gcc_successors),
|
||||||
phrase(gcc_goals(Vals), Gs)
|
phrase(gcc_goals(Vals), Gs)
|
||||||
; Gs = [] )), Gs),
|
; Gs = [] )), Gs) },
|
||||||
disable_queue,
|
disable_queue,
|
||||||
maplist(call, Gs),
|
neq_nums(Gs),
|
||||||
enable_queue.
|
enable_queue.
|
||||||
|
|
||||||
gcc_consistent(T) :-
|
gcc_consistent(T) :-
|
||||||
@@ -6834,7 +6848,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) -->
|
|||||||
get_attr(Val, lowlink, L2),
|
get_attr(Val, lowlink, L2),
|
||||||
L1 =\= L2,
|
L1 =\= L2,
|
||||||
get_attr(Val, value, Value) } ->
|
get_attr(Val, value, Value) } ->
|
||||||
[clpz:neq_num(V, Value)]
|
[neq_num(V, Value)]
|
||||||
; []
|
; []
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -7004,7 +7018,7 @@ gcc_succ_edge(arc_from(_,_,V,F)) -->
|
|||||||
consistency.
|
consistency.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
gcc_check(Pairs) :-
|
gcc_check(Pairs) -->
|
||||||
disable_queue,
|
disable_queue,
|
||||||
gcc_check_(Pairs),
|
gcc_check_(Pairs),
|
||||||
enable_queue.
|
enable_queue.
|
||||||
@@ -7014,36 +7028,36 @@ gcc_done(Num) :-
|
|||||||
del_attr(Num, clpz_gcc_num),
|
del_attr(Num, clpz_gcc_num),
|
||||||
del_attr(Num, clpz_gcc_occurred).
|
del_attr(Num, clpz_gcc_occurred).
|
||||||
|
|
||||||
gcc_check_([]).
|
gcc_check_([]) --> [].
|
||||||
gcc_check_([Key-Num0|KNs]) :-
|
gcc_check_([Key-Num0|KNs]) -->
|
||||||
( get_attr(Num0, clpz_gcc_vs, Vs) ->
|
( { get_attr(Num0, clpz_gcc_vs, Vs) } ->
|
||||||
get_attr(Num0, clpz_gcc_num, Num),
|
{ get_attr(Num0, clpz_gcc_num, Num),
|
||||||
get_attr(Num0, clpz_gcc_occurred, Occ0),
|
get_attr(Num0, clpz_gcc_occurred, Occ0),
|
||||||
vs_key_min_others(Vs, Key, 0, Min, Os),
|
vs_key_min_others(Vs, Key, 0, Min, Os),
|
||||||
put_attr(Num0, clpz_gcc_vs, Os),
|
put_attr(Num0, clpz_gcc_vs, Os),
|
||||||
put_attr(Num0, clpz_gcc_occurred, Occ1),
|
put_attr(Num0, clpz_gcc_occurred, Occ1),
|
||||||
Occ1 is Occ0 + Min,
|
Occ1 is Occ0 + Min },
|
||||||
geq(Num, Occ1),
|
geq(Num, Occ1),
|
||||||
% The queue is disabled for efficiency here in any case.
|
% The queue is disabled for efficiency here in any case.
|
||||||
% If it were enabled, make sure to retain the invariant
|
% If it were enabled, make sure to retain the invariant
|
||||||
% that gcc_global is never triggered during an
|
% that gcc_global is never triggered during an
|
||||||
% inconsistent state (after gcc_done/1 but before all
|
% inconsistent state (after gcc_done/1 but before all
|
||||||
% relevant constraints are posted).
|
% relevant constraints are posted).
|
||||||
( Occ1 == Num -> all_neq(Os, Key), gcc_done(Num0)
|
( Occ1 == Num -> all_neq(Os, Key), { gcc_done(Num0) }
|
||||||
; Os == [] -> gcc_done(Num0), Num = Occ1
|
; Os == [] -> { gcc_done(Num0) }, Num = Occ1
|
||||||
; length(Os, L),
|
; { length(Os, L),
|
||||||
Max is Occ1 + L,
|
Max is Occ1 + L },
|
||||||
geq(Max, Num),
|
geq(Max, Num),
|
||||||
( nonvar(Num) -> Diff is Num - Occ1
|
( { nonvar(Num) } -> Diff is Num - Occ1
|
||||||
; fd_get(Num, ND, _),
|
; { fd_get(Num, ND, _),
|
||||||
domain_infimum(ND, n(NInf)),
|
domain_infimum(ND, n(NInf)) },
|
||||||
Diff is NInf - Occ1
|
Diff is NInf - Occ1
|
||||||
),
|
),
|
||||||
L >= Diff,
|
L >= Diff,
|
||||||
( L =:= Diff ->
|
( L =:= Diff ->
|
||||||
Num is Occ1 + Diff,
|
Num is Occ1 + Diff,
|
||||||
maplist(=(Key), Os),
|
{ maplist(=(Key), Os),
|
||||||
gcc_done(Num0)
|
gcc_done(Num0) }
|
||||||
; true
|
; true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
crypto_password_hash/3, % +Password, -Hash, +Options
|
crypto_password_hash/3, % +Password, -Hash, +Options
|
||||||
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
||||||
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
||||||
|
ed25519_seed_keypair/2, % +Seed, -KeyPair
|
||||||
ed25519_new_keypair/1, % -KeyPair
|
ed25519_new_keypair/1, % -KeyPair
|
||||||
ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
|
ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
|
||||||
ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
|
ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
|
||||||
@@ -612,6 +613,50 @@ encoding_chars(utf8, Cs, Cs) :-
|
|||||||
===============================
|
===============================
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
%% ed25519_seed_keypair(+Seed, -Pair)
|
||||||
|
%
|
||||||
|
% Use Seed to deterministically generate an Ed25519 key pair Pair, a
|
||||||
|
% list of characters. Seed must be a list of 32 bytes. It can be
|
||||||
|
% chosen at random (using for example `crypto_n_random_bytes/2`) or
|
||||||
|
% derived from input keying material (IKM) using for example
|
||||||
|
% `crypto_data_hkdf/4`. The pair contains the private key and must be
|
||||||
|
% kept absolutely secret. Pair can be used for signing. Its public
|
||||||
|
% key can be obtained with `ed25519_keypair_public_key/2`.
|
||||||
|
|
||||||
|
ed25519_seed_keypair(Seed, Pair) :-
|
||||||
|
must_be_bytes(Seed, ed25519_keypair_from_seed/2),
|
||||||
|
length(Seed, 32),
|
||||||
|
'$ed25519_seed_to_public_key'(Seed, Public),
|
||||||
|
maplist(char_code, Public, PublicBytes),
|
||||||
|
phrase(ed25519_PKCS8v2(Seed,PublicBytes), DERs),
|
||||||
|
maplist(char_code, Pair, DERs).
|
||||||
|
|
||||||
|
% DER (and hence BER) encoding of an Ed25519 private key and
|
||||||
|
% corresponding public key in PKCS#8v2 format (RFC 5958) as specified
|
||||||
|
% in RFC 8410.
|
||||||
|
|
||||||
|
ed25519_PKCS8v2(Seed, PublicBytes) -->
|
||||||
|
[0x30,81], % a SEQUENCE of 81 bytes follows
|
||||||
|
|
||||||
|
% the publicKey is present, hence we set version to v2
|
||||||
|
[2,1,1], % the integer 1 denoting version 2 (awesome design!)
|
||||||
|
|
||||||
|
% privateKeyAlgorithm: SEQUENCE
|
||||||
|
[0x30,5], % a SEQUENCE of 5 bytes follows
|
||||||
|
[6,3], % an OBJECT IDENTIFIER of 3 bytes follows
|
||||||
|
[43,101,112], % OID of Ed25519
|
||||||
|
|
||||||
|
% privateKey: OCTET STRING
|
||||||
|
[4,34], % an OCTET STRING of 34 bytes follows
|
||||||
|
[4,32], % an OCTET STRING of 32 bytes follows
|
||||||
|
seq(Seed), % the seed is the private key
|
||||||
|
|
||||||
|
% publicKey: [1] IMPLICIT BIT STRING; context-specific, hence bit 7 set
|
||||||
|
[0b10000001], % the public key follows
|
||||||
|
[33], % a BIT STRING of length 33 follows
|
||||||
|
[0], % 32 bytes is divisible by 8, hence 0 unused bits
|
||||||
|
seq(PublicBytes).
|
||||||
|
|
||||||
%% ed25519_new_keypair(-Pair)
|
%% ed25519_new_keypair(-Pair)
|
||||||
%
|
%
|
||||||
% Yields a new Ed25519 key pair Pair, a list of characters. The
|
% Yields a new Ed25519 key pair Pair, a list of characters. The
|
||||||
@@ -620,7 +665,8 @@ encoding_chars(utf8, Cs, Cs) :-
|
|||||||
% with `ed25519_keypair_public_key/2`.
|
% with `ed25519_keypair_public_key/2`.
|
||||||
|
|
||||||
ed25519_new_keypair(Pair) :-
|
ed25519_new_keypair(Pair) :-
|
||||||
'$ed25519_new_keypair'(Pair).
|
crypto_n_random_bytes(32, Bytes),
|
||||||
|
ed25519_seed_keypair(Bytes, Pair).
|
||||||
|
|
||||||
%% ed25519_keypair_public_key(+Pair, -PublicKey)
|
%% ed25519_keypair_public_key(+Pair, -PublicKey)
|
||||||
%
|
%
|
||||||
@@ -629,8 +675,11 @@ ed25519_new_keypair(Pair) :-
|
|||||||
% The public key is represented as a list of characters.
|
% The public key is represented as a list of characters.
|
||||||
|
|
||||||
ed25519_keypair_public_key(Pair, PublicKey) :-
|
ed25519_keypair_public_key(Pair, PublicKey) :-
|
||||||
must_be_octet_chars(Pair, ed25519_keypair_public_key),
|
must_be_octet_chars(Pair, ed25519_keypair_public_key/2),
|
||||||
'$ed25519_keypair_public_key'(Pair, PublicKey).
|
reverse(Pair, RPs),
|
||||||
|
length(RPublicKey, 32),
|
||||||
|
phrase((seq(RPublicKey),...), RPs),
|
||||||
|
reverse(RPublicKey, PublicKey).
|
||||||
|
|
||||||
%% ed25519_sign(+Key, +Data, -Signature, +Options)
|
%% ed25519_sign(+Key, +Data, -Signature, +Options)
|
||||||
%
|
%
|
||||||
@@ -638,10 +687,14 @@ ed25519_keypair_public_key(Pair, PublicKey) :-
|
|||||||
% PKCS#8 v2 format as generated by `ed25519_new_keypair/1`. Sign Data
|
% PKCS#8 v2 format as generated by `ed25519_new_keypair/1`. Sign Data
|
||||||
% with Key, yielding Signature as a list of hexadecimal characters.
|
% with Key, yielding Signature as a list of hexadecimal characters.
|
||||||
|
|
||||||
ed25519_sign(Key, Data0, Signature, Options) :-
|
ed25519_sign(KeyPair, Data0, Signature, Options) :-
|
||||||
must_be_octet_chars(Key, ed25519_sign),
|
must_be_octet_chars(KeyPair, ed25519_sign/4),
|
||||||
|
length(Prefix, 16),
|
||||||
|
length(PrivateKeyChars, 32),
|
||||||
|
phrase((seq(Prefix),seq(PrivateKeyChars),...), KeyPair),
|
||||||
|
maplist(char_code, PrivateKeyChars, PrivateKey),
|
||||||
options_data_chars(Options, Data0, Data, Encoding),
|
options_data_chars(Options, Data0, Data, Encoding),
|
||||||
'$ed25519_sign'(Key, Data, Encoding, Signature0),
|
'$ed25519_sign_raw'(PrivateKey, Data, Encoding, Signature0),
|
||||||
hex_bytes(Signature, Signature0).
|
hex_bytes(Signature, Signature0).
|
||||||
|
|
||||||
%% ed25519_verify(+Key, +Data, +Signature, +Options)
|
%% ed25519_verify(+Key, +Data, +Signature, +Options)
|
||||||
@@ -658,10 +711,10 @@ ed25519_sign(Key, Data0, Signature, Options) :-
|
|||||||
% which treats Data as a list of raw bytes.
|
% which treats Data as a list of raw bytes.
|
||||||
|
|
||||||
ed25519_verify(Key, Data0, Signature0, Options) :-
|
ed25519_verify(Key, Data0, Signature0, Options) :-
|
||||||
must_be_octet_chars(Key, ed25519_verify),
|
must_be_octet_chars(Key, ed25519_verify/4),
|
||||||
options_data_chars(Options, Data0, Data, Encoding),
|
options_data_chars(Options, Data0, Data, Encoding),
|
||||||
hex_bytes(Signature0, Signature),
|
hex_bytes(Signature0, Signature),
|
||||||
'$ed25519_verify'(Key, Data, Encoding, Signature).
|
'$ed25519_verify_raw'(Key, Data, Encoding, Signature).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
X25519: ECDH key exchange over Curve25519
|
X25519: ECDH key exchange over Curve25519
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ to learn more about them.
|
|||||||
[op(1105, xfy, '|'),
|
[op(1105, xfy, '|'),
|
||||||
phrase/2,
|
phrase/2,
|
||||||
phrase/3,
|
phrase/3,
|
||||||
|
phrase/4,
|
||||||
|
phrase/5,
|
||||||
seq//1,
|
seq//1,
|
||||||
seqq//1,
|
seqq//1,
|
||||||
... //0
|
... //0,
|
||||||
|
(-->)/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
@@ -26,6 +29,10 @@ to learn more about them.
|
|||||||
|
|
||||||
:- meta_predicate phrase(2, ?, ?).
|
:- meta_predicate phrase(2, ?, ?).
|
||||||
|
|
||||||
|
:- meta_predicate phrase(2, ?, ?, ?).
|
||||||
|
|
||||||
|
:- meta_predicate phrase(2, ?, ?, ?, ?).
|
||||||
|
|
||||||
%% phrase(+Body, ?Ls).
|
%% phrase(+Body, ?Ls).
|
||||||
%
|
%
|
||||||
% True iff Body describes the list Ls. Body must be a DCG body.
|
% True iff Body describes the list Ls. Body must be a DCG body.
|
||||||
@@ -75,6 +82,34 @@ phrase(GRBody, S0, S) :-
|
|||||||
; call(M:GRBody1, S0, S)
|
; call(M:GRBody1, S0, S)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
phrase(GRBody, Arg, S0, S) :-
|
||||||
|
strip_module(GRBody, M, GRBody1),
|
||||||
|
( var(GRBody) ->
|
||||||
|
instantiation_error(phrase/4)
|
||||||
|
; nonvar(GRBody1),
|
||||||
|
GRBody1 =.. GRBodys1,
|
||||||
|
append(GRBodys1, [Arg], GRBodys2),
|
||||||
|
GRBody2 =.. GRBodys2,
|
||||||
|
dcg_constr(GRBody2),
|
||||||
|
dcg_body(GRBody2, S0, S, GRBody3) ->
|
||||||
|
call(M:GRBody3)
|
||||||
|
; call(M:GRBody1, Arg, S0, S)
|
||||||
|
).
|
||||||
|
|
||||||
|
phrase(GRBody, Arg1, Arg2, S0, S) :-
|
||||||
|
strip_module(GRBody, M, GRBody1),
|
||||||
|
( var(GRBody) ->
|
||||||
|
instantiation_error(phrase/5)
|
||||||
|
; nonvar(GRBody1),
|
||||||
|
GRBody1 =.. GRBodys1,
|
||||||
|
append(GRBodys1, [Arg1,Arg2], GRBodys2),
|
||||||
|
GRBody2 =.. GRBodys2,
|
||||||
|
dcg_constr(GRBody2),
|
||||||
|
dcg_body(GRBody2, S0, S, GRBody3) ->
|
||||||
|
call(M:GRBody3)
|
||||||
|
; call(M:GRBody1, Arg1, Arg2, S0, S)
|
||||||
|
).
|
||||||
|
|
||||||
% The same version of the below two dcg_rule clauses, but with module scoping.
|
% The same version of the below two dcg_rule clauses, but with module scoping.
|
||||||
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
@@ -101,7 +136,10 @@ dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
|
|||||||
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||||
NonTerminal =.. NonTerminalUniv,
|
NonTerminal =.. NonTerminalUniv,
|
||||||
append(NonTerminalUniv, [S0, S], GoalUniv),
|
append(NonTerminalUniv, [S0, S], GoalUniv),
|
||||||
Goal =.. GoalUniv.
|
( callable(NonTerminal) ->
|
||||||
|
Goal =.. GoalUniv
|
||||||
|
; Goal = NonTerminal % let call/N throw an error instead of throwing one here.
|
||||||
|
).
|
||||||
|
|
||||||
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
||||||
append(Terminals, S, List).
|
append(Terminals, S, List).
|
||||||
@@ -116,8 +154,6 @@ dcg_body(GRBody, S0, S, Body) :-
|
|||||||
dcg_body(NonTerminal, S0, S, Goal1) :-
|
dcg_body(NonTerminal, S0, S, Goal1) :-
|
||||||
nonvar(NonTerminal),
|
nonvar(NonTerminal),
|
||||||
\+ dcg_constr(NonTerminal),
|
\+ dcg_constr(NonTerminal),
|
||||||
NonTerminal \= ( _ -> _ ),
|
|
||||||
NonTerminal \= ( \+ _ ),
|
|
||||||
loader:strip_module(NonTerminal, M, NonTerminal0),
|
loader:strip_module(NonTerminal, M, NonTerminal0),
|
||||||
dcg_non_terminal(NonTerminal0, S0, S, Goal0),
|
dcg_non_terminal(NonTerminal0, S0, S, Goal0),
|
||||||
( functor(NonTerminal, (:), 2) ->
|
( functor(NonTerminal, (:), 2) ->
|
||||||
@@ -135,9 +171,13 @@ dcg_constr(( _'|'_ )). % 7.14.6 - alternative
|
|||||||
dcg_constr({_}). % 7.14.7
|
dcg_constr({_}). % 7.14.7
|
||||||
dcg_constr(call(_)). % 7.14.8
|
dcg_constr(call(_)). % 7.14.8
|
||||||
dcg_constr(phrase(_)). % 7.14.9
|
dcg_constr(phrase(_)). % 7.14.9
|
||||||
|
dcg_constr(phrase(_,_)). % extension of 7.14.9
|
||||||
|
dcg_constr(phrase(_,_,_)). % extension of 7.14.9
|
||||||
dcg_constr(!). % 7.14.10
|
dcg_constr(!). % 7.14.10
|
||||||
%% dcg_constr(\+ _). % 7.14.11 - not (existence implementation dep.)
|
dcg_constr(\+ G_0) :- % 7.14.11 - not (existence implementation def.)
|
||||||
dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
|
throw(error(representation_error(dcg_body), [culprit- (\+ G_0)])).
|
||||||
|
dcg_constr((If->Then)) :- % 7.14.12 - if-then (existence implementation def.)
|
||||||
|
throw(error(representation_error(dcg_body), [culprit- (If->Then)])).
|
||||||
|
|
||||||
% The principal functor of the first argument indicates
|
% The principal functor of the first argument indicates
|
||||||
% the construct to be expanded.
|
% the construct to be expanded.
|
||||||
@@ -162,8 +202,10 @@ dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
|||||||
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||||
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||||
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||||
|
dcg_cbody(phrase(Body, Arg), S0, S, phrase(Body, Arg, S0, S)).
|
||||||
|
dcg_cbody(phrase(Body, Arg1, Arg2), S0, S, phrase(Body, Arg1, Arg2, S0, S)).
|
||||||
dcg_cbody(!, S0, S, ( !, S0 = S )).
|
dcg_cbody(!, S0, S, ( !, S0 = S )).
|
||||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
% dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
||||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
||||||
dcg_body(GRIf, S0, S1, If),
|
dcg_body(GRIf, S0, S1, If),
|
||||||
dcg_body(GRThen, S1, S, Then).
|
dcg_body(GRThen, S1, S, Then).
|
||||||
@@ -202,6 +244,8 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess).
|
|||||||
|
|
||||||
error_goal(error(E, must_be/2), error(E, must_be/2)).
|
error_goal(error(E, must_be/2), error(E, must_be/2)).
|
||||||
error_goal(error(E, (=..)/2), error(E, (=..)/2)).
|
error_goal(error(E, (=..)/2), error(E, (=..)/2)).
|
||||||
|
error_goal(error(representation_error(dcg_body), Context),
|
||||||
|
error(representation_error(dcg_body), Context)).
|
||||||
error_goal(E, _) :- throw(E).
|
error_goal(E, _) :- throw(E).
|
||||||
|
|
||||||
user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
|
user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
|
||||||
@@ -217,3 +261,10 @@ user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
||||||
|
|
||||||
|
|
||||||
|
% (-->)/2 behaves as if it didn't exist. We export (and define) it
|
||||||
|
% only so that clauses for (-->)/2 cannot be asserted when
|
||||||
|
% library(dcgs) is loaded.
|
||||||
|
|
||||||
|
(_-->_) :- throw(error(existence_error(procedure,(-->)/2),(-->)/2)).
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ directory_must_exist(Directory, Context) :-
|
|||||||
; throw(error(existence_error(directory, Directory), Context))
|
; throw(error(existence_error(directory, Directory), Context))
|
||||||
).
|
).
|
||||||
|
|
||||||
%% workind_directory(Dir0, Dir).
|
%% working_directory(Dir0, Dir).
|
||||||
%
|
%
|
||||||
% Dir0 is the current working directory, and the working directory
|
% Dir0 is the current working directory, and the working directory
|
||||||
% is changed to Dir.
|
% is changed to Dir.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written 2020-2023 by Markus Triska (triska@metalevel.at)
|
Written 2020-2024 by Markus Triska (triska@metalevel.at)
|
||||||
Part of Scryer Prolog.
|
Part of Scryer Prolog.
|
||||||
I place this code in the public domain. Use it in any way you want.
|
I place this code in the public domain. Use it in any way you want.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
@@ -302,14 +302,14 @@ format_number_chars(N0, Chars) :-
|
|||||||
N is N0, % evaluate compound expression
|
N is N0, % evaluate compound expression
|
||||||
number_chars(N, Chars).
|
number_chars(N, Chars).
|
||||||
|
|
||||||
n_newlines(0) --> !.
|
|
||||||
n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N).
|
n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N).
|
||||||
|
n_newlines(0) --> [].
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
?- phrase(upto_what(Cs, ~), "abc~test", Rest).
|
?- phrase(format:upto_what(Cs, ~), "abc~test", Rest).
|
||||||
Cs = [a,b,c], Rest = [~,t,e,s,t].
|
Cs = "abc", Rest = "~test".
|
||||||
?- phrase(upto_what(Cs, ~), "abc", Rest).
|
?- phrase(format:upto_what(Cs, ~), "abc", Rest).
|
||||||
Cs = [a,b,c], Rest = [].
|
Cs = "abc", Rest = [].
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
separate_digits_fractional(Arg, Sep, Num, Cs) :-
|
separate_digits_fractional(Arg, Sep, Num, Cs) :-
|
||||||
@@ -444,9 +444,9 @@ format(Stream, Fs, Args) :-
|
|||||||
?- phrase(format:cells("~`at~50|", [], 0, [], []), Cs),
|
?- phrase(format:cells("~`at~50|", [], 0, [], []), Cs),
|
||||||
phrase(format:format_cells(Cs), Ls).
|
phrase(format:format_cells(Cs), Ls).
|
||||||
?- phrase(format:cells("~ta~t~tb~tc~21|", [], 0, [], []), Cs).
|
?- phrase(format:cells("~ta~t~tb~tc~21|", [], 0, [], []), Cs).
|
||||||
Cs = [cell(0,21,[glue(' ',_A),chars("a"),glue(' ',_B),glue(' ',_C),chars("b"),glue(' ',_D),chars("c ...")])]
|
Cs = [cell(0,21,[glue(' ',_A),chars("a"),glue(' ',_B),glue(' ',_C),chars("b"),glue(' ',_D),chars("c")])].
|
||||||
?- phrase(format:cells("~ta~t~4|", [], 0, [], []), Cs).
|
?- phrase(format:cells("~ta~t~4|", [], 0, [], []), Cs).
|
||||||
Cs = [cell(0,4,[glue(' ',_A),chars("a"),glue(' ',_B)])]
|
Cs = [cell(0,4,[glue(' ',_A),chars("a"),glue(' ',_B)])].
|
||||||
|
|
||||||
?- phrase(format:format_cell(cell(0,1,[glue(a,_94)])), Ls).
|
?- phrase(format:format_cell(cell(0,1,[glue(a,_94)])), Ls).
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ but they're not part of the ISO Prolog standard at the moment.
|
|||||||
bb_put/2,
|
bb_put/2,
|
||||||
call_cleanup/2,
|
call_cleanup/2,
|
||||||
call_with_inference_limit/3,
|
call_with_inference_limit/3,
|
||||||
|
call_residue_vars/2,
|
||||||
forall/2,
|
forall/2,
|
||||||
partial_string/1,
|
partial_string/1,
|
||||||
partial_string/3,
|
partial_string/3,
|
||||||
@@ -17,7 +18,8 @@ but they're not part of the ISO Prolog standard at the moment.
|
|||||||
succ/2,
|
succ/2,
|
||||||
call_nth/2,
|
call_nth/2,
|
||||||
countall/2,
|
countall/2,
|
||||||
copy_term_nat/2]).
|
copy_term_nat/2,
|
||||||
|
copy_term/3]).
|
||||||
|
|
||||||
:- use_module(library(error), [can_be/2,
|
:- use_module(library(error), [can_be/2,
|
||||||
domain_error/3,
|
domain_error/3,
|
||||||
@@ -26,6 +28,8 @@ but they're not part of the ISO Prolog standard at the moment.
|
|||||||
|
|
||||||
:- use_module(library(lists), [maplist/3]).
|
:- use_module(library(lists), [maplist/3]).
|
||||||
|
|
||||||
|
:- use_module(library('$project_atts')).
|
||||||
|
|
||||||
:- meta_predicate(forall(0, 0)).
|
:- meta_predicate(forall(0, 0)).
|
||||||
|
|
||||||
%% forall(Generate, Test).
|
%% forall(Generate, Test).
|
||||||
@@ -382,3 +386,23 @@ countall(Goal, N) :-
|
|||||||
copy_term_nat(Source, Dest) :-
|
copy_term_nat(Source, Dest) :-
|
||||||
'$copy_term_without_attr_vars'(Source, Dest).
|
'$copy_term_without_attr_vars'(Source, Dest).
|
||||||
|
|
||||||
|
%% copy_term(+Term, -Copy, -Gs).
|
||||||
|
%
|
||||||
|
% Produce a deep copy of Term and unify it to Copy, without attributes.
|
||||||
|
% Unify Gs with a list of goals that represent the attributes of Term.
|
||||||
|
% Similar to `copy_term/2` but splitting the attributes.
|
||||||
|
copy_term(Term, Copy, Gs) :-
|
||||||
|
can_be(list, Gs),
|
||||||
|
findall(Term-Rs, '$project_atts':term_residual_goals(Term,Rs), [Copy-Gs]),
|
||||||
|
( var(Gs) ->
|
||||||
|
Gs = []
|
||||||
|
; true
|
||||||
|
).
|
||||||
|
|
||||||
|
:- meta_predicate call_residue_vars(0, ?).
|
||||||
|
|
||||||
|
call_residue_vars(Goal, Vars) :-
|
||||||
|
can_be(list, Vars),
|
||||||
|
'$get_attr_var_queue_delim'(B),
|
||||||
|
call(Goal),
|
||||||
|
'$get_attr_var_queue_beyond'(B, Vars).
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ finding out the PID of the running system.
|
|||||||
unsetenv/1,
|
unsetenv/1,
|
||||||
shell/1,
|
shell/1,
|
||||||
shell/2,
|
shell/2,
|
||||||
pid/1]).
|
pid/1,
|
||||||
|
raw_argv/1,
|
||||||
|
argv/1]).
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
@@ -110,3 +112,34 @@ permitted('_').
|
|||||||
must_be_chars(Cs) :-
|
must_be_chars(Cs) :-
|
||||||
must_be(list, Cs),
|
must_be(list, Cs),
|
||||||
maplist(must_be(character), Cs).
|
maplist(must_be(character), Cs).
|
||||||
|
|
||||||
|
%% raw_argv(-Argv)
|
||||||
|
%
|
||||||
|
% True iff Argv is the list of arguments that this program was started with (usually passed via command line).
|
||||||
|
% In contrast to `argv/1`, this version includes every argument, without any postprocessing, just as the operating
|
||||||
|
% system reports it to the system. This includes-flags of Scryer itself, which are not needed in general.
|
||||||
|
raw_argv(Argv) :-
|
||||||
|
can_be(list, Argv),
|
||||||
|
'$argv'(Argv).
|
||||||
|
|
||||||
|
%% argv(-Argv)
|
||||||
|
%
|
||||||
|
% True if Argv is the list of arguments that this program was started with (usually passed via command line).
|
||||||
|
% In this version, only arguments specific to the program are passed. To differentiate between the system
|
||||||
|
% arguments and the program arguments, we use `--` as a separator.
|
||||||
|
%
|
||||||
|
% Example:
|
||||||
|
%
|
||||||
|
% ```
|
||||||
|
% % Call with scryer-prolog -f -- -t hello
|
||||||
|
% ?- argv(X).
|
||||||
|
% X = ["-t", "hello"].
|
||||||
|
% ```
|
||||||
|
argv(Argv) :-
|
||||||
|
can_be(list, Argv),
|
||||||
|
'$argv'(Argv0),
|
||||||
|
( append(_, ["--"|Argv1], Argv0) ->
|
||||||
|
Argv = Argv1
|
||||||
|
;
|
||||||
|
Argv = []
|
||||||
|
).
|
||||||
|
|||||||
@@ -39,7 +39,8 @@
|
|||||||
character_si/1,
|
character_si/1,
|
||||||
term_si/1,
|
term_si/1,
|
||||||
chars_si/1,
|
chars_si/1,
|
||||||
dif_si/2]).
|
dif_si/2,
|
||||||
|
when_si/2]).
|
||||||
|
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
@@ -98,3 +99,31 @@ dif_si(X, Y) :-
|
|||||||
( X \= Y -> true
|
( X \= Y -> true
|
||||||
; throw(error(instantiation_error,dif_si/2))
|
; throw(error(instantiation_error,dif_si/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
:- meta_predicate(when_si(+, 0)).
|
||||||
|
|
||||||
|
%% when_si(Condition, Goal).
|
||||||
|
%
|
||||||
|
% Executes Goal when Condition becomes true. Throws an instantiation error if
|
||||||
|
% it can't decide.
|
||||||
|
when_si(Condition, Goal) :-
|
||||||
|
% Taken from https://stackoverflow.com/a/40449516
|
||||||
|
( when_condition_si(Condition) ->
|
||||||
|
( Condition ->
|
||||||
|
Goal
|
||||||
|
; throw(error(instantiation_error,when_si/2))
|
||||||
|
)
|
||||||
|
; throw(error(domain_error(when_condition_si, Condition),_))
|
||||||
|
).
|
||||||
|
|
||||||
|
when_condition_si(Cond) :-
|
||||||
|
var(Cond), !, throw(error(instantiation_error,when_condition_si/2)).
|
||||||
|
when_condition_si(ground(_)).
|
||||||
|
when_condition_si(nonvar(_)).
|
||||||
|
when_condition_si((A, B)) :-
|
||||||
|
when_condition_si(A),
|
||||||
|
when_condition_si(B).
|
||||||
|
when_condition_si((A ; B)) :-
|
||||||
|
when_condition_si(A),
|
||||||
|
when_condition_si(B).
|
||||||
|
|
||||||
|
|||||||
106
src/lib/when.pl
Normal file
106
src/lib/when.pl
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
Provides the predicate `when/2`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(when, [when/2]).
|
||||||
|
|
||||||
|
:- use_module(library(atts)).
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(lambda)).
|
||||||
|
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(debug)).
|
||||||
|
|
||||||
|
:- attribute when_list/1.
|
||||||
|
|
||||||
|
:- meta_predicate(when(+, 0)).
|
||||||
|
|
||||||
|
%% when(Condition, Goal).
|
||||||
|
%
|
||||||
|
% Executes Goal when Condition becomes true.
|
||||||
|
when(Condition, Goal) :-
|
||||||
|
( when_condition(Condition) ->
|
||||||
|
( Condition ->
|
||||||
|
Goal
|
||||||
|
; term_variables(Condition, Vars),
|
||||||
|
maplist(
|
||||||
|
[Goal, Condition]+\Var^(
|
||||||
|
get_atts(Var, when_list(Whens0)) ->
|
||||||
|
Whens = [when(Condition, Goal) | Whens0],
|
||||||
|
put_atts(Var, when_list(Whens))
|
||||||
|
; put_atts(Var, when_list([when(Condition, Goal)]))
|
||||||
|
),
|
||||||
|
Vars
|
||||||
|
)
|
||||||
|
)
|
||||||
|
; throw(error(domain_error(when_condition, Condition),_))
|
||||||
|
).
|
||||||
|
|
||||||
|
when_condition(Cond) :-
|
||||||
|
% Should this be delayed?
|
||||||
|
var(Cond), !, throw(error(instantiation_error,when_condition/1)).
|
||||||
|
when_condition(ground(_)).
|
||||||
|
when_condition(nonvar(_)).
|
||||||
|
when_condition((A, B)) :-
|
||||||
|
when_condition(A),
|
||||||
|
when_condition(B).
|
||||||
|
when_condition((A ; B)) :-
|
||||||
|
when_condition(A),
|
||||||
|
when_condition(B).
|
||||||
|
|
||||||
|
remove_goal([], _, []).
|
||||||
|
remove_goal([G0|G0s], Goal, Goals) :-
|
||||||
|
( G0 == Goal ->
|
||||||
|
remove_goal(G0s, Goal, Goals)
|
||||||
|
; Goals = [G0|Goals1],
|
||||||
|
remove_goal(G0s, Goal, Goals1)
|
||||||
|
).
|
||||||
|
|
||||||
|
vars_remove_goal(Vars, Goal) :-
|
||||||
|
maplist(
|
||||||
|
Goal+\Var^(
|
||||||
|
get_atts(Var, when_list(Whens0)) ->
|
||||||
|
remove_goal(Whens0, Goal, Whens),
|
||||||
|
( Whens = [] ->
|
||||||
|
put_atts(Var, -when_list(_))
|
||||||
|
; put_atts(Var, when_list(Whens))
|
||||||
|
)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
Vars
|
||||||
|
).
|
||||||
|
|
||||||
|
reinforce_goal(Goal0, Goal) :-
|
||||||
|
Goal = (
|
||||||
|
term_variables(Goal0, Vars),
|
||||||
|
when:vars_remove_goal(Vars, Goal0),
|
||||||
|
Goal0
|
||||||
|
).
|
||||||
|
|
||||||
|
verify_attributes(Var, Value, Goals) :-
|
||||||
|
( get_atts(Var, when_list(Whens)) ->
|
||||||
|
( var(Value) ->
|
||||||
|
( get_atts(Value, when_list(WhensValue)) ->
|
||||||
|
append(Whens, WhensValue, WhensNew),
|
||||||
|
put_atts(Value, when_list(WhensNew))
|
||||||
|
; put_atts(Value, when_list(Whens))
|
||||||
|
),
|
||||||
|
Goals = []
|
||||||
|
; maplist(reinforce_goal, Whens, Goals)
|
||||||
|
)
|
||||||
|
; Goals = []
|
||||||
|
).
|
||||||
|
|
||||||
|
gather_when_goals([], _) --> [].
|
||||||
|
gather_when_goals([When|Whens], Var) -->
|
||||||
|
( { term_variables(When, [V0|_]), Var == V0 } ->
|
||||||
|
[when:When]
|
||||||
|
; []
|
||||||
|
),
|
||||||
|
gather_when_goals(Whens, Var).
|
||||||
|
|
||||||
|
attribute_goals(Var) -->
|
||||||
|
{ get_atts(Var, when_list(Whens)) },
|
||||||
|
gather_when_goals(Whens, Var),
|
||||||
|
{ put_atts(Var, -when_list(_)) }.
|
||||||
109
src/loader.pl
109
src/loader.pl
@@ -112,7 +112,7 @@ success_or_warning(Goal) :-
|
|||||||
( call(Goal) ->
|
( call(Goal) ->
|
||||||
true
|
true
|
||||||
; %% initialization goals can fail without thwarting the load.
|
; %% initialization goals can fail without thwarting the load.
|
||||||
write('Warning: initialization/1 failed for: '),
|
write('% Warning: initialization/1 failed for: '),
|
||||||
writeq(Goal),
|
writeq(Goal),
|
||||||
nl
|
nl
|
||||||
).
|
).
|
||||||
@@ -138,7 +138,7 @@ file_load_cleanup(Evacuable, Error) :-
|
|||||||
load_context(Module),
|
load_context(Module),
|
||||||
abolish(Module:'$initialization_goals'/1),
|
abolish(Module:'$initialization_goals'/1),
|
||||||
unload_evacuable(Evacuable),
|
unload_evacuable(Evacuable),
|
||||||
( clause('$toplevel':argv(_), _) ->
|
( clause('$toplevel':started, _) ->
|
||||||
% let the toplevel call loader:write_error/1
|
% let the toplevel call loader:write_error/1
|
||||||
throw(Error)
|
throw(Error)
|
||||||
; '$print_message_and_fail'(Error)
|
; '$print_message_and_fail'(Error)
|
||||||
@@ -188,7 +188,7 @@ warn_about_singletons([], _).
|
|||||||
warn_about_singletons([Singleton|Singletons], LinesRead) :-
|
warn_about_singletons([Singleton|Singletons], LinesRead) :-
|
||||||
( filter_anonymous_vars([Singleton|Singletons], VarEqs),
|
( filter_anonymous_vars([Singleton|Singletons], VarEqs),
|
||||||
VarEqs \== [] ->
|
VarEqs \== [] ->
|
||||||
write('Warning: singleton variables '),
|
write('% Warning: singleton variables '),
|
||||||
print_comma_separated_list(VarEqs),
|
print_comma_separated_list(VarEqs),
|
||||||
write(' at line '),
|
write(' at line '),
|
||||||
write(LinesRead),
|
write(LinesRead),
|
||||||
@@ -231,6 +231,7 @@ complete_partial_goal(N, HeadArg, InnerHeadArgs, SuppArgs, CompleteHeadArg) :-
|
|||||||
integer(N),
|
integer(N),
|
||||||
N >= 0,
|
N >= 0,
|
||||||
HeadArg =.. [Functor | InnerHeadArgs],
|
HeadArg =.. [Functor | InnerHeadArgs],
|
||||||
|
( callable(Functor) ->
|
||||||
% the next two lines are equivalent to length(SuppArgs, N) but
|
% the next two lines are equivalent to length(SuppArgs, N) but
|
||||||
% avoid length/2 so that copy_term/3 (which is invoked by
|
% avoid length/2 so that copy_term/3 (which is invoked by
|
||||||
% length/2) can be bootstrapped without self-reference.
|
% length/2) can be bootstrapped without self-reference.
|
||||||
@@ -238,7 +239,9 @@ complete_partial_goal(N, HeadArg, InnerHeadArgs, SuppArgs, CompleteHeadArg) :-
|
|||||||
SuppArgsFunctor =.. [_ | SuppArgs],
|
SuppArgsFunctor =.. [_ | SuppArgs],
|
||||||
% length(SuppArgs, N),
|
% length(SuppArgs, N),
|
||||||
append(InnerHeadArgs, SuppArgs, InnerHeadArgs0),
|
append(InnerHeadArgs, SuppArgs, InnerHeadArgs0),
|
||||||
CompleteHeadArg =.. [Functor | InnerHeadArgs0].
|
CompleteHeadArg =.. [Functor | InnerHeadArgs0]
|
||||||
|
; type_error(callable, Functor, _)
|
||||||
|
).
|
||||||
|
|
||||||
inner_meta_specs(0, HeadArg, InnerHeadArgs, InnerMetaSpecs) :-
|
inner_meta_specs(0, HeadArg, InnerHeadArgs, InnerMetaSpecs) :-
|
||||||
!,
|
!,
|
||||||
@@ -283,7 +286,7 @@ module_expanded_head_variables(Head, HeadVars) :-
|
|||||||
|
|
||||||
print_goal_expansion_warning(Pred) :-
|
print_goal_expansion_warning(Pred) :-
|
||||||
nl,
|
nl,
|
||||||
write('Warning: clause body goal expansion failed because '),
|
write('% Warning: clause body goal expansion failed because '),
|
||||||
writeq(Pred),
|
writeq(Pred),
|
||||||
write(' is not callable.'),
|
write(' is not callable.'),
|
||||||
nl.
|
nl.
|
||||||
@@ -296,7 +299,7 @@ expand_term_goals(Terms0, Terms) :-
|
|||||||
( atom(Module) ->
|
( atom(Module) ->
|
||||||
prolog_load_context(module, Target),
|
prolog_load_context(module, Target),
|
||||||
module_expanded_head_variables(Head2, HeadVars),
|
module_expanded_head_variables(Head2, HeadVars),
|
||||||
catch(expand_goal(Body0, Target, Body1, HeadVars),
|
catch(expand_goal(Body0, Target, Body1, HeadVars, []),
|
||||||
error(type_error(callable, Pred), _),
|
error(type_error(callable, Pred), _),
|
||||||
( loader:print_goal_expansion_warning(Pred),
|
( loader:print_goal_expansion_warning(Pred),
|
||||||
builtins:(Body1 = Body0)
|
builtins:(Body1 = Body0)
|
||||||
@@ -306,7 +309,7 @@ expand_term_goals(Terms0, Terms) :-
|
|||||||
)
|
)
|
||||||
; module_expanded_head_variables(Head1, HeadVars),
|
; module_expanded_head_variables(Head1, HeadVars),
|
||||||
prolog_load_context(module, Target),
|
prolog_load_context(module, Target),
|
||||||
catch(expand_goal(Body0, Target, Body1, HeadVars),
|
catch(expand_goal(Body0, Target, Body1, HeadVars, []),
|
||||||
error(type_error(callable, Pred), _),
|
error(type_error(callable, Pred), _),
|
||||||
( loader:print_goal_expansion_warning(Pred),
|
( loader:print_goal_expansion_warning(Pred),
|
||||||
builtins:(Body1 = Body0)
|
builtins:(Body1 = Body0)
|
||||||
@@ -726,9 +729,9 @@ subgoal_expansion(Goal, Module, ExpandedGoal) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
:- non_counted_backtracking expand_subgoal/5.
|
:- non_counted_backtracking expand_subgoal/6.
|
||||||
|
|
||||||
expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars) :-
|
expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars, TGs) :-
|
||||||
strip_subst_module(UnexpandedGoals, M, Module, UnexpandedGoals0),
|
strip_subst_module(UnexpandedGoals, M, Module, UnexpandedGoals0),
|
||||||
nonvar(UnexpandedGoals0),
|
nonvar(UnexpandedGoals0),
|
||||||
complete_partial_goal(MS, UnexpandedGoals0, _, SuppArgs, UnexpandedGoals1),
|
complete_partial_goal(MS, UnexpandedGoals0, _, SuppArgs, UnexpandedGoals1),
|
||||||
@@ -740,7 +743,7 @@ expand_subgoal(UnexpandedGoals, MS, M, ExpandedGoals, HeadVars) :-
|
|||||||
),
|
),
|
||||||
strip_subst_module(UnexpandedGoals3, Module, Module1, UnexpandedGoals4),
|
strip_subst_module(UnexpandedGoals3, Module, Module1, UnexpandedGoals4),
|
||||||
( inner_meta_specs(0, UnexpandedGoals4, _, MetaSpecs) ->
|
( inner_meta_specs(0, UnexpandedGoals4, _, MetaSpecs) ->
|
||||||
expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars)
|
expand_module_names(UnexpandedGoals4, MetaSpecs, Module1, ExpandedGoals0, HeadVars, TGs)
|
||||||
; ExpandedGoals0 = UnexpandedGoals4
|
; ExpandedGoals0 = UnexpandedGoals4
|
||||||
),
|
),
|
||||||
'$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1, UnexpandedGoals0),
|
'$compile_inline_or_expanded_goal'(ExpandedGoals0, SuppArgs, ExpandedGoals1, Module1, UnexpandedGoals0),
|
||||||
@@ -769,10 +772,10 @@ expand_module_name(ESG0, MS, M, ESG) :-
|
|||||||
|
|
||||||
:- non_counted_backtracking eq_member/2.
|
:- non_counted_backtracking eq_member/2.
|
||||||
|
|
||||||
eq_member(V, [L-_|Ls]) :-
|
eq_member(V-M, [L-M|Ls]) :-
|
||||||
V == L.
|
V == L.
|
||||||
eq_member(V, [_|Ls]) :-
|
eq_member(V-M, [_|Ls]) :-
|
||||||
eq_member(V, Ls).
|
eq_member(V-M, Ls).
|
||||||
|
|
||||||
:- non_counted_backtracking qualified_spec/1.
|
:- non_counted_backtracking qualified_spec/1.
|
||||||
|
|
||||||
@@ -782,11 +785,19 @@ qualified_spec(MS) :- integer(MS), MS >= 0.
|
|||||||
|
|
||||||
:- non_counted_backtracking expand_meta_predicate_subgoals/5.
|
:- non_counted_backtracking expand_meta_predicate_subgoals/5.
|
||||||
|
|
||||||
expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars) :-
|
expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars, TGs) :-
|
||||||
( var(SG) ->
|
( var(SG) ->
|
||||||
( qualified_spec(MS) ->
|
( qualified_spec(MS) ->
|
||||||
( eq_member(SG, HeadVars) ->
|
( eq_member(SG-_, HeadVars) ->
|
||||||
ESG = SG
|
ESG = SG
|
||||||
|
; eq_member(SG-TG, TGs),
|
||||||
|
% transitive goals come about from previous equalities:
|
||||||
|
% if SG was bound by (=)/2 to a potential goal TG earlier
|
||||||
|
% in the goal sequence, expand TG and substitute SG with it
|
||||||
|
% in this subgoal context. the binding to SG must not be
|
||||||
|
% changed.
|
||||||
|
expand_subgoal(TG, MS, M, ESG, HeadVars, TGs) ->
|
||||||
|
true
|
||||||
; expand_module_name(SG, MS, M, ESG)
|
; expand_module_name(SG, MS, M, ESG)
|
||||||
)
|
)
|
||||||
; ESG = SG
|
; ESG = SG
|
||||||
@@ -795,26 +806,26 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars
|
|||||||
expand_module_name(SG, MS, M, ESG)
|
expand_module_name(SG, MS, M, ESG)
|
||||||
; '$is_expanded_or_inlined'(SG) ->
|
; '$is_expanded_or_inlined'(SG) ->
|
||||||
ESG = SG
|
ESG = SG
|
||||||
; expand_subgoal(SG, MS, M, ESG, HeadVars) ->
|
; expand_subgoal(SG, MS, M, ESG, HeadVars, TGs) ->
|
||||||
true
|
true
|
||||||
; integer(MS),
|
; integer(MS),
|
||||||
MS >= 0 ->
|
MS >= 0 ->
|
||||||
expand_module_name(SG, MS, M, ESG)
|
expand_module_name(SG, MS, M, ESG)
|
||||||
; SG = ESG
|
; SG = ESG
|
||||||
),
|
),
|
||||||
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars).
|
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars, TGs).
|
||||||
|
|
||||||
expand_meta_predicate_subgoals([], _, _, [], _).
|
expand_meta_predicate_subgoals([], _, _, [], _, _).
|
||||||
|
|
||||||
:- non_counted_backtracking expand_module_names/5.
|
:- non_counted_backtracking expand_module_names/6.
|
||||||
|
|
||||||
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
|
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars, TGs) :-
|
||||||
Goals =.. [GoalFunctor | SubGoals],
|
Goals =.. [GoalFunctor | SubGoals],
|
||||||
( GoalFunctor == (:),
|
( GoalFunctor == (:),
|
||||||
SubGoals = [M, SubGoal] ->
|
SubGoals = [M, SubGoal] ->
|
||||||
expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars),
|
expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars, TGs),
|
||||||
expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals)
|
expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals)
|
||||||
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
|
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars, TGs),
|
||||||
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
|
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -822,26 +833,26 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
|
|||||||
:- non_counted_backtracking expand_goal/3.
|
:- non_counted_backtracking expand_goal/3.
|
||||||
|
|
||||||
expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
|
expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
|
||||||
catch(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, []),
|
catch(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, [], []),
|
||||||
error(type_error(callable, _), _),
|
error(type_error(callable, _), _),
|
||||||
UnexpandedGoals = ExpandedGoals),
|
UnexpandedGoals = ExpandedGoals),
|
||||||
!.
|
!.
|
||||||
|
|
||||||
:- non_counted_backtracking expand_goal/4.
|
:- non_counted_backtracking expand_goal/5.
|
||||||
|
|
||||||
expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :-
|
expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars, TGs) :-
|
||||||
( var(UnexpandedGoals) ->
|
( var(UnexpandedGoals) ->
|
||||||
expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars)
|
expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars, TGs)
|
||||||
; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
|
; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
|
||||||
( Module \== user ->
|
( Module \== user ->
|
||||||
goal_expansion(UnexpandedGoals1, user, Goals)
|
goal_expansion(UnexpandedGoals1, user, Goals)
|
||||||
; Goals = UnexpandedGoals1
|
; Goals = UnexpandedGoals1
|
||||||
),
|
),
|
||||||
( expand_goal_cases(Goals, Module, ExpandedGoals, HeadVars) ->
|
( expand_goal_cases(Goals, Module, ExpandedGoals, HeadVars, TGs) ->
|
||||||
true
|
true
|
||||||
; predicate_property(Module:Goals, meta_predicate(MetaSpecs0)),
|
; predicate_property(Module:Goals, meta_predicate(MetaSpecs0)),
|
||||||
MetaSpecs0 =.. [_ | MetaSpecs] ->
|
MetaSpecs0 =.. [_ | MetaSpecs] ->
|
||||||
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars)
|
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars, TGs)
|
||||||
; thread_goals(Goals, ExpandedGoals, (','))
|
; thread_goals(Goals, ExpandedGoals, (','))
|
||||||
; Goals = ExpandedGoals
|
; Goals = ExpandedGoals
|
||||||
)
|
)
|
||||||
@@ -874,28 +885,40 @@ expand_call_goal_(UnexpandedGoals, Module, ExpandedGoals) :-
|
|||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
:- non_counted_backtracking expand_goal_cases/4.
|
:- non_counted_backtracking transitive_goal/3.
|
||||||
|
|
||||||
expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :-
|
transitive_goal(G, TGs0, TGs1) :-
|
||||||
( expand_goal(Goal0, Module, Goal1, HeadVars) ->
|
( G = (G1 = PotentialGoal),
|
||||||
expand_goal(Goals0, Module, Goals1, HeadVars),
|
callable(PotentialGoal),
|
||||||
|
subsumes_term(G1, PotentialGoal) ->
|
||||||
|
TGs1 = [G1-PotentialGoal|TGs0]
|
||||||
|
; TGs1 = TGs0
|
||||||
|
).
|
||||||
|
|
||||||
|
:- non_counted_backtracking expand_goal_cases/5.
|
||||||
|
|
||||||
|
expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars, TGs) :-
|
||||||
|
( expand_goal(Goal0, Module, Goal1, HeadVars, TGs) ->
|
||||||
|
transitive_goal(Goal0, TGs, TGs1),
|
||||||
|
expand_goal(Goals0, Module, Goals1, HeadVars, TGs1),
|
||||||
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
|
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
|
||||||
; expand_goal(Goals0, Module, Goals1, HeadVars),
|
; expand_goal(Goals0, Module, Goals1, HeadVars, TGs),
|
||||||
ExpandedGoals = (Goal0, Goals1)
|
ExpandedGoals = (Goal0, Goals1)
|
||||||
).
|
).
|
||||||
expand_goal_cases((Goals0 -> Goals1), Module, ExpandedGoals, HeadVars) :-
|
expand_goal_cases((Goals0 -> Goals1), Module, ExpandedGoals, HeadVars, TGs) :-
|
||||||
expand_goal(Goals0, Module, ExpandedGoals0, HeadVars),
|
expand_goal(Goals0, Module, ExpandedGoals0, HeadVars, TGs),
|
||||||
expand_goal(Goals1, Module, ExpandedGoals1, HeadVars),
|
transitive_goal(ExpandedGoals0, TGs, TGs1),
|
||||||
|
expand_goal(Goals1, Module, ExpandedGoals1, HeadVars, TGs1),
|
||||||
ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1).
|
ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1).
|
||||||
expand_goal_cases((Goals0 ; Goals1), Module, ExpandedGoals, HeadVars) :-
|
expand_goal_cases((Goals0 ; Goals1), Module, ExpandedGoals, HeadVars, TGs) :-
|
||||||
expand_goal(Goals0, Module, ExpandedGoals0, HeadVars),
|
expand_goal(Goals0, Module, ExpandedGoals0, HeadVars, TGs),
|
||||||
expand_goal(Goals1, Module, ExpandedGoals1, HeadVars),
|
expand_goal(Goals1, Module, ExpandedGoals1, HeadVars, TGs),
|
||||||
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1).
|
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1).
|
||||||
expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars) :-
|
expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars, TGs) :-
|
||||||
expand_goal(Goals0, Module, Goals1, HeadVars),
|
expand_goal(Goals0, Module, Goals1, HeadVars, TGs),
|
||||||
ExpandedGoals = (\+ Goals1).
|
ExpandedGoals = (\+ Goals1).
|
||||||
expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars) :-
|
expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars, TGs) :-
|
||||||
expand_goal(Goals0, Module, Goals1, HeadVars),
|
expand_goal(Goals0, Module, Goals1, HeadVars, TGs),
|
||||||
ExpandedGoals = (Module:Goals1).
|
ExpandedGoals = (Module:Goals1).
|
||||||
|
|
||||||
:- non_counted_backtracking thread_goals/3.
|
:- non_counted_backtracking thread_goals/3.
|
||||||
|
|||||||
@@ -1423,6 +1423,7 @@ mod tests {
|
|||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn arith_eval_by_metacall_tests() {
|
fn arith_eval_by_metacall_tests() {
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
let mut op_dir = default_op_dir();
|
let mut op_dir = default_op_dir();
|
||||||
|
|||||||
@@ -42,42 +42,35 @@ pub(super) fn bootstrapping_compile(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
|
fn lower_bound_of_target_clause(skeleton: &mut PredicateSkeleton, target_pos: usize) -> usize {
|
||||||
if target_pos == 0 {
|
if target_pos == 0 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_num = skeleton.clauses[target_pos - 1].opt_arg_index_key.arg_num();
|
debug_assert!(skeleton.clauses.len() >= 2);
|
||||||
|
|
||||||
if arg_num == 0 {
|
let index = target_pos - 1;
|
||||||
return target_pos - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut index_loc_opt = None;
|
let index = if let Some(index_loc) = skeleton.clauses[index]
|
||||||
|
|
||||||
for index in (0..target_pos).rev() {
|
|
||||||
let current_arg_num = skeleton.clauses[index].opt_arg_index_key.arg_num();
|
|
||||||
|
|
||||||
if current_arg_num == 0 || current_arg_num != arg_num {
|
|
||||||
return index + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(index_loc) = index_loc_opt {
|
|
||||||
let current_index_loc = skeleton.clauses[index]
|
|
||||||
.opt_arg_index_key
|
.opt_arg_index_key
|
||||||
.switch_on_term_loc();
|
.switch_on_term_loc()
|
||||||
|
{
|
||||||
|
let search_result = skeleton.clauses.make_contiguous()
|
||||||
|
[0..skeleton.core.clause_assert_margin]
|
||||||
|
.partition_point(|clause_index_info| clause_index_info.clause_start > index_loc);
|
||||||
|
|
||||||
if Some(index_loc) != current_index_loc {
|
if search_result < skeleton.core.clause_assert_margin {
|
||||||
return index + 1;
|
search_result
|
||||||
|
} else {
|
||||||
|
skeleton.clauses.make_contiguous()[skeleton.core.clause_assert_margin..]
|
||||||
|
.partition_point(|clause_index_info| clause_index_info.clause_start < index_loc)
|
||||||
|
+ skeleton.core.clause_assert_margin
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
index_loc_opt = skeleton.clauses[index]
|
index
|
||||||
.opt_arg_index_key
|
};
|
||||||
.switch_on_term_loc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
0
|
index.clamp(0, skeleton.clauses.len() - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derelictize_try_me_else(
|
fn derelictize_try_me_else(
|
||||||
@@ -1215,7 +1208,7 @@ fn print_overwrite_warning(
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Warning: overwriting {}/{} because the clauses are discontiguous",
|
"% Warning: overwriting {}/{} because the clauses are discontiguous",
|
||||||
key.0.as_str(),
|
key.0.as_str(),
|
||||||
key.1
|
key.1
|
||||||
);
|
);
|
||||||
@@ -1327,7 +1320,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.clause_clause_locs
|
.clause_clause_locs
|
||||||
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
.extend(&clause_clause_locs.make_contiguous()[0..]);
|
||||||
|
|
||||||
let skeleton = cg.skeleton;
|
let mut skeleton = cg.skeleton;
|
||||||
|
skeleton.core.is_dynamic = settings.is_dynamic();
|
||||||
|
|
||||||
self.add_extensible_predicate(key, skeleton, predicates.compilation_target);
|
self.add_extensible_predicate(key, skeleton, predicates.compilation_target);
|
||||||
}
|
}
|
||||||
@@ -1527,6 +1521,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
let code_len = self.wam_prelude.code.len();
|
let code_len = self.wam_prelude.code.len();
|
||||||
|
|
||||||
|
standalone_skeleton.clauses[0].clause_start += code_len;
|
||||||
|
|
||||||
let skeleton = match self
|
let skeleton = match self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
@@ -1539,8 +1535,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
match append_or_prepend {
|
match append_or_prepend {
|
||||||
AppendOrPrepend::Append => {
|
AppendOrPrepend::Append => {
|
||||||
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
|
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
|
||||||
skeleton.clauses.push_back(clause_index_info);
|
|
||||||
|
|
||||||
|
skeleton.clauses.push_back(clause_index_info);
|
||||||
skeleton.core.clause_clause_locs.push_back(code_len);
|
skeleton.core.clause_clause_locs.push_back(code_len);
|
||||||
|
|
||||||
self.payload
|
self.payload
|
||||||
@@ -2148,7 +2144,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.map(|skeleton| skeleton.predicate_info())
|
.map(|skeleton| skeleton.predicate_info())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut predicate_info = self
|
let predicate_info = self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
|
.get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
|
||||||
@@ -2183,7 +2179,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
if is_cross_module_clause && !local_predicate_info.is_extensible {
|
if is_cross_module_clause && !local_predicate_info.is_extensible {
|
||||||
if predicate_info.is_multifile {
|
if predicate_info.is_multifile {
|
||||||
println!(
|
println!(
|
||||||
"Warning: overwriting multifile predicate {}:{}/{} because \
|
"% Warning: overwriting multifile predicate {}:{}/{} because \
|
||||||
it was not locally declared multifile.",
|
it was not locally declared multifile.",
|
||||||
self.payload.predicates.compilation_target,
|
self.payload.predicates.compilation_target,
|
||||||
key.0.as_str(),
|
key.0.as_str(),
|
||||||
@@ -2210,8 +2206,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
(0..skeleton.clauses.len()).map(Some).collect(),
|
(0..skeleton.clauses.len()).map(Some).collect(),
|
||||||
false, // the builtin M:'$clause'/2 is never dynamic.
|
false, // the builtin M:'$clause'/2 is never dynamic.
|
||||||
);
|
);
|
||||||
|
|
||||||
predicate_info.is_dynamic = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.payload
|
self.payload
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ mod tests {
|
|||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on atom_table.rs UB")]
|
||||||
fn copier_tests() {
|
fn copier_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
|||||||
@@ -557,20 +557,29 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut p = self.machine_st.p;
|
let mut p = self.machine_st.p;
|
||||||
|
let mut arity = 0;
|
||||||
|
|
||||||
while self.code[p].is_head_instr() {
|
while self.code[p].is_head_instr() {
|
||||||
|
for r in self.code[p].registers() {
|
||||||
|
if let RegType::Temp(t) = r {
|
||||||
|
arity = std::cmp::max(arity, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p += 1;
|
p += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let instr =
|
let instr = std::mem::replace(
|
||||||
std::mem::replace(&mut self.code[p], Instruction::VerifyAttrInterrupt);
|
&mut self.code[p],
|
||||||
|
Instruction::VerifyAttrInterrupt(arity),
|
||||||
|
);
|
||||||
|
|
||||||
self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr;
|
self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr;
|
||||||
self.machine_st.attr_var_init.cp = p;
|
self.machine_st.attr_var_init.cp = p;
|
||||||
}
|
}
|
||||||
&Instruction::VerifyAttrInterrupt => {
|
&Instruction::VerifyAttrInterrupt(arity) => {
|
||||||
let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity();
|
// let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity();
|
||||||
let arity = std::cmp::max(arity, self.machine_st.num_of_args);
|
// let arity = std::cmp::max(arity, self.machine_st.num_of_args);
|
||||||
self.run_verify_attr_interrupt(arity);
|
self.run_verify_attr_interrupt(arity);
|
||||||
}
|
}
|
||||||
&Instruction::Add(ref a1, ref a2, t) => {
|
&Instruction::Add(ref a1, ref a2, t) => {
|
||||||
@@ -4147,6 +4156,14 @@ impl Machine {
|
|||||||
try_or_throw!(self.machine_st, self.js_eval());
|
try_or_throw!(self.machine_st, self.js_eval());
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
|
&Instruction::CallArgv => {
|
||||||
|
try_or_throw!(self.machine_st, self.argv());
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteArgv => {
|
||||||
|
try_or_throw!(self.machine_st, self.argv());
|
||||||
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
|
}
|
||||||
&Instruction::CallCurrentTime => {
|
&Instruction::CallCurrentTime => {
|
||||||
self.current_time();
|
self.current_time();
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
@@ -4491,44 +4508,28 @@ impl Machine {
|
|||||||
self.crypto_curve_scalar_mult();
|
self.crypto_curve_scalar_mult();
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "crypto-full")]
|
&Instruction::CallEd25519SignRaw => {
|
||||||
&Instruction::CallEd25519Sign => {
|
self.ed25519_sign_raw();
|
||||||
self.ed25519_sign();
|
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "crypto-full")]
|
&Instruction::ExecuteEd25519SignRaw => {
|
||||||
&Instruction::ExecuteEd25519Sign => {
|
self.ed25519_sign_raw();
|
||||||
self.ed25519_sign();
|
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "crypto-full")]
|
&Instruction::CallEd25519VerifyRaw => {
|
||||||
&Instruction::CallEd25519Verify => {
|
self.ed25519_verify_raw();
|
||||||
self.ed25519_verify();
|
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "crypto-full")]
|
&Instruction::ExecuteEd25519VerifyRaw => {
|
||||||
&Instruction::ExecuteEd25519Verify => {
|
self.ed25519_verify_raw();
|
||||||
self.ed25519_verify();
|
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "crypto-full")]
|
&Instruction::CallEd25519SeedToPublicKey => {
|
||||||
&Instruction::CallEd25519NewKeyPair => {
|
self.ed25519_seed_to_public_key();
|
||||||
self.ed25519_new_key_pair();
|
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "crypto-full")]
|
&Instruction::ExecuteEd25519SeedToPublicKey => {
|
||||||
&Instruction::ExecuteEd25519NewKeyPair => {
|
self.ed25519_seed_to_public_key();
|
||||||
self.ed25519_new_key_pair();
|
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
|
||||||
}
|
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
&Instruction::CallEd25519KeyPairPublicKey => {
|
|
||||||
self.ed25519_key_pair_public_key();
|
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
|
||||||
}
|
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
&Instruction::ExecuteEd25519KeyPairPublicKey => {
|
|
||||||
self.ed25519_key_pair_public_key();
|
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||||
}
|
}
|
||||||
&Instruction::CallCurve25519ScalarMult => {
|
&Instruction::CallCurve25519ScalarMult => {
|
||||||
|
|||||||
@@ -369,6 +369,7 @@ mod tests {
|
|||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn heap_marking_tests() {
|
fn heap_marking_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ mod tests {
|
|||||||
use crate::machine::{QueryMatch, QueryResolution, Value};
|
use crate::machine::{QueryMatch, QueryResolution, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn programatic_query() {
|
fn programatic_query() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
|
|
||||||
@@ -275,6 +276,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn failing_query() {
|
fn failing_query() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
let query = String::from(r#"triple("a",P,"b")."#);
|
let query = String::from(r#"triple("a",P,"b")."#);
|
||||||
@@ -288,6 +290,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
fn complex_results() {
|
fn complex_results() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
machine.load_module_string(
|
machine.load_module_string(
|
||||||
@@ -344,6 +347,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn empty_predicate() {
|
fn empty_predicate() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
machine.load_module_string(
|
machine.load_module_string(
|
||||||
@@ -359,6 +363,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn list_results() {
|
fn list_results() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
machine.load_module_string(
|
machine.load_module_string(
|
||||||
@@ -387,6 +392,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn consult() {
|
fn consult() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
|
|
||||||
@@ -445,6 +451,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn integration_test() {
|
fn integration_test() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
|
|
||||||
@@ -495,6 +502,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn findall() {
|
fn findall() {
|
||||||
let mut machine = Machine::new_lib();
|
let mut machine = Machine::new_lib();
|
||||||
|
|
||||||
|
|||||||
@@ -466,24 +466,48 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (key, code_index) in removed_module.code_dir.iter_mut() {
|
let mut skipped_local_predicates = IndexSet::with_hasher(FxBuildHasher::default());
|
||||||
match removed_module
|
|
||||||
.local_extensible_predicates
|
for ((local_compilation_target, key), skeleton) in
|
||||||
.get(&(CompilationTarget::User, *key))
|
removed_module.local_extensible_predicates.iter()
|
||||||
{
|
{
|
||||||
Some(skeleton) if skeleton.is_multifile => continue,
|
skipped_local_predicates.insert(key);
|
||||||
_ => {}
|
|
||||||
|
if skeleton.is_multifile {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(code_index) = removed_module.code_dir.get_mut(key) {
|
||||||
|
if let Some(global_skeleton) = self
|
||||||
|
.wam_prelude
|
||||||
|
.indices
|
||||||
|
.get_predicate_skeleton(local_compilation_target, key)
|
||||||
|
{
|
||||||
|
let old_index_ptr = code_index.replace(if global_skeleton.core.is_dynamic {
|
||||||
|
IndexPtr::dynamic_undefined()
|
||||||
|
} else {
|
||||||
|
IndexPtr::undefined()
|
||||||
|
});
|
||||||
|
|
||||||
|
self.payload.retraction_info.push_record(
|
||||||
|
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (key, code_index) in removed_module.code_dir.iter_mut() {
|
||||||
|
if skipped_local_predicates.contains(key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !code_index.is_undefined() && !code_index.is_dynamic_undefined() {
|
||||||
let old_index_ptr = code_index.replace(IndexPtr::undefined());
|
let old_index_ptr = code_index.replace(IndexPtr::undefined());
|
||||||
|
|
||||||
self.payload
|
self.payload.retraction_info.push_record(
|
||||||
.retraction_info
|
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
||||||
.push_record(RetractionRecord::ReplacedModulePredicate(
|
);
|
||||||
module_name,
|
}
|
||||||
*key,
|
|
||||||
old_index_ptr,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, skeleton) in removed_module.extensible_predicates.drain(..) {
|
for (key, skeleton) in removed_module.extensible_predicates.drain(..) {
|
||||||
|
|||||||
@@ -1833,9 +1833,33 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scoped_clause_to_evacuable(&mut self) -> CallResult {
|
pub(crate) fn scoped_clause_to_evacuable(&mut self) -> CallResult {
|
||||||
let module_name = cell_as_atom!(self
|
let target = self.deref_register(1);
|
||||||
.machine_st
|
|
||||||
.store(self.machine_st.deref(self.machine_st.registers[1])));
|
let mut permission_error = || {
|
||||||
|
let err = self.machine_st.permission_error(
|
||||||
|
Permission::Modify,
|
||||||
|
atom!("static_procedure"),
|
||||||
|
functor_stub(atom!(":"), 2)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<MachineStub>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.machine_st
|
||||||
|
.error_form(err, functor_stub(atom!("load"), 1))
|
||||||
|
};
|
||||||
|
|
||||||
|
let module_name = read_heap_cell!(target,
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
if arity == 0 {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
return Err(permission_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(permission_error());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
let loader = self.loader_from_heap_evacuable(temp_v!(3));
|
let loader = self.loader_from_heap_evacuable(temp_v!(3));
|
||||||
|
|
||||||
@@ -1948,11 +1972,13 @@ impl Machine {
|
|||||||
_ => CompilationTarget::Module(module_name),
|
_ => CompilationTarget::Module(module_name),
|
||||||
};
|
};
|
||||||
|
|
||||||
let stub_gen = || match append_or_prepend {
|
let key = match append_or_prepend {
|
||||||
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
|
AppendOrPrepend::Append => (atom!("assertz"), 1),
|
||||||
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
|
AppendOrPrepend::Prepend => (atom!("asserta"), 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let stub_gen = || functor_stub(key.0, key.1);
|
||||||
|
|
||||||
let head = self.deref_register(2);
|
let head = self.deref_register(2);
|
||||||
|
|
||||||
if head.is_var() {
|
if head.is_var() {
|
||||||
@@ -1991,7 +2017,11 @@ impl Machine {
|
|||||||
.map(|code_idx| code_idx.get_tag())
|
.map(|code_idx| code_idx.get_tag())
|
||||||
.unwrap_or(IndexPtrTag::DynamicUndefined);
|
.unwrap_or(IndexPtrTag::DynamicUndefined);
|
||||||
|
|
||||||
idx_tag == IndexPtrTag::DynamicUndefined || idx_tag == IndexPtrTag::Undefined
|
if idx_tag == IndexPtrTag::Index {
|
||||||
|
return Err(SessionError::CannotOverwriteStaticProcedure((name, arity)));
|
||||||
|
} else {
|
||||||
|
idx_tag == IndexPtrTag::Undefined || idx_tag == IndexPtrTag::DynamicUndefined
|
||||||
|
}
|
||||||
} else if is_builtin {
|
} else if is_builtin {
|
||||||
return Err(SessionError::CannotOverwriteBuiltIn((name, arity)));
|
return Err(SessionError::CannotOverwriteBuiltIn((name, arity)));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -488,6 +488,13 @@ impl MachineState {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<MachineStub>(),
|
.collect::<MachineStub>(),
|
||||||
),
|
),
|
||||||
|
SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
|
||||||
|
Permission::Modify,
|
||||||
|
atom!("static_procedure"),
|
||||||
|
functor_stub(key.0, key.1)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<MachineStub>(),
|
||||||
|
),
|
||||||
SessionError::CannotOverwriteBuiltInModule(module) => {
|
SessionError::CannotOverwriteBuiltInModule(module) => {
|
||||||
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
||||||
}
|
}
|
||||||
@@ -1005,6 +1012,7 @@ pub enum SessionError {
|
|||||||
CompilationError(CompilationError),
|
CompilationError(CompilationError),
|
||||||
CannotOverwriteBuiltIn(PredicateKey),
|
CannotOverwriteBuiltIn(PredicateKey),
|
||||||
CannotOverwriteBuiltInModule(Atom),
|
CannotOverwriteBuiltInModule(Atom),
|
||||||
|
CannotOverwriteStaticProcedure(PredicateKey),
|
||||||
ExistenceError(ExistenceError),
|
ExistenceError(ExistenceError),
|
||||||
ModuleDoesNotContainExport(Atom, PredicateKey),
|
ModuleDoesNotContainExport(Atom, PredicateKey),
|
||||||
ModuleCannotImportSelf(Atom),
|
ModuleCannotImportSelf(Atom),
|
||||||
|
|||||||
@@ -1450,10 +1450,15 @@ impl MachineState {
|
|||||||
a1.as_var().unwrap(),
|
a1.as_var().unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Cons | HeapCellValueTag::Fixnum |
|
||||||
|
HeapCellValueTag::F64) if arity != 0 => {
|
||||||
|
let err = self.type_error(ValidType::Atom, store_name);
|
||||||
|
return Err(self.error_form(err, stub_gen())); // 8.5.1.3 e)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let err = self.type_error(ValidType::Atomic, store_name);
|
let err = self.type_error(ValidType::Atomic, store_name);
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen())); // 8.5.1.3 c)
|
||||||
} // 8.5.1.3 c)
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -260,6 +260,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn unify_tests() {
|
fn unify_tests() {
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
let mut op_dir = default_op_dir();
|
let mut op_dir = default_op_dir();
|
||||||
@@ -481,6 +482,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn test_unify_with_occurs_check() {
|
fn test_unify_with_occurs_check() {
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
let mut op_dir = default_op_dir();
|
let mut op_dir = default_op_dir();
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ impl Machine {
|
|||||||
self.machine_st.throw_exception(err);
|
self.machine_st.throw_exception(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_module_predicate(
|
pub fn run_module_predicate(
|
||||||
&mut self,
|
&mut self,
|
||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
@@ -307,29 +307,6 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_top_level(
|
|
||||||
&mut self,
|
|
||||||
module_name: Atom,
|
|
||||||
key: PredicateKey,
|
|
||||||
) -> std::process::ExitCode {
|
|
||||||
let mut arg_pstrs = vec![];
|
|
||||||
|
|
||||||
for arg in env::args() {
|
|
||||||
arg_pstrs.push(put_complete_string(
|
|
||||||
&mut self.machine_st.heap,
|
|
||||||
&arg,
|
|
||||||
&self.machine_st.atom_tbl,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.registers[1] = heap_loc_as_cell!(iter_to_heap_list(
|
|
||||||
&mut self.machine_st.heap,
|
|
||||||
arg_pstrs.into_iter()
|
|
||||||
));
|
|
||||||
|
|
||||||
self.run_module_predicate(module_name, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_user_input(&mut self, input: String) {
|
pub fn set_user_input(&mut self, input: String) {
|
||||||
self.user_input = Stream::from_owned_string(input, &mut self.machine_st.arena);
|
self.user_input = Stream::from_owned_string(input, &mut self.machine_st.arena);
|
||||||
}
|
}
|
||||||
@@ -414,7 +391,7 @@ impl Machine {
|
|||||||
self.code.extend(vec![
|
self.code.extend(vec![
|
||||||
Instruction::BreakFromDispatchLoop,
|
Instruction::BreakFromDispatchLoop,
|
||||||
Instruction::InstallVerifyAttr,
|
Instruction::InstallVerifyAttr,
|
||||||
Instruction::VerifyAttrInterrupt,
|
Instruction::VerifyAttrInterrupt(0),
|
||||||
Instruction::BreakFromDispatchLoop, // the location of LIB_QUERY_SUCCESS
|
Instruction::BreakFromDispatchLoop, // the location of LIB_QUERY_SUCCESS
|
||||||
Instruction::ExecuteTermGreaterThan,
|
Instruction::ExecuteTermGreaterThan,
|
||||||
Instruction::ExecuteTermLessThan,
|
Instruction::ExecuteTermLessThan,
|
||||||
@@ -925,8 +902,8 @@ impl Machine {
|
|||||||
|
|
||||||
self.machine_st.hb = self.machine_st.heap.len();
|
self.machine_st.hb = self.machine_st.heap.len();
|
||||||
|
|
||||||
self.machine_st.oip = 0;
|
// self.machine_st.oip = 0;
|
||||||
self.machine_st.iip = 0;
|
// self.machine_st.iip = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.p += offset;
|
self.machine_st.p += offset;
|
||||||
@@ -1010,8 +987,22 @@ impl Machine {
|
|||||||
|
|
||||||
self.machine_st.heap.truncate(target_h);
|
self.machine_st.heap.truncate(target_h);
|
||||||
|
|
||||||
self.machine_st.oip = 0;
|
// these registers don't need to be reset here and MUST
|
||||||
self.machine_st.iip = 0;
|
// NOT be (nor in indexed_try! trust_epilogue is an
|
||||||
|
// exception, see next paragraph)! oip could be reset
|
||||||
|
// without any adverse effects but iip is needed by
|
||||||
|
// get_clause_p to find the last executed clause/2 clause.
|
||||||
|
|
||||||
|
// trust_epilogue must reset these for the sake of
|
||||||
|
// subsequent predicates beginning with
|
||||||
|
// switch_to_term. get_clause_p copes by checking
|
||||||
|
// self.machine_st.b > self.machine.e: if true, it is safe
|
||||||
|
// to use self.machine_st.iip; if false, use the choice
|
||||||
|
// point left at the top of the stack by '$clause'
|
||||||
|
// (specifically its biip value).
|
||||||
|
|
||||||
|
// self.machine_st.oip = 0;
|
||||||
|
// self.machine_st.iip = 0;
|
||||||
} else {
|
} else {
|
||||||
self.trust_epilogue(offset);
|
self.trust_epilogue(offset);
|
||||||
}
|
}
|
||||||
@@ -1116,7 +1107,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
Unknown::Warn => {
|
Unknown::Warn => {
|
||||||
println!(
|
println!(
|
||||||
"warning: predicate {}/{} is undefined",
|
"% Warning: predicate {}/{} is undefined",
|
||||||
name.as_str(),
|
name.as_str(),
|
||||||
arity
|
arity
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -764,13 +764,29 @@ pub fn compare_pstr_prefixes<'a>(
|
|||||||
if i1.focus == empty_list_as_cell!() {
|
if i1.focus == empty_list_as_cell!() {
|
||||||
PStrCmpResult::Ordered(Ordering::Less)
|
PStrCmpResult::Ordered(Ordering::Less)
|
||||||
} else {
|
} else {
|
||||||
PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee)
|
let r2_step = r2.unwrap();
|
||||||
|
|
||||||
|
// advance i2 to the next character so the same character
|
||||||
|
// isn't repeated
|
||||||
|
if matches!(r2_step.iteratee, PStrIteratee::Char(..)) {
|
||||||
|
cycle_detection_step(i2, i1, &r2_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
PStrCmpResult::SecondIterContinuable(r2_step.iteratee)
|
||||||
}
|
}
|
||||||
} else if r2_at_end {
|
} else if r2_at_end {
|
||||||
if i2.focus == empty_list_as_cell!() {
|
if i2.focus == empty_list_as_cell!() {
|
||||||
PStrCmpResult::Ordered(Ordering::Greater)
|
PStrCmpResult::Ordered(Ordering::Greater)
|
||||||
} else {
|
} else {
|
||||||
PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee)
|
let r1_step = r1.unwrap();
|
||||||
|
|
||||||
|
// advance i1 to the next character so the same character
|
||||||
|
// isn't repeated
|
||||||
|
if matches!(r1_step.iteratee, PStrIteratee::Char(..)) {
|
||||||
|
cycle_detection_step(i1, i2, &r1_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
PStrCmpResult::FirstIterContinuable(r1_step.iteratee)
|
||||||
}
|
}
|
||||||
} else if i1.is_continuable() && i2.is_continuable() {
|
} else if i1.is_continuable() && i2.is_continuable() {
|
||||||
PStrCmpResult::Ordered(Ordering::Equal)
|
PStrCmpResult::Ordered(Ordering::Equal)
|
||||||
@@ -785,6 +801,7 @@ mod test {
|
|||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "blocked on streams.rs UB")]
|
||||||
fn pstr_iter_tests() {
|
fn pstr_iter_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
@@ -1089,9 +1106,119 @@ mod test {
|
|||||||
Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1))
|
Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1))
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert!(iter.next().is_none());
|
|
||||||
|
|
||||||
for _ in iter {}
|
for _ in iter {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #2293, test1.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a ")));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(1));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
|
|
||||||
|
// #2293, test2.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a")));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
|
|
||||||
|
// #2293, test3.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a b")));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(1));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
|
|
||||||
|
// #2293, test4.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a ")));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
|
|
||||||
|
// #2293, test5.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a bc")));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!(' '));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(6));
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
|
|
||||||
|
// #2293, test6.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abc")));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(1));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!('b'));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
|
|
||||||
|
// #2293, test7.
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abcde")));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!('a'));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(3));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(5));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!('c'));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(7));
|
||||||
|
wam.machine_st.heap.push(heap_loc_as_cell!(7));
|
||||||
|
wam.machine_st.heap.push(list_loc_as_cell!(9));
|
||||||
|
wam.machine_st.heap.push(char_as_cell!('e'));
|
||||||
|
wam.machine_st.heap.push(empty_list_as_cell!());
|
||||||
|
|
||||||
|
unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert!(!wam.machine_st.fail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -565,21 +565,6 @@ impl Preprocessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn try_term_to_query<'a, LS: LoadState<'a>>(
|
|
||||||
&mut self,
|
|
||||||
loader: &mut Loader<'a, LS>,
|
|
||||||
terms: Vec<Term>,
|
|
||||||
cut_context: CutContext,
|
|
||||||
) -> Result<TopLevel, CompilationError> {
|
|
||||||
Ok(TopLevel::Query(self.setup_query(
|
|
||||||
loader,
|
|
||||||
terms,
|
|
||||||
cut_context,
|
|
||||||
)?))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
@@ -607,20 +592,4 @@ impl Preprocessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
|
|
||||||
&mut self,
|
|
||||||
loader: &mut Loader<'a, LS>,
|
|
||||||
terms: I,
|
|
||||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
|
||||||
let mut results = VecDeque::new();
|
|
||||||
|
|
||||||
for term in terms.into_iter() {
|
|
||||||
results.push_back(self.try_term_to_tl(loader, term)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(results)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
:- module('$project_atts', [copy_term/3]).
|
:- module('$project_atts', []).
|
||||||
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(error), [can_be/2]).
|
:- use_module(library(error), [can_be/2]).
|
||||||
@@ -100,14 +100,6 @@ gather_residual_goals([V|Vs]) -->
|
|||||||
|
|
||||||
delete_all_attributes_from_var(V) :- '$delete_all_attributes_from_var'(V).
|
delete_all_attributes_from_var(V) :- '$delete_all_attributes_from_var'(V).
|
||||||
|
|
||||||
copy_term(Term, Copy, Gs) :-
|
|
||||||
can_be(list, Gs),
|
|
||||||
findall(Term-Rs, term_residual_goals(Term,Rs), [Copy-Gs]),
|
|
||||||
( var(Gs) ->
|
|
||||||
Gs = []
|
|
||||||
; true
|
|
||||||
).
|
|
||||||
|
|
||||||
term_residual_goals(Term,Rs) :-
|
term_residual_goals(Term,Rs) :-
|
||||||
'$term_attributed_variables'(Term, Vs),
|
'$term_attributed_variables'(Term, Vs),
|
||||||
phrase(gather_residual_goals(Vs), Rs),
|
phrase(gather_residual_goals(Vs), Rs),
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ impl Stack {
|
|||||||
|
|
||||||
for idx in 0..num_cells {
|
for idx in 0..num_cells {
|
||||||
ptr::write(
|
ptr::write(
|
||||||
(new_ptr as usize + offset) as *mut HeapCellValue,
|
new_ptr.add(offset) as *mut HeapCellValue,
|
||||||
stack_loc_as_cell!(AndFrame, e, idx + 1),
|
stack_loc_as_cell!(AndFrame, e, idx + 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -203,6 +203,10 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn top(&self) -> usize {
|
||||||
|
unsafe { (*self.buf.ptr.get()) as usize - self.buf.base as usize }
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
||||||
let frame_size = OrFrame::size_of(num_cells);
|
let frame_size = OrFrame::size_of(num_cells);
|
||||||
|
|
||||||
@@ -238,7 +242,8 @@ impl Stack {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
|
pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.buf.base as usize + e;
|
// This is doing alignment wrong
|
||||||
|
let ptr = self.buf.base.add(e);
|
||||||
&mut *(ptr as *mut AndFrame)
|
&mut *(ptr as *mut AndFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,6 +281,7 @@ mod tests {
|
|||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
fn stack_tests() {
|
fn stack_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ macro_rules! arena_allocated_impl_for_stream {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// Miri seems to hit this a lot
|
||||||
ptr::write(dst, self);
|
ptr::write(dst, self);
|
||||||
TypedArenaPtr::new(dst as *mut Self)
|
TypedArenaPtr::new(dst as *mut Self)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,14 +81,11 @@ use ring::rand::{SecureRandom, SystemRandom};
|
|||||||
use ring::{digest, hkdf, pbkdf2};
|
use ring::{digest, hkdf, pbkdf2};
|
||||||
|
|
||||||
#[cfg(feature = "crypto-full")]
|
#[cfg(feature = "crypto-full")]
|
||||||
use ring::{
|
use ring::aead;
|
||||||
aead,
|
|
||||||
signature::{self, KeyPair},
|
|
||||||
};
|
|
||||||
use ripemd160::{Digest, Ripemd160};
|
use ripemd160::{Digest, Ripemd160};
|
||||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
||||||
|
|
||||||
use crrl::{secp256k1, x25519};
|
use crrl::{ed25519, secp256k1, x25519};
|
||||||
|
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
use native_tls::{Identity, TlsAcceptor, TlsConnector};
|
use native_tls::{Identity, TlsAcceptor, TlsConnector};
|
||||||
@@ -1171,43 +1168,12 @@ impl Machine {
|
|||||||
.get_predicate_skeleton(&compilation_target, &key)
|
.get_predicate_skeleton(&compilation_target, &key)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if self.machine_st.b > self.machine_st.e {
|
|
||||||
let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b);
|
|
||||||
let bp = or_frame.prelude.bp;
|
|
||||||
|
|
||||||
match &self.code[bp] {
|
|
||||||
Instruction::IndexingCode(ref indexing_code) => {
|
|
||||||
match &indexing_code[or_frame.prelude.boip as usize] {
|
|
||||||
IndexingLine::IndexedChoice(ref indexed_choice) => {
|
|
||||||
let p = or_frame.prelude.biip as usize - 1;
|
|
||||||
|
|
||||||
match &indexed_choice[p] {
|
|
||||||
&IndexedChoiceInstruction::Try(offset)
|
|
||||||
| &IndexedChoiceInstruction::Retry(offset)
|
|
||||||
| &IndexedChoiceInstruction::DefaultRetry(offset) => {
|
|
||||||
let clause_clause_loc = skeleton.core.clause_clause_locs[p];
|
|
||||||
(clause_clause_loc, bp + offset)
|
|
||||||
}
|
|
||||||
&IndexedChoiceInstruction::Trust(_)
|
|
||||||
| &IndexedChoiceInstruction::DefaultTrust(_) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let module_name = match compilation_target {
|
let module_name = match compilation_target {
|
||||||
CompilationTarget::User => atom!("builtins"),
|
CompilationTarget::User => atom!("builtins"),
|
||||||
CompilationTarget::Module(target) => target,
|
CompilationTarget::Module(target) => target,
|
||||||
};
|
};
|
||||||
|
|
||||||
let bp = self
|
let mut bp = self
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_code_index(atom!("$clause"), 2, module_name)
|
.get_predicate_code_index(atom!("$clause"), 2, module_name)
|
||||||
.and_then(|idx| idx.local())
|
.and_then(|idx| idx.local())
|
||||||
@@ -1228,6 +1194,7 @@ impl Machine {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
match &self.code[bp] {
|
match &self.code[bp] {
|
||||||
Instruction::IndexingCode(ref indexing_code) => {
|
Instruction::IndexingCode(ref indexing_code) => {
|
||||||
let indexing_code_ptr = match &indexing_code[0] {
|
let indexing_code_ptr = match &indexing_code[0] {
|
||||||
@@ -1263,14 +1230,38 @@ impl Machine {
|
|||||||
|
|
||||||
match &indexing_code[boip] {
|
match &indexing_code[boip] {
|
||||||
IndexingLine::IndexedChoice(indexed_choice) => {
|
IndexingLine::IndexedChoice(indexed_choice) => {
|
||||||
|
let p = if self.machine_st.b > self.machine_st.e {
|
||||||
|
// this means the last
|
||||||
|
// self.machine_st.iip value has yet
|
||||||
|
// to be overwritten by the Trust
|
||||||
|
// instruction. In this case, return
|
||||||
|
// it.
|
||||||
|
self.machine_st.iip as usize
|
||||||
|
} else {
|
||||||
|
// otherwise, read the '$clause'
|
||||||
|
// choicepoint from the top of the
|
||||||
|
// stack. this is very volatile in
|
||||||
|
// that it depends on '$clause'
|
||||||
|
// immediately preceding
|
||||||
|
// '$get_clause_p', which cannot be
|
||||||
|
// the last clause of the retract
|
||||||
|
// helper to delay deallocation of its
|
||||||
|
// environment frame.
|
||||||
|
let clause_b = self.machine_st.stack.top();
|
||||||
|
self.machine_st.stack.index_or_frame(clause_b).prelude.biip as usize
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
skeleton.core.clause_clause_locs.back().cloned().unwrap(),
|
skeleton.core.clause_clause_locs[p],
|
||||||
bp + indexed_choice.back().unwrap().offset(),
|
bp + indexed_choice[p].offset(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&Instruction::RevJmpBy(offset) => {
|
||||||
|
bp -= offset;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return (
|
return (
|
||||||
skeleton.core.clause_clause_locs.back().cloned().unwrap(),
|
skeleton.core.clause_clause_locs.back().cloned().unwrap(),
|
||||||
@@ -3501,6 +3492,12 @@ impl Machine {
|
|||||||
Some(Ok(c)) => {
|
Some(Ok(c)) => {
|
||||||
string.push(c);
|
string.push(c);
|
||||||
}
|
}
|
||||||
|
Some(Err(e)) => {
|
||||||
|
let stub = functor_stub(atom!("$get_n_chars"), 3);
|
||||||
|
let err = self.machine_st.session_error(SessionError::from(e));
|
||||||
|
|
||||||
|
return Err(self.machine_st.error_form(err, stub));
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -4291,18 +4288,18 @@ impl Machine {
|
|||||||
let address_string = address_sink.as_str(); //to_string();
|
let address_string = address_sink.as_str(); //to_string();
|
||||||
let address: Url = address_string.parse().unwrap();
|
let address: Url = address_string.parse().unwrap();
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::builder().build().unwrap();
|
let client = reqwest::Client::builder().build().unwrap();
|
||||||
|
|
||||||
// request
|
// request
|
||||||
let mut req = reqwest::blocking::Request::new(method, address);
|
let mut req = reqwest::Request::new(method, address);
|
||||||
|
|
||||||
*req.headers_mut() = headers;
|
*req.headers_mut() = headers;
|
||||||
if !bytes.is_empty() {
|
if !bytes.is_empty() {
|
||||||
*req.body_mut() = Some(reqwest::blocking::Body::from(bytes));
|
*req.body_mut() = Some(reqwest::Body::from(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
// do it!
|
// do it!
|
||||||
match client.execute(req) {
|
match futures::executor::block_on(client.execute(req)) {
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
// status code
|
// status code
|
||||||
let status = resp.status().as_u16();
|
let status = resp.status().as_u16();
|
||||||
@@ -4339,7 +4336,7 @@ impl Machine {
|
|||||||
self.machine_st.registers[6]
|
self.machine_st.registers[6]
|
||||||
);
|
);
|
||||||
// body
|
// body
|
||||||
let reader = resp.bytes().unwrap().reader();
|
let reader = futures::executor::block_on(resp.bytes()).unwrap().reader();
|
||||||
|
|
||||||
let mut stream = Stream::from_http_stream(
|
let mut stream = Stream::from_http_stream(
|
||||||
AtomTable::build_with(&self.machine_st.atom_tbl, &address_string),
|
AtomTable::build_with(&self.machine_st.atom_tbl, &address_string),
|
||||||
@@ -4953,6 +4950,27 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn argv(&mut self) -> CallResult {
|
||||||
|
let args = self.deref_register(1);
|
||||||
|
|
||||||
|
let mut args_pstrs = vec![];
|
||||||
|
for arg in env::args() {
|
||||||
|
args_pstrs.push(put_complete_string(
|
||||||
|
&mut self.machine_st.heap,
|
||||||
|
&arg,
|
||||||
|
&self.machine_st.atom_tbl,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let cell = heap_loc_as_cell!(iter_to_heap_list(
|
||||||
|
&mut self.machine_st.heap,
|
||||||
|
args_pstrs.into_iter()
|
||||||
|
));
|
||||||
|
|
||||||
|
unify!(self.machine_st, args, cell);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn current_time(&mut self) {
|
pub(crate) fn current_time(&mut self) {
|
||||||
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
|
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
|
||||||
@@ -5721,11 +5739,11 @@ impl Machine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) {
|
pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) {
|
||||||
match &self.code[VERIFY_ATTR_INTERRUPT_LOC] {
|
match &self.code[VERIFY_ATTR_INTERRUPT_LOC] {
|
||||||
&Instruction::VerifyAttrInterrupt => {}
|
&Instruction::VerifyAttrInterrupt(_) => {}
|
||||||
_ => {
|
_ => {
|
||||||
let instr = mem::replace(
|
let instr = mem::replace(
|
||||||
&mut self.code[VERIFY_ATTR_INTERRUPT_LOC],
|
&mut self.code[VERIFY_ATTR_INTERRUPT_LOC],
|
||||||
Instruction::VerifyAttrInterrupt,
|
Instruction::VerifyAttrInterrupt(0),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.code[self.machine_st.attr_var_init.cp] = instr;
|
self.code[self.machine_st.attr_var_init.cp] = instr;
|
||||||
@@ -6520,10 +6538,8 @@ impl Machine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if had_zero_port {
|
if had_zero_port {
|
||||||
self.machine_st.unify_fixnum(
|
self.machine_st
|
||||||
Fixnum::build_with(port as i64),
|
.unify_fixnum(Fixnum::build_with(port as i64), self.deref_register(2));
|
||||||
self.machine_st.registers[2],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -7625,33 +7641,16 @@ impl Machine {
|
|||||||
unify!(self.machine_st, self.machine_st.registers[4], uncompressed);
|
unify!(self.machine_st, self.machine_st.registers[4], uncompressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn ed25519_new_key_pair(&mut self) {
|
pub(crate) fn ed25519_seed_to_public_key(&mut self) {
|
||||||
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
|
let stub_gen = || functor_stub(atom!("ed25519_seed_keypair"), 2);
|
||||||
let complete_string = self.u8s_to_string(pkcs8_bytes.as_ref());
|
let seed_bytes = self
|
||||||
|
.machine_st
|
||||||
|
.integers_to_bytevec(self.machine_st.registers[1], stub_gen);
|
||||||
|
|
||||||
unify!(
|
let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
|
||||||
self.machine_st,
|
|
||||||
self.machine_st.registers[1],
|
|
||||||
complete_string
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "crypto-full")]
|
let complete_string = self.u8s_to_string(skey.public_key.encoded.as_ref());
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn ed25519_key_pair_public_key(&mut self) {
|
|
||||||
let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
|
|
||||||
|
|
||||||
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
|
|
||||||
Ok(kp) => kp,
|
|
||||||
_ => {
|
|
||||||
self.machine_st.fail = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let complete_string = self.u8s_to_string(key_pair.public_key().as_ref());
|
|
||||||
|
|
||||||
unify!(
|
unify!(
|
||||||
self.machine_st,
|
self.machine_st,
|
||||||
@@ -7660,22 +7659,19 @@ impl Machine {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn ed25519_sign(&mut self) {
|
pub(crate) fn ed25519_sign_raw(&mut self) {
|
||||||
let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
|
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 skey = ed25519::PrivateKey::from_seed(&seed_bytes);
|
||||||
|
|
||||||
let encoding = cell_as_atom!(self.deref_register(3));
|
let encoding = cell_as_atom!(self.deref_register(3));
|
||||||
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
|
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
|
||||||
|
|
||||||
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
|
let sig = skey.sign_raw(&data);
|
||||||
Ok(kp) => kp,
|
|
||||||
_ => {
|
|
||||||
self.machine_st.fail = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sig = key_pair.sign(&data);
|
|
||||||
|
|
||||||
let sig_list = heap_loc_as_cell!(iter_to_heap_list(
|
let sig_list = heap_loc_as_cell!(iter_to_heap_list(
|
||||||
&mut self.machine_st.heap,
|
&mut self.machine_st.heap,
|
||||||
@@ -7687,25 +7683,21 @@ impl Machine {
|
|||||||
unify!(self.machine_st, self.machine_st.registers[4], sig_list);
|
unify!(self.machine_st, self.machine_st.registers[4], sig_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "crypto-full")]
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn ed25519_verify(&mut self) {
|
pub(crate) fn ed25519_verify_raw(&mut self) {
|
||||||
let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
|
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 encoding = cell_as_atom!(self.deref_register(3));
|
||||||
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
|
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
|
||||||
let stub_gen = || functor_stub(atom!("ed25519_verify"), 5);
|
|
||||||
|
let stub_gen = || functor_stub(atom!("ed25519_verify"), 4);
|
||||||
|
|
||||||
let signature = self
|
let signature = self
|
||||||
.machine_st
|
.machine_st
|
||||||
.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
|
.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
|
||||||
|
|
||||||
let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
|
self.machine_st.fail = !pkey.verify_raw(&signature, &data);
|
||||||
|
|
||||||
match peer_public_key.verify(&data, &signature) {
|
|
||||||
Ok(_) => {}
|
|
||||||
_ => {
|
|
||||||
self.machine_st.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|||||||
@@ -173,6 +173,98 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1);
|
let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1);
|
||||||
let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1);
|
let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1);
|
||||||
|
|
||||||
|
fn unify_sequence(
|
||||||
|
machine_st: &mut MachineState,
|
||||||
|
iter: PStrIteratee,
|
||||||
|
source_cell: HeapCellValue,
|
||||||
|
) -> bool {
|
||||||
|
match iter {
|
||||||
|
PStrIteratee::Char(focus, _) => {
|
||||||
|
machine_st.pdl.push(machine_st.heap[focus]);
|
||||||
|
machine_st.pdl.push(source_cell);
|
||||||
|
}
|
||||||
|
PStrIteratee::PStrSegment(focus, _, n) => {
|
||||||
|
read_heap_cell!(machine_st.heap[focus],
|
||||||
|
(HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
|
||||||
|
if focus < machine_st.heap.len() - 2 {
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
let target_cell = match machine_st.heap[focus].get_tag() {
|
||||||
|
HeapCellValueTag::CStr => {
|
||||||
|
atom_as_cstr_cell!(pstr_atom)
|
||||||
|
}
|
||||||
|
HeapCellValueTag::PStr => {
|
||||||
|
pstr_loc_as_cell!(focus)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
machine_st.pdl.push(target_cell);
|
||||||
|
machine_st.pdl.push(source_cell);
|
||||||
|
} else {
|
||||||
|
let h_len = machine_st.heap.len();
|
||||||
|
|
||||||
|
machine_st.heap.push(pstr_offset_as_cell!(focus));
|
||||||
|
machine_st.heap.push(fixnum_as_cell!(
|
||||||
|
Fixnum::build_with(n as i64)
|
||||||
|
));
|
||||||
|
|
||||||
|
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
||||||
|
machine_st.pdl.push(source_cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrOffset, pstr_loc) => {
|
||||||
|
let n0 = cell_as_fixnum!(machine_st.heap[focus+1])
|
||||||
|
.get_num() as usize;
|
||||||
|
|
||||||
|
if pstr_loc < machine_st.heap.len() - 2 {
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == n0 {
|
||||||
|
machine_st.pdl.push(pstr_loc_as_cell!(focus));
|
||||||
|
machine_st.pdl.push(source_cell);
|
||||||
|
} else {
|
||||||
|
let h_len = machine_st.heap.len();
|
||||||
|
|
||||||
|
machine_st.heap.push(pstr_offset_as_cell!(pstr_loc));
|
||||||
|
machine_st.heap.push(fixnum_as_cell!(
|
||||||
|
Fixnum::build_with(n as i64)
|
||||||
|
));
|
||||||
|
|
||||||
|
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
||||||
|
machine_st.pdl.push(source_cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if focus < machine_st.heap.len() - 2 {
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_st.pdl.push(machine_st.heap[focus]);
|
||||||
|
machine_st.pdl.push(source_cell);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
||||||
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
||||||
PStrCmpResult::Ordered(Ordering::Less) => {
|
PStrCmpResult::Ordered(Ordering::Less) => {
|
||||||
@@ -229,90 +321,14 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
|
||||||
|
unify_sequence(machine_st, chars_iter.item.unwrap(), focus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||||
match chars_iter.item.unwrap() {
|
if unify_sequence(machine_st, chars_iter.item.unwrap(), heap_loc_as_cell!(h)) {
|
||||||
PStrIteratee::Char(focus, _) => {
|
|
||||||
machine_st.pdl.push(machine_st.heap[focus]);
|
|
||||||
machine_st.pdl.push(heap_loc_as_cell!(h));
|
|
||||||
}
|
|
||||||
PStrIteratee::PStrSegment(focus, _, n) => {
|
|
||||||
read_heap_cell!(machine_st.heap[focus],
|
|
||||||
(HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
|
|
||||||
if focus < machine_st.heap.len() - 2 {
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
let target_cell = match machine_st.heap[focus].get_tag() {
|
|
||||||
HeapCellValueTag::CStr => {
|
|
||||||
atom_as_cstr_cell!(pstr_atom)
|
|
||||||
}
|
|
||||||
HeapCellValueTag::PStr => {
|
|
||||||
pstr_loc_as_cell!(focus)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
machine_st.pdl.push(target_cell);
|
|
||||||
machine_st.pdl.push(heap_loc_as_cell!(h));
|
|
||||||
} else {
|
|
||||||
let h_len = machine_st.heap.len();
|
|
||||||
|
|
||||||
machine_st.heap.push(pstr_offset_as_cell!(focus));
|
|
||||||
machine_st.heap.push(fixnum_as_cell!(
|
|
||||||
Fixnum::build_with(n as i64)
|
|
||||||
));
|
|
||||||
|
|
||||||
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
|
||||||
machine_st.pdl.push(heap_loc_as_cell!(h));
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrOffset, pstr_loc) => {
|
|
||||||
let n0 = cell_as_fixnum!(machine_st.heap[focus+1])
|
|
||||||
.get_num() as usize;
|
|
||||||
|
|
||||||
if pstr_loc < machine_st.heap.len() - 2 {
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == n0 {
|
|
||||||
machine_st.pdl.push(pstr_loc_as_cell!(focus));
|
|
||||||
machine_st.pdl.push(heap_loc_as_cell!(h));
|
|
||||||
} else {
|
|
||||||
let h_len = machine_st.heap.len();
|
|
||||||
|
|
||||||
machine_st.heap.push(pstr_offset_as_cell!(pstr_loc));
|
|
||||||
machine_st.heap.push(fixnum_as_cell!(
|
|
||||||
Fixnum::build_with(n as i64)
|
|
||||||
));
|
|
||||||
|
|
||||||
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
|
||||||
machine_st.pdl.push(heap_loc_as_cell!(h));
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if focus < machine_st.heap.len() - 2 {
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
machine_st.pdl.push(machine_st.heap[focus]);
|
|
||||||
machine_st.pdl.push(heap_loc_as_cell!(h));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break 'outer;
|
break 'outer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -417,6 +417,9 @@ impl ParserError {
|
|||||||
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
||||||
atom!("unexpected_end_of_file")
|
atom!("unexpected_end_of_file")
|
||||||
}
|
}
|
||||||
|
ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
|
||||||
|
atom!("invalid_data")
|
||||||
|
}
|
||||||
ParserError::IO(_) => atom!("input_output_error"),
|
ParserError::IO(_) => atom!("input_output_error"),
|
||||||
ParserError::LexicalError(_) => atom!("lexical_error"),
|
ParserError::LexicalError(_) => atom!("lexical_error"),
|
||||||
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
||||||
|
|||||||
@@ -144,21 +144,7 @@ impl<R: Read> CharRead for CharReader<R> {
|
|||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e)),
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
let bad_bytes_error = |buf: &[u8]| {
|
||||||
let buf = &self.buf[self.pos..];
|
|
||||||
|
|
||||||
if !buf.is_empty() {
|
|
||||||
let e = match str::from_utf8(buf) {
|
|
||||||
Ok(s) => {
|
|
||||||
let mut chars = s.chars();
|
|
||||||
let c = chars.next().unwrap();
|
|
||||||
|
|
||||||
return Some(Ok(c));
|
|
||||||
}
|
|
||||||
Err(e) => e,
|
|
||||||
};
|
|
||||||
|
|
||||||
if buf.len() - e.valid_up_to() >= 4 {
|
|
||||||
// If we have 4 bytes that still don't make up
|
// If we have 4 bytes that still don't make up
|
||||||
// a valid code point, then we have garbage.
|
// a valid code point, then we have garbage.
|
||||||
|
|
||||||
@@ -184,13 +170,28 @@ impl<R: Read> CharRead for CharReader<R> {
|
|||||||
// the buffer, it will be returned on the next
|
// the buffer, it will be returned on the next
|
||||||
// loop.
|
// loop.
|
||||||
|
|
||||||
return Some(Err(io::Error::new(
|
io::Error::new(io::ErrorKind::InvalidData, BadUtf8Error { bytes: badbytes })
|
||||||
io::ErrorKind::InvalidData,
|
};
|
||||||
BadUtf8Error { bytes: badbytes },
|
|
||||||
)));
|
loop {
|
||||||
|
let buf = &self.buf[self.pos..];
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
let e = match str::from_utf8(buf) {
|
||||||
|
Ok(s) => {
|
||||||
|
let mut chars = s.chars();
|
||||||
|
let c = chars.next().unwrap();
|
||||||
|
|
||||||
|
return Some(Ok(c));
|
||||||
|
}
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
|
||||||
|
if buf.len() - e.valid_up_to() >= 4 {
|
||||||
|
return Some(Err(bad_bytes_error(buf)));
|
||||||
} else if self.pos >= self.buf.len() {
|
} else if self.pos >= self.buf.len() {
|
||||||
return None;
|
return None;
|
||||||
} else if self.buf.len() - self.pos >= 4 {
|
} else if self.buf.len() - self.pos >= 4 && self.pos < e.valid_up_to() {
|
||||||
return match str::from_utf8(&self.buf[self.pos..e.valid_up_to()]) {
|
return match str::from_utf8(&self.buf[self.pos..e.valid_up_to()]) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let mut chars = s.chars();
|
let mut chars = s.chars();
|
||||||
@@ -217,18 +218,22 @@ impl<R: Read> CharRead for CharReader<R> {
|
|||||||
self.buf.truncate(buf_len - self.pos);
|
self.buf.truncate(buf_len - self.pos);
|
||||||
|
|
||||||
let buf_len = self.buf.len();
|
let buf_len = self.buf.len();
|
||||||
|
self.pos = 0;
|
||||||
|
|
||||||
|
if buf_len >= 4 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let mut word = [0u8; 4];
|
let mut word = [0u8; 4];
|
||||||
let word_slice = &mut word[buf_len..4];
|
let word_slice = &mut word[buf_len..4];
|
||||||
|
|
||||||
match self.inner.read(word_slice) {
|
match self.inner.read(word_slice) {
|
||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e)),
|
||||||
|
Ok(nread) if nread == 0 => return Some(Err(bad_bytes_error(&self.buf))),
|
||||||
Ok(nread) => {
|
Ok(nread) => {
|
||||||
self.buf.extend_from_slice(&word_slice[0..nread]);
|
self.buf.extend_from_slice(&word_slice[0..nread]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pos = 0;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@@ -375,6 +380,7 @@ mod tests {
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "slow and not very relevant")]
|
||||||
fn plain_string() {
|
fn plain_string() {
|
||||||
let mut read_string = CharReader::new(Cursor::new("a string"));
|
let mut read_string = CharReader::new(Cursor::new("a string"));
|
||||||
|
|
||||||
@@ -387,6 +393,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "slow and not very relevant")]
|
||||||
fn greek_string() {
|
fn greek_string() {
|
||||||
let mut read_string = CharReader::new(Cursor::new("λέξη"));
|
let mut read_string = CharReader::new(Cursor::new("λέξη"));
|
||||||
|
|
||||||
@@ -399,6 +406,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "slow and not very relevant")]
|
||||||
fn russian_string() {
|
fn russian_string() {
|
||||||
let mut read_string = CharReader::new(Cursor::new("слово"));
|
let mut read_string = CharReader::new(Cursor::new("слово"));
|
||||||
|
|
||||||
@@ -411,6 +419,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "slow and not very relevant")]
|
||||||
fn greek_lorem_ipsum() {
|
fn greek_lorem_ipsum() {
|
||||||
let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ
|
let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ
|
||||||
εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ
|
εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ
|
||||||
@@ -482,6 +491,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "slow and not very relevant")]
|
||||||
fn armenian_lorem_ipsum() {
|
fn armenian_lorem_ipsum() {
|
||||||
let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո
|
let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո
|
||||||
սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում
|
սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում
|
||||||
@@ -555,6 +565,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "slow and not very relevant")]
|
||||||
fn russian_lorem_ipsum() {
|
fn russian_lorem_ipsum() {
|
||||||
let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи
|
let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи
|
||||||
сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи
|
сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи
|
||||||
|
|||||||
@@ -97,7 +97,12 @@ pub(crate) fn as_partial_string(
|
|||||||
string.push(*c);
|
string.push(*c);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
|
tail = Term::Cons(
|
||||||
|
Cell::default(),
|
||||||
|
Box::new((**prev).clone()),
|
||||||
|
Box::new((**succ).clone()),
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -880,11 +885,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
|
.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack[idx].spec = if self.stack[idx].priority > 0 {
|
self.stack[idx].spec = BTERM;
|
||||||
TERM
|
|
||||||
} else {
|
|
||||||
BTERM
|
|
||||||
};
|
|
||||||
self.stack[idx].tt = TokenType::Term;
|
self.stack[idx].tt = TokenType::Term;
|
||||||
self.stack[idx].priority = 0;
|
self.stack[idx].priority = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
||||||
|
|
||||||
self.base = alloc::alloc(layout) as *const _;
|
self.base = alloc::alloc(layout) as *const _;
|
||||||
self.top = (self.base as usize + cap) as *const _;
|
self.top = self.base.add(cap);
|
||||||
*self.ptr.get_mut() = self.base as *mut _;
|
*self.ptr.get_mut() = self.base as *mut _;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
|
pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
|
||||||
if self.free_space() >= size {
|
if self.free_space() >= size {
|
||||||
let ptr = *self.ptr.get();
|
let ptr = *self.ptr.get();
|
||||||
*self.ptr.get() = (ptr as usize + size) as *mut _;
|
*self.ptr.get() = ptr.add(size) as *mut _;
|
||||||
ptr
|
ptr
|
||||||
} else {
|
} else {
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ impl ReadlineStream {
|
|||||||
if let Some(mut path) = dirs_next::home_dir() {
|
if let Some(mut path) = dirs_next::home_dir() {
|
||||||
path.push(HISTORY_FILE);
|
path.push(HISTORY_FILE);
|
||||||
if path.exists() && rl.load_history(&path).is_err() {
|
if path.exists() && rl.load_history(&path).is_err() {
|
||||||
println!("Warning: loading history failed");
|
println!("% Warning: loading history failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,10 +213,10 @@ impl ReadlineStream {
|
|||||||
path.push(HISTORY_FILE);
|
path.push(HISTORY_FILE);
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
if self.rl.append_history(&path).is_err() {
|
if self.rl.append_history(&path).is_err() {
|
||||||
println!("Warning: couldn't append history (existing file)");
|
println!("% Warning: couldn't append history (existing file)");
|
||||||
}
|
}
|
||||||
} else if self.rl.save_history(&path).is_err() {
|
} else if self.rl.save_history(&path).is_err() {
|
||||||
println!("Warning: couldn't save history (new file)");
|
println!("% Warning: couldn't save history (new file)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**/
|
/**/
|
||||||
|
|
||||||
:- use_module(library(format)).
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(format)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(debug)).
|
:- use_module(library(debug)).
|
||||||
:- use_module(library(atts)).
|
:- use_module(library(iso_ext)).
|
||||||
:- use_module(library(dif)).
|
:- use_module(library(dif)).
|
||||||
|
|
||||||
% Tests from https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif
|
% Tests from https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif
|
||||||
|
|||||||
145
src/tests/when.pl
Normal file
145
src/tests/when.pl
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/**/
|
||||||
|
|
||||||
|
:- use_module(library(iso_ext)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(debug)).
|
||||||
|
|
||||||
|
:- use_module(library(when)).
|
||||||
|
|
||||||
|
test("condition true before ground/1",(
|
||||||
|
A = 1,
|
||||||
|
when(ground(A), Run = true),
|
||||||
|
Run == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true before nonvar/1",(
|
||||||
|
A = a(_),
|
||||||
|
when(nonvar(A), Run = true),
|
||||||
|
Run == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true before ','/2",(
|
||||||
|
A = 1,
|
||||||
|
B = a(_),
|
||||||
|
when((ground(A), nonvar(B)), Run = true),
|
||||||
|
Run == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true before (;)/2",(
|
||||||
|
A = 1,
|
||||||
|
when((ground(A) ; nonvar(_)), Run1 = true),
|
||||||
|
Run1 == true,
|
||||||
|
|
||||||
|
B = a(_),
|
||||||
|
when((ground(_) ; nonvar(B)), Run2 = true),
|
||||||
|
Run2 == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true after ground/1",(
|
||||||
|
when(ground(A), Run = true),
|
||||||
|
var(Run),
|
||||||
|
A = 1,
|
||||||
|
Run == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true after nonvar/1",(
|
||||||
|
when(nonvar(A), Run = true),
|
||||||
|
var(Run),
|
||||||
|
A = a(_),
|
||||||
|
Run == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true after ','/2",(
|
||||||
|
when((ground(A), nonvar(B)), Run = true),
|
||||||
|
var(Run),
|
||||||
|
A = 1,
|
||||||
|
var(Run),
|
||||||
|
B = a(_),
|
||||||
|
Run == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("condition true after (;)/2",(
|
||||||
|
when((ground(A) ; nonvar(_)), Run1 = true),
|
||||||
|
var(Run1),
|
||||||
|
A = 1,
|
||||||
|
Run1 == true,
|
||||||
|
|
||||||
|
when((ground(_) ; nonvar(B)), Run2 = true),
|
||||||
|
var(Run2),
|
||||||
|
B = a(_),
|
||||||
|
Run2 == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
test("multiple when/2 on same variable",(
|
||||||
|
when(nonvar(A), Run1 = true),
|
||||||
|
when(ground(A), Run2 = true),
|
||||||
|
var(Run1), var(Run2),
|
||||||
|
A = a(B),
|
||||||
|
Run1 == true, var(Run2),
|
||||||
|
B = 1,
|
||||||
|
Run2 == true
|
||||||
|
)).
|
||||||
|
|
||||||
|
main :-
|
||||||
|
findall(test(Name, Goal), test(Name, Goal), Tests),
|
||||||
|
run_tests(Tests, Failed),
|
||||||
|
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).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
:- module('$toplevel', [argv/1,
|
:- module('$toplevel', []).
|
||||||
copy_term/3]).
|
|
||||||
|
|
||||||
:- use_module(library(atts), [call_residue_vars/2]).
|
|
||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(files)).
|
:- use_module(library(files)).
|
||||||
@@ -9,11 +7,13 @@
|
|||||||
:- use_module(library(lambda)).
|
:- use_module(library(lambda)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(si)).
|
:- use_module(library(si)).
|
||||||
|
:- use_module(library(os)).
|
||||||
|
|
||||||
:- use_module(library('$project_atts')).
|
:- use_module(library('$project_atts')).
|
||||||
:- use_module(library('$atts')).
|
:- use_module(library('$atts')).
|
||||||
|
|
||||||
:- dynamic(disabled_init_file/0).
|
:- dynamic(disabled_init_file/0).
|
||||||
|
:- dynamic(started/0).
|
||||||
|
|
||||||
load_scryerrc :-
|
load_scryerrc :-
|
||||||
( '$home_directory'(HomeDir) ->
|
( '$home_directory'(HomeDir) ->
|
||||||
@@ -26,24 +26,18 @@ load_scryerrc :-
|
|||||||
; true
|
; true
|
||||||
).
|
).
|
||||||
|
|
||||||
:- dynamic(argv/1).
|
'$repl' :-
|
||||||
|
asserta('$toplevel':started),
|
||||||
'$repl'([_|Args0]) :-
|
raw_argv(Args0),
|
||||||
\+ argv(_),
|
( append(Args1, ["--"|_], Args0) ->
|
||||||
( append(Args1, ["--"|Args2], Args0) ->
|
|
||||||
asserta('$toplevel':argv(Args2)),
|
|
||||||
Args = Args1
|
Args = Args1
|
||||||
; asserta('$toplevel':argv([])),
|
; Args = Args0
|
||||||
Args = Args0
|
|
||||||
),
|
),
|
||||||
delegate_task(Args, []),
|
( Args = [_|TaskArgs] ->
|
||||||
(\+ disabled_init_file -> load_scryerrc ; true),
|
delegate_task(TaskArgs, [])
|
||||||
repl.
|
|
||||||
'$repl'(_) :-
|
|
||||||
( \+ argv(_) -> asserta('$toplevel':argv([]))
|
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
load_scryerrc,
|
(\+ disabled_init_file -> load_scryerrc ; true),
|
||||||
repl.
|
repl.
|
||||||
|
|
||||||
delegate_task([], []).
|
delegate_task([], []).
|
||||||
@@ -134,7 +128,7 @@ run_goals([g(Gs0)|Goals]) :- !,
|
|||||||
write_term(Exception, [double_quotes(DQ)]), nl % halt?
|
write_term(Exception, [double_quotes(DQ)]), nl % halt?
|
||||||
)
|
)
|
||||||
) -> true
|
) -> true
|
||||||
; write('Warning: initialization failed for: '),
|
; write('% Warning: initialization failed for: '),
|
||||||
write_term(Goal, [variable_names(VNs),double_quotes(DQ)]), nl
|
write_term(Goal, [variable_names(VNs),double_quotes(DQ)]), nl
|
||||||
),
|
),
|
||||||
run_goals(Goals).
|
run_goals(Goals).
|
||||||
@@ -191,7 +185,7 @@ submit_query_and_print_results_(Term, VarList) :-
|
|||||||
bb_put('$report_all', false),
|
bb_put('$report_all', false),
|
||||||
bb_put('$report_n_more', 0),
|
bb_put('$report_n_more', 0),
|
||||||
expand_goal(Term, user, Term0),
|
expand_goal(Term, user, Term0),
|
||||||
atts:call_residue_vars(user:Term0, AttrVars),
|
call_residue_vars(user:Term0, AttrVars),
|
||||||
write_eqs_and_read_input(B, VarList, AttrVars),
|
write_eqs_and_read_input(B, VarList, AttrVars),
|
||||||
!.
|
!.
|
||||||
submit_query_and_print_results_(_, _) :-
|
submit_query_and_print_results_(_, _) :-
|
||||||
@@ -314,7 +308,11 @@ write_eqs_and_read_input(B, VarList, AttrVars) :-
|
|||||||
% one layer of depth added for (=/2) functor
|
% one layer of depth added for (=/2) functor
|
||||||
'$term_variables_under_max_depth'(OrigVars, 22, Vars0),
|
'$term_variables_under_max_depth'(OrigVars, 22, Vars0),
|
||||||
'$project_atts':project_attributes(Vars0, AttrVars),
|
'$project_atts':project_attributes(Vars0, AttrVars),
|
||||||
copy_term(AttrVars, AttrVars, AttrGoals),
|
% Need to copy all the visible Vars here so that they appear
|
||||||
|
% properly in AttrGoals, even the non-attributed. Need to also
|
||||||
|
% copy all the attributed variables here so that anonymous
|
||||||
|
% attributed variables also appear properly in AttrGoals.
|
||||||
|
copy_term([Vars0, AttrVars], [Vars0, AttrVars], AttrGoals),
|
||||||
term_variables(AttrGoals, AttrGoalVars),
|
term_variables(AttrGoals, AttrGoalVars),
|
||||||
append([Vars0, AttrGoalVars, AttrVars], Vars),
|
append([Vars0, AttrGoalVars, AttrVars], Vars),
|
||||||
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
|
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
|
||||||
@@ -452,4 +450,3 @@ print_exception_with_check(E) :-
|
|||||||
% is expected to be printed instead.
|
% is expected to be printed instead.
|
||||||
; print_exception(E)
|
; print_exception(E)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|||||||
@@ -1005,6 +1005,18 @@ test_311 :- test_syntax_error("Finis ().", syntax_error(incomplete_reduction)).
|
|||||||
test_318 :- writeq_term_to_chars(+((1*2)^3), C),
|
test_318 :- writeq_term_to_chars(+((1*2)^3), C),
|
||||||
C == "+ (1*2)^3".
|
C == "+ (1*2)^3".
|
||||||
|
|
||||||
|
test_320 :- writeq_term_to_chars([a|\+2], C),
|
||||||
|
C == "[a|\\+2]".
|
||||||
|
|
||||||
|
test_321 :- test_syntax_error("writeq((a)(b)).", syntax_error(incomplete_reduction)).
|
||||||
|
|
||||||
|
test_324 :- writeq_term_to_chars('%', C),
|
||||||
|
C == "'%'".
|
||||||
|
|
||||||
|
test_325 :- test_syntax_error("writeq({[y}]).", syntax_error(incomplete_reduction)).
|
||||||
|
|
||||||
|
test_326 :- test_syntax_error("(>)(1,2).", syntax_error(incomplete_reduction)).
|
||||||
|
|
||||||
run_tests([Test|Tests]) -->
|
run_tests([Test|Tests]) -->
|
||||||
( { call(Test) } ->
|
( { call(Test) } ->
|
||||||
[]
|
[]
|
||||||
|
|||||||
0
tests/scryer/cli/issues/display_constraints.stderr
Normal file
0
tests/scryer/cli/issues/display_constraints.stderr
Normal file
5
tests/scryer/cli/issues/display_constraints.stdin
Normal file
5
tests/scryer/cli/issues/display_constraints.stdin
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
X = 1.
|
||||||
|
use_module(library(dif)).
|
||||||
|
X = 1.
|
||||||
|
dif(X,1).
|
||||||
|
halt.
|
||||||
4
tests/scryer/cli/issues/display_constraints.stdout
Normal file
4
tests/scryer/cli/issues/display_constraints.stdout
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
X = 1.
|
||||||
|
true.
|
||||||
|
X = 1.
|
||||||
|
dif:dif(X,1).
|
||||||
2
tests/scryer/cli/issues/display_constraints.toml
Normal file
2
tests/scryer/cli/issues/display_constraints.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 857
|
||||||
|
args = ["-f", "--no-add-history"]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
['throw_e.pl'].
|
||||||
|
['throw_e.pl'].
|
||||||
|
halt.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
throw(e).
|
||||||
|
throw(e).
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 852
|
||||||
|
args = ["-f", "--no-add-history"]
|
||||||
0
tests/scryer/cli/issues/goals_compound_goal.stderr
Normal file
0
tests/scryer/cli/issues/goals_compound_goal.stderr
Normal file
1
tests/scryer/cli/issues/goals_compound_goal.stdout
Normal file
1
tests/scryer/cli/issues/goals_compound_goal.stdout
Normal file
@@ -0,0 +1 @@
|
|||||||
|
helloworld
|
||||||
2
tests/scryer/cli/issues/goals_compound_goal.toml
Normal file
2
tests/scryer/cli/issues/goals_compound_goal.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 820
|
||||||
|
args = ["-f", "--no-add-history", "-g", "test,halt", "goals.pl"]
|
||||||
3
tests/scryer/cli/issues/goals_multiple_goals.in/goals.pl
Normal file
3
tests/scryer/cli/issues/goals_multiple_goals.in/goals.pl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
test :- write(world), nl.
|
||||||
|
|
||||||
|
:- initialization(write(hello)).
|
||||||
0
tests/scryer/cli/issues/goals_multiple_goals.stderr
Normal file
0
tests/scryer/cli/issues/goals_multiple_goals.stderr
Normal file
1
tests/scryer/cli/issues/goals_multiple_goals.stdout
Normal file
1
tests/scryer/cli/issues/goals_multiple_goals.stdout
Normal file
@@ -0,0 +1 @@
|
|||||||
|
helloworld
|
||||||
2
tests/scryer/cli/issues/goals_multiple_goals.toml
Normal file
2
tests/scryer/cli/issues/goals_multiple_goals.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 820
|
||||||
|
args = ["-f", "--no-add-history", "-g", "test", "-g", "halt", "goals.pl"]
|
||||||
0
tests/scryer/cli/issues/handle_residual_goal.stderr
Normal file
0
tests/scryer/cli/issues/handle_residual_goal.stderr
Normal file
11
tests/scryer/cli/issues/handle_residual_goal.stdin
Normal file
11
tests/scryer/cli/issues/handle_residual_goal.stdin
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use_module(library(dif)).
|
||||||
|
use_module(library(iso_ext)).
|
||||||
|
-X\=X.
|
||||||
|
-X=X.
|
||||||
|
dif(-X,X).
|
||||||
|
dif(-X,X), -X=X.
|
||||||
|
call_residue_vars(dif(-X,X), Vars).
|
||||||
|
set_prolog_flag(occurs_check, true).
|
||||||
|
-X\=X.
|
||||||
|
dif(-X,X).
|
||||||
|
halt.
|
||||||
10
tests/scryer/cli/issues/handle_residual_goal.stdout
Normal file
10
tests/scryer/cli/issues/handle_residual_goal.stdout
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
true.
|
||||||
|
true.
|
||||||
|
false.
|
||||||
|
X = -X.
|
||||||
|
dif:dif(-X,X).
|
||||||
|
false.
|
||||||
|
Vars = [X], dif:dif(-X,X).
|
||||||
|
true.
|
||||||
|
true.
|
||||||
|
true.
|
||||||
2
tests/scryer/cli/issues/handle_residual_goal.toml
Normal file
2
tests/scryer/cli/issues/handle_residual_goal.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 844
|
||||||
|
args = ["-f", "--no-add-history"]
|
||||||
0
tests/scryer/cli/issues/ignored_constraint.stderr
Normal file
0
tests/scryer/cli/issues/ignored_constraint.stderr
Normal file
2
tests/scryer/cli/issues/ignored_constraint.stdin
Normal file
2
tests/scryer/cli/issues/ignored_constraint.stdin
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
use_module(library(freeze)), freeze(X,false), X \=a.
|
||||||
|
halt.
|
||||||
1
tests/scryer/cli/issues/ignored_constraint.stdout
Normal file
1
tests/scryer/cli/issues/ignored_constraint.stdout
Normal file
@@ -0,0 +1 @@
|
|||||||
|
freeze:freeze(X,false).
|
||||||
2
tests/scryer/cli/issues/ignored_constraint.toml
Normal file
2
tests/scryer/cli/issues/ignored_constraint.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 807
|
||||||
|
args = ["-f", "--no-add-history"]
|
||||||
0
tests/scryer/cli/issues/no_stutter.stderr
Normal file
0
tests/scryer/cli/issues/no_stutter.stderr
Normal file
2
tests/scryer/cli/issues/no_stutter.stdin
Normal file
2
tests/scryer/cli/issues/no_stutter.stdin
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
write(a), write(b), false.
|
||||||
|
halt.
|
||||||
1
tests/scryer/cli/issues/no_stutter.stdout
Normal file
1
tests/scryer/cli/issues/no_stutter.stdout
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ab false.
|
||||||
2
tests/scryer/cli/issues/no_stutter.toml
Normal file
2
tests/scryer/cli/issues/no_stutter.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 815
|
||||||
|
args = ["-f", "--no-add-history"]
|
||||||
0
tests/scryer/cli/issues/occurs_check_flag.stderr
Normal file
0
tests/scryer/cli/issues/occurs_check_flag.stderr
Normal file
2
tests/scryer/cli/issues/occurs_check_flag.stdin
Normal file
2
tests/scryer/cli/issues/occurs_check_flag.stdin
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
f(X, X).
|
||||||
|
halt.
|
||||||
1
tests/scryer/cli/issues/occurs_check_flag.stdout
Normal file
1
tests/scryer/cli/issues/occurs_check_flag.stdout
Normal file
@@ -0,0 +1 @@
|
|||||||
|
false.
|
||||||
2
tests/scryer/cli/issues/occurs_check_flag.toml
Normal file
2
tests/scryer/cli/issues/occurs_check_flag.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 841
|
||||||
|
args = ["-f", "--no-add-history", "occurs_check_example.pl"]
|
||||||
0
tests/scryer/cli/issues/occurs_check_flag2.stderr
Normal file
0
tests/scryer/cli/issues/occurs_check_flag2.stderr
Normal file
6
tests/scryer/cli/issues/occurs_check_flag2.stdin
Normal file
6
tests/scryer/cli/issues/occurs_check_flag2.stdin
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
set_prolog_flag(occurs_check, true).
|
||||||
|
X = -X.
|
||||||
|
asserta(f(X,g(X))).
|
||||||
|
f(X,X).
|
||||||
|
X-X = X-g(X).
|
||||||
|
halt.
|
||||||
5
tests/scryer/cli/issues/occurs_check_flag2.stdout
Normal file
5
tests/scryer/cli/issues/occurs_check_flag2.stdout
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
true.
|
||||||
|
false.
|
||||||
|
true.
|
||||||
|
false.
|
||||||
|
false.
|
||||||
2
tests/scryer/cli/issues/occurs_check_flag2.toml
Normal file
2
tests/scryer/cli/issues/occurs_check_flag2.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 841
|
||||||
|
args = ["-f", "--no-add-history"]
|
||||||
0
tests/scryer/cli/issues/op3.stderr
Normal file
0
tests/scryer/cli/issues/op3.stderr
Normal file
0
tests/scryer/cli/issues/op3.stdout
Normal file
0
tests/scryer/cli/issues/op3.stdout
Normal file
2
tests/scryer/cli/issues/op3.toml
Normal file
2
tests/scryer/cli/issues/op3.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# issue 839
|
||||||
|
args = ["-f", "--no-add-history", "op3.pl", "-g", "halt"]
|
||||||
0
tests/scryer/cli/issues/os_argv-no-final--.stderr
Normal file
0
tests/scryer/cli/issues/os_argv-no-final--.stderr
Normal file
6
tests/scryer/cli/issues/os_argv-no-final--.stdin
Normal file
6
tests/scryer/cli/issues/os_argv-no-final--.stdin
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
os:argv(V).
|
||||||
|
os:argv(["test1"|_]).
|
||||||
|
os:argv(["--"|_]).
|
||||||
|
os:argv([V, "--"|_]).
|
||||||
|
os:argv(["test2"|_]).
|
||||||
|
os:argv([]).
|
||||||
6
tests/scryer/cli/issues/os_argv-no-final--.stdout
Normal file
6
tests/scryer/cli/issues/os_argv-no-final--.stdout
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
V = ["test1","--","test2"].
|
||||||
|
true.
|
||||||
|
false.
|
||||||
|
V = "test1".
|
||||||
|
false.
|
||||||
|
false.
|
||||||
2
tests/scryer/cli/issues/os_argv-no-final--.toml
Normal file
2
tests/scryer/cli/issues/os_argv-no-final--.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# https://github.com/mthom/scryer-prolog/pull/2263#issuecomment-1874400820
|
||||||
|
args = ["-f", "--no-add-history", "--", "test1", "--", "test2"]
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user