Merge branch 'master' of https://github.com/mthom/rusty-wam into master
This commit is contained in:
29
Cargo.lock
generated
29
Cargo.lock
generated
@@ -502,6 +502,17 @@ version = "0.2.69"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libsodium-sys"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a685b64f837b339074115f2e7f7b431ac73681d08d75b389db7498b8892b8a58"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
@@ -894,9 +905,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prolog_parser"
|
name = "prolog_parser"
|
||||||
version = "0.8.63"
|
version = "0.8.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fa8dbe0881bcc9a247db279802701d87bbe9d4c6604bb0e5cad3dd3314f241d"
|
checksum = "520bf98dcd386ef320ef11239415c9a11856d3b28fab0d8dc0b61b0d7e65ffe5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lexical",
|
"lexical",
|
||||||
"num-rug-adapter",
|
"num-rug-adapter",
|
||||||
@@ -1221,7 +1232,7 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.126"
|
version = "0.8.127"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.12.3",
|
"base64 0.12.3",
|
||||||
"blake2",
|
"blake2",
|
||||||
@@ -1250,6 +1261,7 @@ dependencies = [
|
|||||||
"rustyline",
|
"rustyline",
|
||||||
"select",
|
"select",
|
||||||
"sha3",
|
"sha3",
|
||||||
|
"sodiumoxide",
|
||||||
"unicode_reader",
|
"unicode_reader",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1390,6 +1402,17 @@ version = "1.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sodiumoxide"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7038b67c941e23501573cb7242ffb08709abe9b11eb74bceff875bbda024a6a8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libsodium-sys",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.126"
|
version = "0.8.127"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "A modern Prolog implementation written mostly in Rust."
|
description = "A modern Prolog implementation written mostly in Rust."
|
||||||
@@ -32,7 +32,7 @@ libc = "0.2.62"
|
|||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
num-rug-adapter = { optional = true, version = "0.1.3" }
|
num-rug-adapter = { optional = true, version = "0.1.3" }
|
||||||
ordered-float = "0.5.0"
|
ordered-float = "0.5.0"
|
||||||
prolog_parser = { version = "0.8.63", default-features = false }
|
prolog_parser = { version = "0.8.68", default-features = false }
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = { version = "1.4.0", optional = true }
|
rug = { version = "1.4.0", optional = true }
|
||||||
rustyline = "6.0.0"
|
rustyline = "6.0.0"
|
||||||
@@ -47,3 +47,4 @@ chrono = "0.4.11"
|
|||||||
select = "0.4.3"
|
select = "0.4.3"
|
||||||
roxmltree = "0.11.0"
|
roxmltree = "0.11.0"
|
||||||
base64 = "0.12.3"
|
base64 = "0.12.3"
|
||||||
|
sodiumoxide = "0.2.6"
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ the exact same internal representation, and has the advantage that
|
|||||||
only the standard predicate `(=)/2` is used.
|
only the standard predicate `(=)/2` is used.
|
||||||
|
|
||||||
Definite clause grammars as provided by
|
Definite clause grammars as provided by
|
||||||
[`library(dcgs)`](src/lib/lists.pl), and the predicates from
|
[`library(dcgs)`](src/lib/dcgs.pl), and the predicates from
|
||||||
[`library(lists)`](src/lib/lists.pl), are ideally suited for reasoning
|
[`library(lists)`](src/lib/lists.pl), are ideally suited for reasoning
|
||||||
about strings.
|
about strings.
|
||||||
|
|
||||||
@@ -450,14 +450,14 @@ The modules that ship with Scryer Prolog are also called
|
|||||||
Predicates for reasoning about environment variables.
|
Predicates for reasoning about environment variables.
|
||||||
* [`iso_ext`](src/lib/iso_ext.pl)
|
* [`iso_ext`](src/lib/iso_ext.pl)
|
||||||
Conforming extensions to and candidates for inclusion in the Prolog
|
Conforming extensions to and candidates for inclusion in the Prolog
|
||||||
ISO standard, such as `setup_call_cleanup/3` and
|
ISO standard, such as `setup_call_cleanup/3`, `call_nth/2` and
|
||||||
`call_with_inference_limit/3`.
|
`call_with_inference_limit/3`.
|
||||||
* [`crypto`](src/lib/crypto.pl)
|
* [`crypto`](src/lib/crypto.pl)
|
||||||
Cryptographically secure random numbers and hashes, HMAC-based key
|
Cryptographically secure random numbers and hashes, HMAC-based key
|
||||||
derivation (HKDF), password-based key derivation (PBKDF2),
|
derivation (HKDF), password-based key derivation (PBKDF2),
|
||||||
public key signatures and signature verification with Ed25519,
|
public key signatures and signature verification with Ed25519,
|
||||||
authenticated symmetric encryption with ChaCha20-Poly1305, and
|
ECDH key exchange over Curve25519 (X25519), authenticated symmetric
|
||||||
reasoning about elliptic curves.
|
encryption with ChaCha20-Poly1305, and reasoning about elliptic curves.
|
||||||
|
|
||||||
To use predicates provided by the `lists` library, write:
|
To use predicates provided by the `lists` library, write:
|
||||||
|
|
||||||
|
|||||||
@@ -309,6 +309,7 @@ pub enum SystemClauseType {
|
|||||||
Ed25519Verify,
|
Ed25519Verify,
|
||||||
Ed25519NewKeyPair,
|
Ed25519NewKeyPair,
|
||||||
Ed25519KeyPairPublicKey,
|
Ed25519KeyPairPublicKey,
|
||||||
|
Curve25519ScalarMult,
|
||||||
LoadHTML,
|
LoadHTML,
|
||||||
LoadXML,
|
LoadXML,
|
||||||
GetEnv,
|
GetEnv,
|
||||||
@@ -522,6 +523,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
|
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
|
||||||
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
|
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
|
||||||
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
|
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
|
||||||
|
&SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
|
||||||
&SystemClauseType::LoadHTML => clause_name!("$load_html"),
|
&SystemClauseType::LoadHTML => clause_name!("$load_html"),
|
||||||
&SystemClauseType::LoadXML => clause_name!("$load_xml"),
|
&SystemClauseType::LoadXML => clause_name!("$load_xml"),
|
||||||
&SystemClauseType::GetEnv => clause_name!("$getenv"),
|
&SystemClauseType::GetEnv => clause_name!("$getenv"),
|
||||||
@@ -708,13 +710,14 @@ impl SystemClauseType {
|
|||||||
("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash),
|
("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash),
|
||||||
("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
|
("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
|
||||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||||
("$crypto_data_encrypt", 6) => Some(SystemClauseType::CryptoDataEncrypt),
|
("$crypto_data_encrypt", 7) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||||
("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt),
|
("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt),
|
||||||
("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult),
|
("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult),
|
||||||
("$ed25519_sign", 5) => Some(SystemClauseType::Ed25519Sign),
|
("$ed25519_sign", 4) => Some(SystemClauseType::Ed25519Sign),
|
||||||
("$ed25519_verify", 5) => Some(SystemClauseType::Ed25519Verify),
|
("$ed25519_verify", 4) => Some(SystemClauseType::Ed25519Verify),
|
||||||
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
|
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
|
||||||
("$ed25519_keypair_public_key", 3) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
|
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
|
||||||
|
("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult),
|
||||||
("$load_html", 3) => Some(SystemClauseType::LoadHTML),
|
("$load_html", 3) => Some(SystemClauseType::LoadHTML),
|
||||||
("$load_xml", 3) => Some(SystemClauseType::LoadXML),
|
("$load_xml", 3) => Some(SystemClauseType::LoadXML),
|
||||||
("$getenv", 2) => Some(SystemClauseType::GetEnv),
|
("$getenv", 2) => Some(SystemClauseType::GetEnv),
|
||||||
|
|||||||
@@ -1298,6 +1298,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
!iter.immediate_leaf_has_property(|addr, heap| {
|
!iter.immediate_leaf_has_property(|addr, heap| {
|
||||||
match heap.index_addr(&addr).as_ref() {
|
match heap.index_addr(&addr).as_ref() {
|
||||||
&HeapCellValue::Integer(ref n) => &**n >= &0,
|
&HeapCellValue::Integer(ref n) => &**n >= &0,
|
||||||
|
&HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0,
|
||||||
&HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64),
|
&HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64),
|
||||||
&HeapCellValue::Rational(ref r) => &**r >= &0,
|
&HeapCellValue::Rational(ref r) => &**r >= &0,
|
||||||
_ => false
|
_ => false
|
||||||
|
|||||||
@@ -123,10 +123,6 @@ impl CodeOffsets {
|
|||||||
code.push(Self::add_index(code.is_empty(), index));
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Constant::String(_) => {
|
|
||||||
let is_initial_index = self.lists.is_empty();
|
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
|
||||||
}
|
|
||||||
&Constant::Usize(n) => {
|
&Constant::Usize(n) => {
|
||||||
let code = self.constants
|
let code = self.constants
|
||||||
.entry(Constant::Integer(Rc::new(Integer::from(n))))
|
.entry(Constant::Integer(Rc::new(Integer::from(n))))
|
||||||
@@ -158,7 +154,7 @@ impl CodeOffsets {
|
|||||||
let is_initial_index = code.is_empty();
|
let is_initial_index = code.is_empty();
|
||||||
code.push(Self::add_index(is_initial_index, index));
|
code.push(Self::add_index(is_initial_index, index));
|
||||||
}
|
}
|
||||||
&Term::Cons(..) => {
|
&Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => {
|
||||||
let is_initial_index = self.lists.is_empty();
|
let is_initial_index = self.lists.is_empty();
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
self.lists.push(Self::add_index(is_initial_index, index));
|
||||||
}
|
}
|
||||||
@@ -172,7 +168,8 @@ impl CodeOffsets {
|
|||||||
let is_initial_index = code.is_empty();
|
let is_initial_index = code.is_empty();
|
||||||
code.push(Self::add_index(is_initial_index, index));
|
code.push(Self::add_index(is_initial_index, index));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
|
:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
|
||||||
:- op(200, fy, [+, -, \]).
|
:- op(200, fy, [+, -, \]).
|
||||||
|
|
||||||
|
:- op(1200, xfx, -->).
|
||||||
|
|
||||||
% arithmetic comparison operators.
|
% arithmetic comparison operators.
|
||||||
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
|
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
|
||||||
|
|
||||||
@@ -189,81 +191,129 @@ set_prolog_flag(Flag, _) :-
|
|||||||
|
|
||||||
fail :- '$fail'.
|
fail :- '$fail'.
|
||||||
|
|
||||||
|
|
||||||
\+ G :- call(G), !, false.
|
\+ G :- call(G), !, false.
|
||||||
\+ _.
|
\+ _.
|
||||||
|
|
||||||
|
|
||||||
X \= X :- !, false.
|
X \= X :- !, false.
|
||||||
_ \= _.
|
_ \= _.
|
||||||
|
|
||||||
|
|
||||||
once(G) :- call(G), !.
|
once(G) :- call(G), !.
|
||||||
|
|
||||||
|
|
||||||
repeat.
|
repeat.
|
||||||
repeat :- repeat.
|
repeat :- repeat.
|
||||||
|
|
||||||
','(G1, G2) :- '$get_b_value'(B), '$call_with_default_policy'(comma_errors(G1, G2, B)).
|
|
||||||
|
|
||||||
:- non_counted_backtracking comma_errors/3.
|
','(G1, G2) :-
|
||||||
comma_errors(G1, G2, B) :- var(G1), throw(error(instantiation_error, (',')/2)).
|
'$get_b_value'(B),
|
||||||
comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)).
|
( '$call_with_default_policy'(var(G1)) ->
|
||||||
|
throw(error(instantiation_error, (',')/2))
|
||||||
|
; '$call_with_default_policy'(','(G1, G2, B))
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
';'(G1, G2) :-
|
||||||
|
'$get_b_value'(B),
|
||||||
|
( '$call_with_default_policy'(var(G1)) ->
|
||||||
|
throw(error(instantiation_error, (';')/2))
|
||||||
|
; '$call_with_default_policy'(';'(G1, G2, B))
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
G1 -> G2 :-
|
||||||
|
'$get_b_value'(B),
|
||||||
|
( '$call_with_default_policy'(var(G1)) ->
|
||||||
|
throw(error(instantiation_error, (->)/2))
|
||||||
|
; '$call_with_default_policy'(->(G1, G2, B))
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
call_or_cut(G, B, ErrorPI) :-
|
||||||
|
( '$call_with_default_policy'(var(G)) ->
|
||||||
|
throw(error(instantiation_error, ErrorPI))
|
||||||
|
; '$call_with_default_policy'(call_or_cut(G, B))
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
call_or_cut(!, B) :-
|
||||||
|
'$set_cp_by_default'(B).
|
||||||
|
call_or_cut((G1, G2), B) :-
|
||||||
|
!,
|
||||||
|
'$call_with_default_policy'(','(G1, G2, B)).
|
||||||
|
call_or_cut((G1 ; G2), B) :-
|
||||||
|
!,
|
||||||
|
'$call_with_default_policy'(';'(G1, G2, B)).
|
||||||
|
call_or_cut((G1 -> G2), B) :-
|
||||||
|
!,
|
||||||
|
'$call_with_default_policy'(->(G1, G2, B)).
|
||||||
|
call_or_cut(G, _) :-
|
||||||
|
'$call_with_default_policy'(G).
|
||||||
|
|
||||||
|
|
||||||
:- non_counted_backtracking (',')/3.
|
:- non_counted_backtracking (',')/3.
|
||||||
','(!, CF, B) :- compound(CF),
|
','((G1, G2), G3, B) :-
|
||||||
'$call_with_default_policy'(CF = ','(G1, G2)),
|
!,
|
||||||
'$set_cp'(B),
|
'$call_with_default_policy'(','(G1, G2, B)),
|
||||||
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
'$call_with_default_policy'(call_or_cut(G3, B, (',')/2)).
|
||||||
','(!, Atom, B) :- Atom == !, '$set_cp'(B).
|
','((G1; G2), G3, B) :-
|
||||||
','(!, G, B) :- '$set_cp'(B), call(G).
|
!,
|
||||||
','(G, CF, B) :- compound(CF),
|
'$call_with_default_policy'(';'(G1, G2, B)),
|
||||||
'$call_with_default_policy'(CF = ','(G1, G2)),
|
'$call_with_default_policy'(call_or_cut(G3, B, (',')/2)).
|
||||||
!,
|
','((G1 -> G2), G3, B) :-
|
||||||
call(G),
|
!,
|
||||||
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
'$call_with_default_policy'(->(G1, G2, B)),
|
||||||
','(G, Atom, B) :- Atom == !, !, call(G), '$set_cp'(B).
|
'$call_with_default_policy'(call_or_cut(G3, B, (',')/2)).
|
||||||
','(G1, G2, _) :- call(G1), call(G2).
|
','(G1, G2, B) :-
|
||||||
|
'$call_with_default_policy'(call_or_cut(G1, B, (',')/2)),
|
||||||
|
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2)).
|
||||||
|
|
||||||
;(G1, G2) :- '$get_b_value'(B), ;(G1, G2, B).
|
|
||||||
|
|
||||||
:- non_counted_backtracking semicolon_compound_selector/3.
|
|
||||||
semicolon_compound_selector(->(G2, G3), G4, B) :-
|
|
||||||
( call(G2) ->
|
|
||||||
call(G3)
|
|
||||||
; '$set_cp'(B),
|
|
||||||
call(G4)
|
|
||||||
).
|
|
||||||
semicolon_compound_selector(','(G2, G3), G4, B) :-
|
|
||||||
( ','(G2, G3, B)
|
|
||||||
; '$set_cp'(B),
|
|
||||||
call(G4)
|
|
||||||
).
|
|
||||||
semicolon_compound_selector(';'(G2, G3), G4, B) :-
|
|
||||||
( ';'(G2, G3, B)
|
|
||||||
; '$set_cp'(B),
|
|
||||||
call(G4)
|
|
||||||
).
|
|
||||||
|
|
||||||
:- non_counted_backtracking (;)/3.
|
:- non_counted_backtracking (;)/3.
|
||||||
;(G1, G4, B) :-
|
';'((G1, G2), G3, B) :-
|
||||||
( ( G1 = (_ -> _)
|
!,
|
||||||
; G1 = (_ , _)
|
( '$call_with_default_policy'(','(G1, G2, B))
|
||||||
; G1 = (_ ; _)
|
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||||
) ->
|
).
|
||||||
!,
|
';'((G1; G2), G3, B) :-
|
||||||
semicolon_compound_selector(G1, G4, B)
|
!,
|
||||||
|
( '$call_with_default_policy'(';'(G1, G2, B))
|
||||||
|
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||||
|
).
|
||||||
|
';'((G1 -> G2), G3, B) :-
|
||||||
|
!,
|
||||||
|
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
|
||||||
|
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||||
|
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||||
|
).
|
||||||
|
';'(G1, G2, B) :-
|
||||||
|
( '$call_with_default_policy'(call_or_cut(G1, B, (;)/2))
|
||||||
|
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
|
||||||
).
|
).
|
||||||
;(G1, G2, B) :-
|
|
||||||
G1 == !, !, '$set_cp'(B), call(G2).
|
|
||||||
;(G1, G2, B) :-
|
|
||||||
G2 == !, !, call(G1), '$set_cp'(B).
|
|
||||||
;(G, _, _) :-
|
|
||||||
call(G).
|
|
||||||
;(_, G, _) :-
|
|
||||||
call(G).
|
|
||||||
|
|
||||||
G1 -> G2 :- '$get_b_value'(B), '$call_with_default_policy'(->(G1, G2, B)).
|
|
||||||
|
|
||||||
:- non_counted_backtracking (->)/3.
|
:- non_counted_backtracking (->)/3.
|
||||||
->(G1, G2, B) :- G2 == !, call(G1), '$set_cp'(B).
|
->((G1, G2), G3, B) :-
|
||||||
->(G1, G2, B) :- call(G1), '$set_cp'(B), call(G2).
|
!,
|
||||||
|
( '$call_with_default_policy'(','(G1, G2, B)) ->
|
||||||
|
'$call_with_default_policy'(call_or_cut(G3, B, (->)/2))
|
||||||
|
).
|
||||||
|
->((G1 ; G2), G3, B) :-
|
||||||
|
!,
|
||||||
|
( '$call_with_default_policy'(';'(G1, G2, B)) ->
|
||||||
|
'$call_with_default_policy'(call_or_cut(G3, B, (->)/2))
|
||||||
|
).
|
||||||
|
->((G1 -> G2), G3, B) :-
|
||||||
|
!,
|
||||||
|
( '$call_with_default_policy'(->(G1, G2, B)) ->
|
||||||
|
'$call_with_default_policy'(call_or_cut(G3, B, (->)/2))
|
||||||
|
).
|
||||||
|
->(G1, G2, B) :-
|
||||||
|
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2))
|
||||||
|
-> '$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||||
|
).
|
||||||
|
|
||||||
% univ.
|
% univ.
|
||||||
|
|
||||||
@@ -916,6 +966,7 @@ op(Priority, OpSpec, Op) :-
|
|||||||
halt :- halt(0).
|
halt :- halt(0).
|
||||||
|
|
||||||
halt(N) :-
|
halt(N) :-
|
||||||
|
must_be_number(N, halt/1),
|
||||||
( -2^31 =< N, N =< 2^31 - 1 ->
|
( -2^31 =< N, N =< 2^31 - 1 ->
|
||||||
'$halt'(N)
|
'$halt'(N)
|
||||||
; throw(error(domain_error(exit_code, N), halt/1))
|
; throw(error(domain_error(exit_code, N), halt/1))
|
||||||
|
|||||||
@@ -842,9 +842,8 @@ verify_attributes(Var, Other, Gs) :-
|
|||||||
( integer(Other) ->
|
( integer(Other) ->
|
||||||
( between(0, 1, Other) ->
|
( between(0, 1, Other) ->
|
||||||
root_get_formula_bdd(Root, Sat, BDD0),
|
root_get_formula_bdd(Root, Sat, BDD0),
|
||||||
bdd_restriction(BDD0, I, Other, BDD),
|
|
||||||
root_put_formula_bdd(Root, Sat, BDD),
|
root_put_formula_bdd(Root, Sat, BDD),
|
||||||
Gs = [satisfiable_bdd(BDD)]
|
Gs = [bdd_restriction(BDD0,I,Other,BDD),satisfiable_bdd(BDD)]
|
||||||
; no_truth_value(Other)
|
; no_truth_value(Other)
|
||||||
)
|
)
|
||||||
; atom(Other) ->
|
; atom(Other) ->
|
||||||
@@ -1558,9 +1557,10 @@ sats([]) --> [].
|
|||||||
sats([A|As]) --> [clpb:sat(A)], sats(As).
|
sats([A|As]) --> [clpb:sat(A)], sats(As).
|
||||||
|
|
||||||
booleans([]) --> [].
|
booleans([]) --> [].
|
||||||
booleans([B|Bs]) --> boolean(B), { del_clpb(B) }, booleans(Bs).
|
booleans([B|Bs]) --> boolean(B), booleans(Bs).
|
||||||
|
|
||||||
boolean(Var) -->
|
boolean(Var) -->
|
||||||
|
{ del_clpb(Var) },
|
||||||
( { get_attr(Var, clpb_omit_boolean, true) } -> []
|
( { get_attr(Var, clpb_omit_boolean, true) } -> []
|
||||||
; [clpb:sat(Var =:= Var)]
|
; [clpb:sat(Var =:= Var)]
|
||||||
).
|
).
|
||||||
|
|||||||
294
src/lib/clpz.pl
294
src/lib/clpz.pl
@@ -4925,97 +4925,229 @@ run_propagator(ptzdiv(X,Y,Z), MState) -->
|
|||||||
%% % Z = X mod Y
|
%% % Z = X mod Y
|
||||||
|
|
||||||
run_propagator(pmod(X,Y,Z), MState) -->
|
run_propagator(pmod(X,Y,Z), MState) -->
|
||||||
( nonvar(X) ->
|
( Y == 0 -> { false }
|
||||||
( nonvar(Y) -> kill(MState), Y =\= 0, Z is X mod Y
|
; Y == Z -> { false }
|
||||||
|
% ; nonvar(Y), Z == X -> true
|
||||||
|
; X == Y -> kill(MState), queue_goal(Z = 0)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
( nonvar(X), nonvar(Y) ->
|
||||||
|
kill(MState),
|
||||||
|
Z is X mod Y
|
||||||
|
; nonvar(Y), nonvar(Z) ->
|
||||||
|
( Y > 0 -> Z >= 0, Z < Y
|
||||||
|
; Y < 0 -> Z =< 0, Z > Y
|
||||||
|
),
|
||||||
|
( { fd_get(X, _, n(XL), _, _) } ->
|
||||||
|
( (XL - Z) mod Y =\= 0 ->
|
||||||
|
XMin is Z + Y * ((XL - Z) div Y + 1)
|
||||||
|
; XMin is XL
|
||||||
|
),
|
||||||
|
{ fd_get(X, XD0, XPs),
|
||||||
|
domain_remove_smaller_than(XD0, XMin, XD2) },
|
||||||
|
fd_put(X, XD2, XPs)
|
||||||
|
% queue_goal(X #>= XMin)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
( { fd_get(X, _, _, n(XU), _) } ->
|
||||||
|
XMax is Z + Y * ((XU - Z) div Y),
|
||||||
|
{ fd_get(X, XD1, XPs),
|
||||||
|
domain_remove_greater_than(XD1, XMax, XD3) },
|
||||||
|
fd_put(X, XD3, XPs)
|
||||||
|
% queue_goal(X #=< XMax)
|
||||||
; true
|
; true
|
||||||
)
|
)
|
||||||
; nonvar(Y) ->
|
% kill(MState),
|
||||||
Y =\= 0,
|
% queue_goal(X #= Z + Y * _) % Add a variable to be efficient.
|
||||||
( abs(Y) =:= 1 -> kill(MState), Z = 0
|
; nonvar(Z), nonvar(X) ->
|
||||||
; var(Z) ->
|
( Z > 0 ->
|
||||||
YP is abs(Y) - 1,
|
( X < 0 -> true
|
||||||
( Y > 0, { fd_get(X, _, n(XL), n(XU), _) } ->
|
; X >= Z
|
||||||
( XL >= 0, XU < Y ->
|
|
||||||
kill(MState), Z = X, ZL = XL, ZU = XU
|
|
||||||
; ZL = 0, ZU = YP
|
|
||||||
)
|
|
||||||
; Y > 0 -> ZL = 0, ZU = YP
|
|
||||||
; YN is -YP, ZL = YN, ZU = 0
|
|
||||||
),
|
|
||||||
( { fd_get(Z, ZD, ZPs) } ->
|
|
||||||
{ domains_intersection(ZD, from_to(n(ZL), n(ZU)), ZD1),
|
|
||||||
domain_infimum(ZD1, n(ZMin)),
|
|
||||||
domain_supremum(ZD1, n(ZMax)) },
|
|
||||||
fd_put(Z, ZD1, ZPs)
|
|
||||||
; ZMin = Z, ZMax = Z
|
|
||||||
),
|
|
||||||
( { fd_get(X, XD, XPs), domain_infimum(XD, n(XMin)) } ->
|
|
||||||
Z1 is XMin mod Y,
|
|
||||||
( { between(ZMin, ZMax, Z1) } -> true
|
|
||||||
; Y > 0 ->
|
|
||||||
Next is ((XMin - ZMin + Y - 1) div Y)*Y + ZMin,
|
|
||||||
{ domain_remove_smaller_than(XD, Next, XD1) },
|
|
||||||
fd_put(X, XD1, XPs)
|
|
||||||
; neq_num(X, XMin)
|
|
||||||
)
|
|
||||||
; true
|
|
||||||
),
|
|
||||||
( { fd_get(X, XD2, XPs2), domain_supremum(XD2, n(XMax)) } ->
|
|
||||||
Z2 is XMax mod Y,
|
|
||||||
( { between(ZMin, ZMax, Z2) } -> true
|
|
||||||
; Y > 0 ->
|
|
||||||
Prev is ((XMax - ZMin) div Y)*Y + ZMax,
|
|
||||||
{ domain_remove_greater_than(XD2, Prev, XD3) },
|
|
||||||
fd_put(X, XD3, XPs2)
|
|
||||||
; neq_num(X, XMax)
|
|
||||||
)
|
|
||||||
; true
|
|
||||||
)
|
)
|
||||||
; { fd_get(X, XD, XPs) },
|
; Z < 0 ->
|
||||||
% if possible, propagate at the boundaries
|
( X > 0 -> true
|
||||||
( { domain_infimum(XD, n(Min)) } ->
|
; X =< Z
|
||||||
( Min mod Y =:= Z -> true
|
)
|
||||||
; Y > 0 ->
|
; Z =:= 0 % Multiple solutions so do nothing special.
|
||||||
Next is ((Min - Z + Y - 1) div Y)*Y + Z,
|
),
|
||||||
{ domain_remove_smaller_than(XD, Next, XD1) },
|
( Z > 0 ->
|
||||||
fd_put(X, XD1, XPs)
|
{ fd_get(Y, YD, YPs),
|
||||||
; neq_num(X, Min)
|
YMin is Z + 1,
|
||||||
|
domain_remove_smaller_than(YD, YMin, YD1) },
|
||||||
|
fd_put(Y, YD1, YPs)
|
||||||
|
% queue_goal(Y #> Z)
|
||||||
|
; Z < 0 ->
|
||||||
|
{ fd_get(Y, YD, YPs),
|
||||||
|
YMax is Z - 1,
|
||||||
|
domain_remove_greater_than(YD, YMax, YD1) },
|
||||||
|
fd_put(Y, YD1, YPs)
|
||||||
|
% queue_goal(Y #< Z)
|
||||||
|
; true
|
||||||
|
)
|
||||||
|
; run_propagator(pmodz(X,Y,Z), MState),
|
||||||
|
run_propagator(pmody(X,Y,Z), MState),
|
||||||
|
true
|
||||||
|
).
|
||||||
|
|
||||||
|
run_propagator(pmodz(X,Y,Z), MState) -->
|
||||||
|
( nonvar(Z) -> true % Nothing to do.
|
||||||
|
; nonvar(X) ->
|
||||||
|
( X =:= 0 -> kill(MState), queue_goal(Z = X)
|
||||||
|
; ( X > 0 ->
|
||||||
|
( { fd_get(Y, _, n(YL), _, _), YL > X } ->
|
||||||
|
kill(MState),
|
||||||
|
queue_goal(Z = X)
|
||||||
|
; { fd_get(Z, ZD0, ZPs),
|
||||||
|
domain_remove_greater_than(ZD0, X, ZD2) },
|
||||||
|
fd_put(Z, ZD2, ZPs)
|
||||||
|
% queue_goal(Z #=< X)
|
||||||
|
)
|
||||||
|
; X < 0 ->
|
||||||
|
( { fd_get(Y, _, _, n(YU), _), YU < X } ->
|
||||||
|
kill(MState),
|
||||||
|
queue_goal(Z = X)
|
||||||
|
; { fd_get(Z, ZD0, ZPs),
|
||||||
|
domain_remove_smaller_than(ZD0, X, ZD2) },
|
||||||
|
fd_put(Z, ZD2, ZPs)
|
||||||
|
% queue_goal(Z #>= X)
|
||||||
)
|
)
|
||||||
; true
|
|
||||||
),
|
),
|
||||||
( { fd_get(X, XD2, XPs2) } ->
|
( { fd_get(Y, _, n(YL), n(YU), _), YL > 0 } ->
|
||||||
( { domain_supremum(XD2, n(Max)) } ->
|
ZMax is YU - 1,
|
||||||
( Max mod Y =:= Z -> true
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
; Y > 0 ->
|
domain_remove_smaller_than(ZD1, 0, ZD3),
|
||||||
Prev is ((Max - Z) div Y)*Y + Z,
|
domain_remove_greater_than(ZD3, ZMax, ZD5) },
|
||||||
{ domain_remove_greater_than(XD2, Prev, XD3) },
|
fd_put(Z, ZD5, ZPs)
|
||||||
fd_put(X, XD3, XPs2)
|
% queue_goal(Z in 0..ZMax)
|
||||||
; neq_num(X, Max)
|
; { fd_get(Y, _, n(YL), n(YU), _), YU < 0 } ->
|
||||||
)
|
ZMin is YL + 1,
|
||||||
; true
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
)
|
domain_remove_greater_than(ZD1, 0, ZD3),
|
||||||
|
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
||||||
|
fd_put(Z, ZD5, ZPs)
|
||||||
|
% queue_goal(Z in ZMin..0)
|
||||||
|
; true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
; nonvar(Y) ->
|
||||||
|
( abs(Y) =:= 1 -> kill(MState), queue_goal(Z = 0)
|
||||||
|
; Y < 0 ->
|
||||||
|
( { fd_get(X, _, n(XL), n(XU), _), XU =< 0, Y < XL } ->
|
||||||
|
kill(MState),
|
||||||
|
queue_goal(Z = X)
|
||||||
|
; ZMin is Y + 1,
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
domain_remove_greater_than(ZD1, 0, ZD3),
|
||||||
|
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
||||||
|
fd_put(Z, ZD5, ZPs)
|
||||||
|
% queue_goal(Z in ZMin..0)
|
||||||
|
)
|
||||||
|
; Y > 0 ->
|
||||||
|
( { fd_get(X, _, n(XL), n(XU), _), XL >= 0, Y > XU } ->
|
||||||
|
kill(MState),
|
||||||
|
queue_goal(Z = X)
|
||||||
|
; ZMax is Y - 1,
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
domain_remove_smaller_than(ZD1, 0, ZD3),
|
||||||
|
domain_remove_greater_than(ZD3, ZMax, ZD5) },
|
||||||
|
fd_put(Z, ZD5, ZPs)
|
||||||
|
% queue_goal(Z in 0..ZMax)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
; ( { fd_get(X, _, n(XL), n(XU), _), XL >= 0,
|
||||||
|
fd_get(Y, _, n(YL), _, _), XU < YL } ->
|
||||||
|
kill(MState),
|
||||||
|
queue_goal(Z = X)
|
||||||
|
; { fd_get(X, _, n(XL), n(XU), _), XU =< 0,
|
||||||
|
fd_get(Y, _, _, n(YU), _), XL > YU } ->
|
||||||
|
kill(MState),
|
||||||
|
queue_goal(Z = X)
|
||||||
|
; ( { fd_get(X, _, n(XL), n(XU), _), XL >= 0 } ->
|
||||||
|
{ fd_get(Z, ZD0, ZPs),
|
||||||
|
domain_remove_greater_than(ZD0, XU, ZD2) },
|
||||||
|
fd_put(Z, ZD2, ZPs)
|
||||||
|
% queue_goal(Z #=< XU)
|
||||||
|
; { fd_get(X, _, n(XL), n(XU), _), XU =< 0 } ->
|
||||||
|
{ fd_get(Z, ZD0, ZPs),
|
||||||
|
domain_remove_smaller_than(ZD0, XL, ZD2) },
|
||||||
|
fd_put(Z, ZD2, ZPs)
|
||||||
|
% queue_goal(Z #>= XL)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
( { fd_get(Y, _, n(YL), n(YU), _), YL > 0 } ->
|
||||||
|
ZMax is YU - 1,
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
domain_remove_smaller_than(ZD1, 0, ZD3),
|
||||||
|
domain_remove_greater_than(ZD3, ZMax, ZD5) },
|
||||||
|
fd_put(Z, ZD5, ZPs)
|
||||||
|
% queue_goal(Z in 0..ZMax)
|
||||||
|
; { fd_get(Y, _, n(YL), n(YU), _), YU < 0 } ->
|
||||||
|
ZMin is YL + 1,
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
domain_remove_greater_than(ZD1, 0, ZD3),
|
||||||
|
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
||||||
|
fd_put(Z, ZD5, ZPs)
|
||||||
|
% queue_goal(Z in ZMin..0)
|
||||||
|
; { fd_get(Y, _, n(YL), n(YU), _) } ->
|
||||||
|
ZMin is YL + 1,
|
||||||
|
ZMax is YU - 1,
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
domain_remove_greater_than(ZD1, ZMax, ZD3),
|
||||||
|
domain_remove_smaller_than(ZD3, ZMin, ZD5) },
|
||||||
|
fd_put(Z, ZD5, ZPs)
|
||||||
|
% queue_goal(Z in ZMin..ZMax)
|
||||||
|
%/* This doesn't work very well.
|
||||||
|
; { fd_get(Y, _, _, n(YU), _), YU > 0 } ->
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
ZMax is YU - 1,
|
||||||
|
domain_remove_greater_than(ZD1, ZMax, ZD3) },
|
||||||
|
fd_put(Z, ZD3, ZPs)
|
||||||
|
% queue_goal(Z #< YU)
|
||||||
|
; { fd_get(Y, _, n(YL), _, _), YL < 0 } ->
|
||||||
|
{ fd_get(Z, ZD1, ZPs),
|
||||||
|
ZMin is YL + 1,
|
||||||
|
domain_remove_smaller_than(ZD1, ZMin, ZD3) },
|
||||||
|
fd_put(Z, ZD3, ZPs)
|
||||||
|
% queue_goal(Z #> YL)
|
||||||
|
% * /
|
||||||
; true
|
; true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
; X == Y -> kill(MState), Z = 0
|
|
||||||
; { fd_get(X, XD, XPs),
|
|
||||||
fd_get(Y, YD, _),
|
|
||||||
fd_get(Z, ZD, ZPs) },
|
|
||||||
( { domain_infimum(XD, n(XMin)), XMin >= 0,
|
|
||||||
domain_infimum(YD, n(YMin)), YMin > 0 } ->
|
|
||||||
{ domain_remove_smaller_than(ZD, 0, ZD1) }
|
|
||||||
; ZD1 = ZD
|
|
||||||
),
|
|
||||||
( { domain_supremum(YD, n(YMax)), YMax > 0 } ->
|
|
||||||
{ Max is YMax - 1, Min is -Max,
|
|
||||||
domain_remove_smaller_than(ZD1, Min, ZD2),
|
|
||||||
domain_remove_greater_than(ZD2, Max, ZD3) }
|
|
||||||
; ZD3 = ZD1
|
|
||||||
),
|
|
||||||
fd_put(Z, ZD3, ZPs)
|
|
||||||
% TODO: propagate more
|
|
||||||
).
|
).
|
||||||
|
|
||||||
|
run_propagator(pmody(X,Y,Z), MState) -->
|
||||||
|
( nonvar(Y) -> true % Nothing to do.
|
||||||
|
% ; nonvar(X) -> true
|
||||||
|
; nonvar(Z) ->
|
||||||
|
( Z > 0 -> % queue_goal(Y #> Z)
|
||||||
|
{ fd_get(Y, YD, YPs),
|
||||||
|
YMin is Z + 1,
|
||||||
|
domain_remove_smaller_than(YD, YMin, YD1) },
|
||||||
|
fd_put(Y, YD1, YPs)
|
||||||
|
; Z < 0 -> % queue_goal(Y #< Z)
|
||||||
|
{ fd_get(Y, YD, YPs),
|
||||||
|
YMax is Z - 1,
|
||||||
|
domain_remove_greater_than(YD, YMax, YD1) },
|
||||||
|
fd_put(Y, YD1, YPs)
|
||||||
|
; Z =:= 0 -> kill(MState), queue_goal(X / Y #= _)
|
||||||
|
)
|
||||||
|
; ( { fd_get(Z, _, n(ZL), _, _), ZL > 0 } ->
|
||||||
|
{ fd_get(Y, YD, YPs),
|
||||||
|
YMin is ZL + 1,
|
||||||
|
domain_remove_smaller_than(YD, YMin, YD1) },
|
||||||
|
fd_put(Y, YD1, YPs)
|
||||||
|
% queue_goal(Y #> ZL)
|
||||||
|
; { fd_get(Z, _, _, n(ZU), _), ZU < 0 } ->
|
||||||
|
{ fd_get(Y, YD, YPs),
|
||||||
|
YMax is ZU - 1,
|
||||||
|
domain_remove_greater_than(YD, YMax, YD1) },
|
||||||
|
fd_put(Y, YD1, YPs)
|
||||||
|
% queue_goal(Y #< ZU)
|
||||||
|
; true
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%% % Z = X rem Y
|
%% % Z = X rem Y
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
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
|
||||||
ed25519_verify/4, % +PublicKey, +Data, +Signature, +Options
|
ed25519_verify/4, % +PublicKey, +Data, +Signature, +Options
|
||||||
|
curve25519_generator/1, % -Generator
|
||||||
|
curve25519_scalar_mult/3, % +Scalar, +Point, -Result
|
||||||
crypto_name_curve/2, % +Name, -Curve
|
crypto_name_curve/2, % +Name, -Curve
|
||||||
crypto_curve_order/2, % +Curve, -Order
|
crypto_curve_order/2, % +Curve, -Order
|
||||||
crypto_curve_generator/2, % +Curve, -Generator
|
crypto_curve_generator/2, % +Curve, -Generator
|
||||||
@@ -43,6 +45,7 @@
|
|||||||
:- use_module(library(arithmetic)).
|
:- use_module(library(arithmetic)).
|
||||||
:- use_module(library(format)).
|
:- use_module(library(format)).
|
||||||
:- use_module(library(charsio)).
|
:- use_module(library(charsio)).
|
||||||
|
:- use_module(library(si)).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
hex_bytes(?Hex, ?Bytes) is det.
|
hex_bytes(?Hex, ?Bytes) is det.
|
||||||
@@ -279,7 +282,7 @@ crypto_data_hkdf(Data0, L, Bytes, Options0) :-
|
|||||||
; domain_error(hkdf_algorithm, Algorithm, crypto_data_hkdf/4)
|
; domain_error(hkdf_algorithm, Algorithm, crypto_data_hkdf/4)
|
||||||
),
|
),
|
||||||
must_be(integer, L),
|
must_be(integer, L),
|
||||||
L >= 0,
|
L #>= 0,
|
||||||
options_data_chars(Options, Data0, Data, Encoding),
|
options_data_chars(Options, Data0, Data, Encoding),
|
||||||
option(salt(SaltBytes), Options, []),
|
option(salt(SaltBytes), Options, []),
|
||||||
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
|
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
|
||||||
@@ -412,7 +415,7 @@ crypto_password_hash(Password0, Hash, Options) :-
|
|||||||
chars_bytes_(Password0, Password, crypto_password_hash/3),
|
chars_bytes_(Password0, Password, crypto_password_hash/3),
|
||||||
must_be(list, Options),
|
must_be(list, Options),
|
||||||
option(cost(C), Options, 17),
|
option(cost(C), Options, 17),
|
||||||
Iterations is 2^C,
|
Iterations #= 2^C,
|
||||||
Algorithm = 'pbkdf2-sha512', % current default and only option
|
Algorithm = 'pbkdf2-sha512', % current default and only option
|
||||||
option(algorithm(Algorithm), Options, Algorithm),
|
option(algorithm(Algorithm), Options, Algorithm),
|
||||||
( member(salt(SaltBytes), Options) ->
|
( member(salt(SaltBytes), Options) ->
|
||||||
@@ -489,6 +492,12 @@ bytes_base64(Bytes, Base64) :-
|
|||||||
list of _bytes_ holding the tag. This tag must be provided for
|
list of _bytes_ holding the tag. This tag must be provided for
|
||||||
decryption.
|
decryption.
|
||||||
|
|
||||||
|
- aad(+Data)
|
||||||
|
Data is additional authenticated data (AAD), a list of
|
||||||
|
characters. It is authenticated in that it influences the tag,
|
||||||
|
but it is not encrypted. The encoding/1 option also specifies
|
||||||
|
the encoding of Data.
|
||||||
|
|
||||||
Here is an example encryption and decryption, using the ChaCha20
|
Here is an example encryption and decryption, using the ChaCha20
|
||||||
stream cipher with the Poly1305 authenticator. This cipher uses a
|
stream cipher with the Poly1305 authenticator. This cipher uses a
|
||||||
256-bit key and a 96-bit nonce, i.e., 32 and 12 _bytes_,
|
256-bit key and a 96-bit nonce, i.e., 32 and 12 _bytes_,
|
||||||
@@ -530,13 +539,20 @@ crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
|
|||||||
must_be_bytes(Tag, crypto_data_encrypt/6)
|
must_be_bytes(Tag, crypto_data_encrypt/6)
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
|
option(aad(AAD0), Options, []),
|
||||||
|
encoding_chars(Encoding, AAD0, AAD),
|
||||||
must_be_bytes(Key, crypto_data_encrypt/6),
|
must_be_bytes(Key, crypto_data_encrypt/6),
|
||||||
must_be_bytes(IV, crypto_data_encrypt/6),
|
must_be_bytes(IV, crypto_data_encrypt/6),
|
||||||
must_be(atom, Algorithm),
|
must_be(atom, Algorithm),
|
||||||
( Algorithm = 'chacha20-poly1305' -> true
|
( Algorithm = 'chacha20-poly1305' -> true
|
||||||
; domain_error('chacha20-poly1305', Algorithm, crypto_data_encrypt/6)
|
; domain_error('chacha20-poly1305', Algorithm, crypto_data_encrypt/6)
|
||||||
),
|
),
|
||||||
'$crypto_data_encrypt'(PlainText, Encoding, Key, IV, Tag, CipherText).
|
algorithm_key_iv(Algorithm, Key, IV),
|
||||||
|
'$crypto_data_encrypt'(PlainText, AAD, Encoding, Key, IV, Tag, CipherText).
|
||||||
|
|
||||||
|
algorithm_key_iv('chacha20-poly1305', Key, IV) :-
|
||||||
|
length(Key, 32),
|
||||||
|
length(IV, 12).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
crypto_data_decrypt(+CipherText,
|
crypto_data_decrypt(+CipherText,
|
||||||
@@ -564,6 +580,10 @@ crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
|
|||||||
- tag(+Tag)
|
- tag(+Tag)
|
||||||
For authenticated encryption schemes, the tag must be specified as
|
For authenticated encryption schemes, the tag must be specified as
|
||||||
a list of bytes exactly as they were generated upon encryption.
|
a list of bytes exactly as they were generated upon encryption.
|
||||||
|
|
||||||
|
- aad(+Data)
|
||||||
|
Any additional authenticated data (AAD) must be specified. The
|
||||||
|
encoding/1 option also specifies the encoding of Data.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||||
@@ -573,16 +593,18 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
|||||||
must_be_bytes(IV, crypto_data_decrypt/6),
|
must_be_bytes(IV, crypto_data_decrypt/6),
|
||||||
must_be(atom, Algorithm),
|
must_be(atom, Algorithm),
|
||||||
option(encoding(Encoding), Options, utf8),
|
option(encoding(Encoding), Options, utf8),
|
||||||
|
option(aad(AAD0), Options, []),
|
||||||
|
encoding_chars(Encoding, AAD0, AAD),
|
||||||
must_be(atom, Encoding),
|
must_be(atom, Encoding),
|
||||||
member(Encoding, [utf8,octet]),
|
member(Encoding, [utf8,octet]),
|
||||||
must_be(list, CipherText0),
|
|
||||||
encoding_chars(octet, CipherText0, CipherText1),
|
encoding_chars(octet, CipherText0, CipherText1),
|
||||||
maplist(char_code, TagChars, Tag),
|
maplist(char_code, TagChars, Tag),
|
||||||
append(CipherText1, TagChars, CipherText),
|
append(CipherText1, TagChars, CipherText),
|
||||||
( Algorithm = 'chacha20-poly1305' -> true
|
( Algorithm = 'chacha20-poly1305' -> true
|
||||||
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
|
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
|
||||||
),
|
),
|
||||||
'$crypto_data_decrypt'(CipherText, octet, Key, IV, Encoding, PlainText).
|
algorithm_key_iv(Algorithm, Key, IV),
|
||||||
|
'$crypto_data_decrypt'(CipherText, AAD, Key, IV, Encoding, PlainText).
|
||||||
|
|
||||||
|
|
||||||
encoding_chars(octet, Bs, Cs) :-
|
encoding_chars(octet, Bs, Cs) :-
|
||||||
@@ -634,19 +656,73 @@ ed25519_new_keypair(Pair) :-
|
|||||||
|
|
||||||
ed25519_keypair_public_key(Pair, PublicKey) :-
|
ed25519_keypair_public_key(Pair, PublicKey) :-
|
||||||
must_be_byte_chars(Pair, ed25519_keypair_public_key),
|
must_be_byte_chars(Pair, ed25519_keypair_public_key),
|
||||||
'$ed25519_keypair_public_key'(Pair, octet, PublicKey).
|
'$ed25519_keypair_public_key'(Pair, PublicKey).
|
||||||
|
|
||||||
ed25519_sign(Key, Data0, Signature, Options) :-
|
ed25519_sign(Key, Data0, Signature, Options) :-
|
||||||
must_be_byte_chars(Key, ed25519_sign),
|
must_be_byte_chars(Key, ed25519_sign),
|
||||||
options_data_chars(Options, Data0, Data, Encoding),
|
options_data_chars(Options, Data0, Data, Encoding),
|
||||||
'$ed25519_sign'(Key, octet, Data, Encoding, Signature0),
|
'$ed25519_sign'(Key, Data, Encoding, Signature0),
|
||||||
hex_bytes(Signature, Signature0).
|
hex_bytes(Signature, Signature0).
|
||||||
|
|
||||||
ed25519_verify(Key, Data0, Signature0, Options) :-
|
ed25519_verify(Key, Data0, Signature0, Options) :-
|
||||||
must_be_byte_chars(Key, ed25519_verify),
|
must_be_byte_chars(Key, ed25519_verify),
|
||||||
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, octet, Data, Encoding, Signature).
|
'$ed25519_verify'(Key, Data, Encoding, Signature).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
X25519: ECDH key exchange over Curve25519
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
Points on Curve25519 are represented as lists of characters that denote
|
||||||
|
the u-coordinate of the Montgomery curve.
|
||||||
|
|
||||||
|
- curve25519_generator(-Gs)
|
||||||
|
Gs is the generator point of Curve25519.
|
||||||
|
|
||||||
|
- curve25519_scalar_mult(+Scalar, +Ps, -Rs)
|
||||||
|
Scalar must be an integer between 0 and 2^256-1,
|
||||||
|
or a list of 32 bytes, and Ps must be a point on the curve.
|
||||||
|
Computes the point Rs = Scalar*Ps as mandated by X25519.
|
||||||
|
|
||||||
|
Alice and Bob can use this to establish a shared secret as follows,
|
||||||
|
where Gs is the generator point of Curve25519:
|
||||||
|
|
||||||
|
1. Alice creates a random integer a and sends As = a*Gs to Bob.
|
||||||
|
2. Bob creates a random integer b and sends Bs = b*Gs to Alice.
|
||||||
|
3. Alice computes Rs = a*Bs.
|
||||||
|
4. Bob computes Rs = b*As.
|
||||||
|
5. Alice and Bob use crypto_data_hkdf/4 on Rs with suitable
|
||||||
|
(same) parameters to obtain lists of bytes that can be used as
|
||||||
|
keys and initialization vectors for symmetric encryption.
|
||||||
|
|
||||||
|
If a and b are kept secret, this method is considered very secure.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
curve25519_generator(Gs) :-
|
||||||
|
length(Gs0, 32),
|
||||||
|
Gs0 = [9|Zs],
|
||||||
|
maplist(=(0), Zs),
|
||||||
|
maplist(char_code, Gs, Gs0).
|
||||||
|
|
||||||
|
curve25519_scalar_mult(Scalar, Point, Result) :-
|
||||||
|
( integer_si(Scalar) ->
|
||||||
|
length(ScalarBytes, 32),
|
||||||
|
bytes_integer(ScalarBytes, Scalar)
|
||||||
|
; ScalarBytes = Scalar,
|
||||||
|
must_be_bytes(ScalarBytes, curve25519_scalar_mult/3),
|
||||||
|
length(ScalarBytes, 32)
|
||||||
|
),
|
||||||
|
maplist(char_code, Point, PointBytes),
|
||||||
|
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
|
||||||
|
|
||||||
|
bytes_integer(Bs, N) :-
|
||||||
|
foldl(pow, Bs, 0-0, N-_).
|
||||||
|
|
||||||
|
pow(B, N0-I0, N-I) :-
|
||||||
|
B in 0..255,
|
||||||
|
N #= N0 + B*256^I0,
|
||||||
|
I #= I0 + 1.
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Operations on Elliptic Curves
|
Operations on Elliptic Curves
|
||||||
@@ -663,6 +739,7 @@ ed25519_verify(Key, Data0, Signature0, Options) :-
|
|||||||
crypto_curve_scalar_mult(C, Random, PublicKey, S),
|
crypto_curve_scalar_mult(C, Random, PublicKey, S),
|
||||||
crypto_curve_scalar_mult(C, PrivateKey, R, S).
|
crypto_curve_scalar_mult(C, PrivateKey, R, S).
|
||||||
|
|
||||||
|
For better security, new code should use Curve25519 instead.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
:- module(dcgs, [op(1200, xfx, -->),
|
:- module(dcgs,
|
||||||
op(1105, xfy, '|'),
|
[op(1105, xfy, '|'),
|
||||||
phrase/2,
|
phrase/2,
|
||||||
phrase/3]).
|
phrase/3]).
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists), [append/3]).
|
:- use_module(library(lists), [append/3]).
|
||||||
|
|||||||
@@ -38,15 +38,20 @@ verify_attributes(Var, Value, Goals) :-
|
|||||||
% Probably the world's worst dif/2 implementation. I'm open to
|
% Probably the world's worst dif/2 implementation. I'm open to
|
||||||
% suggestions for improvement.
|
% suggestions for improvement.
|
||||||
|
|
||||||
dif(X, Y) :- X \== Y,
|
dif(X, Y) :-
|
||||||
( term_variables(X, XVars), term_variables(Y, YVars),
|
X \== Y,
|
||||||
dif_set_variables(XVars, X, Y),
|
( X \= Y -> true
|
||||||
dif_set_variables(YVars, X, Y)
|
; ( term_variables(X, XVars), term_variables(Y, YVars),
|
||||||
).
|
dif_set_variables(XVars, X, Y),
|
||||||
|
dif_set_variables(YVars, X, Y)
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
gather_dif_goals([]) --> [].
|
gather_dif_goals([]) --> [].
|
||||||
gather_dif_goals([(X \== Y) | Goals]) -->
|
gather_dif_goals([(X \== Y) | Goals]) -->
|
||||||
[dif(X, Y)],
|
( { X \= Y } -> []
|
||||||
|
; [dif(X, Y)]
|
||||||
|
),
|
||||||
gather_dif_goals(Goals).
|
gather_dif_goals(Goals).
|
||||||
|
|
||||||
attribute_goals(X) -->
|
attribute_goals(X) -->
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ directory_files(Directory, Files) :-
|
|||||||
'$directory_files'(Directory, Files).
|
'$directory_files'(Directory, Files).
|
||||||
|
|
||||||
file_size(File, Size) :-
|
file_size(File, Size) :-
|
||||||
|
file_must_exist(File, file_size/2),
|
||||||
list_of_chars(File),
|
list_of_chars(File),
|
||||||
can_be(integer, Size),
|
can_be(integer, Size),
|
||||||
'$file_size'(File, Size).
|
'$file_size'(File, Size).
|
||||||
@@ -90,9 +91,15 @@ make_directory(Directory) :-
|
|||||||
'$make_directory'(Directory).
|
'$make_directory'(Directory).
|
||||||
|
|
||||||
delete_file(File) :-
|
delete_file(File) :-
|
||||||
|
file_must_exist(File, delete_file/1),
|
||||||
list_of_chars(File),
|
list_of_chars(File),
|
||||||
'$delete_file'(File).
|
'$delete_file'(File).
|
||||||
|
|
||||||
|
file_must_exist(File, Context) :-
|
||||||
|
( file_exists(File) -> true
|
||||||
|
; throw(error(existence_error(file, File), Context))
|
||||||
|
).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
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.
|
||||||
@@ -142,6 +149,7 @@ file_creation_time(File, T) :-
|
|||||||
file_time_(File, creation, T).
|
file_time_(File, creation, T).
|
||||||
|
|
||||||
file_time_(File, Which, T) :-
|
file_time_(File, Which, T) :-
|
||||||
|
file_must_exist(File, file_time_/3),
|
||||||
'$file_time'(File, Which, T0),
|
'$file_time'(File, Which, T0),
|
||||||
read_term_from_chars(T0, T).
|
read_term_from_chars(T0, T).
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,8 @@
|
|||||||
format_(Fs, Args) -->
|
format_(Fs, Args) -->
|
||||||
{ must_be(list, Fs),
|
{ must_be(list, Fs),
|
||||||
must_be(list, Args),
|
must_be(list, Args),
|
||||||
phrase(cells(Fs,Args,0,[]), Cells) },
|
unique_variable_names(Args, VNs),
|
||||||
|
phrase(cells(Fs,Args,0,[],VNs), Cells) },
|
||||||
format_cells(Cells).
|
format_cells(Cells).
|
||||||
|
|
||||||
format_cells([]) --> [].
|
format_cells([]) --> [].
|
||||||
@@ -157,22 +158,22 @@ element_gluevar(glue(_,V), N, N) --> [V].
|
|||||||
consume whitespace in the sense of format strings.
|
consume whitespace in the sense of format strings.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
cells([], Args, Tab, Es) -->
|
cells([], Args, Tab, Es, _) -->
|
||||||
( { Args == [] } -> cell(Tab, Tab, Es)
|
( { Args == [] } -> cell(Tab, Tab, Es)
|
||||||
; { domain_error(empty_list, Args, format_//2) }
|
; { domain_error(empty_list, Args, format_//2) }
|
||||||
).
|
).
|
||||||
cells([~,~|Fs], Args, Tab, Es) --> !,
|
cells([~,~|Fs], Args, Tab, Es, VNs) --> !,
|
||||||
cells(Fs, Args, Tab, [chars("~")|Es]).
|
cells(Fs, Args, Tab, [chars("~")|Es], VNs).
|
||||||
cells([~,w|Fs], [Arg|Args], Tab, Es) --> !,
|
cells([~,w|Fs], [Arg|Args], Tab, Es, VNs) --> !,
|
||||||
{ write_term_to_chars(Arg, [], Chars) },
|
{ write_term_to_chars(Arg, [variable_names(VNs)], Chars) },
|
||||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
cells(Fs, Args, Tab, [chars(Chars)|Es], VNs).
|
||||||
cells([~,q|Fs], [Arg|Args], Tab, Es) --> !,
|
cells([~,q|Fs], [Arg|Args], Tab, Es, VNs) --> !,
|
||||||
{ write_term_to_chars(Arg, [quoted(true)], Chars) },
|
{ write_term_to_chars(Arg, [quoted(true),variable_names(VNs)], Chars) },
|
||||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
cells(Fs, Args, Tab, [chars(Chars)|Es], VNs).
|
||||||
cells([~,a|Fs], [Arg|Args], Tab, Es) --> !,
|
cells([~,a|Fs], [Arg|Args], Tab, Es, VNs) --> !,
|
||||||
{ atom_chars(Arg, Chars) },
|
{ atom_chars(Arg, Chars) },
|
||||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
cells(Fs, Args, Tab, [chars(Chars)|Es], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, [d|Fs], Args0, [Arg0|Args]) },
|
{ numeric_argument(Fs0, Num, [d|Fs], Args0, [Arg0|Args]) },
|
||||||
!,
|
!,
|
||||||
{ Arg is Arg0, % evaluate compound expression
|
{ Arg is Arg0, % evaluate compound expression
|
||||||
@@ -191,8 +192,8 @@ cells([~|Fs0], Args0, Tab, Es) -->
|
|||||||
phrase((list(Bs),".",list(Ds)), Cs)
|
phrase((list(Bs),".",list(Ds)), Cs)
|
||||||
) }
|
) }
|
||||||
),
|
),
|
||||||
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
|
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
|
||||||
!,
|
!,
|
||||||
{ number_chars(Num, NCs),
|
{ number_chars(Num, NCs),
|
||||||
@@ -203,25 +204,25 @@ cells([~|Fs0], Args0, Tab, Es) -->
|
|||||||
phrase(groups_of_three(Bs1), Bs2),
|
phrase(groups_of_three(Bs1), Bs2),
|
||||||
reverse(Bs2, Bs),
|
reverse(Bs2, Bs),
|
||||||
append(Bs, Ds, Cs) },
|
append(Bs, Ds, Cs) },
|
||||||
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||||
cells([~,i|Fs], [_|Args], Tab, Es) --> !,
|
cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !,
|
||||||
cells(Fs, Args, Tab, Es).
|
cells(Fs, Args, Tab, Es, VNs).
|
||||||
cells([~,n|Fs], Args, Tab, Es) --> !,
|
cells([~,n|Fs], Args, Tab, Es, VNs) --> !,
|
||||||
cell(Tab, Tab, Es),
|
cell(Tab, Tab, Es),
|
||||||
n_newlines(1),
|
n_newlines(1),
|
||||||
cells(Fs, Args, 0, []).
|
cells(Fs, Args, 0, [], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, [n|Fs], Args0, Args) },
|
{ numeric_argument(Fs0, Num, [n|Fs], Args0, Args) },
|
||||||
!,
|
!,
|
||||||
cell(Tab, Tab, Es),
|
cell(Tab, Tab, Es),
|
||||||
n_newlines(Num),
|
n_newlines(Num),
|
||||||
cells(Fs, Args, 0, []).
|
cells(Fs, Args, 0, [], VNs).
|
||||||
cells([~,s|Fs], [Arg|Args], Tab, Es) --> !,
|
cells([~,s|Fs], [Arg|Args], Tab, Es, VNs) --> !,
|
||||||
cells(Fs, Args, Tab, [chars(Arg)|Es]).
|
cells(Fs, Args, Tab, [chars(Arg)|Es], VNs).
|
||||||
cells([~,f|Fs], [Arg|Args], Tab, Es) --> !,
|
cells([~,f|Fs], [Arg|Args], Tab, Es, VNs) --> !,
|
||||||
{ format_number_chars(Arg, Chars) },
|
{ format_number_chars(Arg, Chars) },
|
||||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
cells(Fs, Args, Tab, [chars(Chars)|Es], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, [f|Fs], Args0, [Arg|Args]) },
|
{ numeric_argument(Fs0, Num, [f|Fs], Args0, [Arg|Args]) },
|
||||||
!,
|
!,
|
||||||
{ format_number_chars(Arg, Cs0),
|
{ format_number_chars(Arg, Cs0),
|
||||||
@@ -248,39 +249,39 @@ cells([~|Fs0], Args0, Tab, Es) -->
|
|||||||
),
|
),
|
||||||
append(Bs, ['.'|Ds], Chars)
|
append(Bs, ['.'|Ds], Chars)
|
||||||
) },
|
) },
|
||||||
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
cells(Fs, Args, Tab, [chars(Chars)|Es], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, [r|Fs], Args0, [Arg|Args]) },
|
{ numeric_argument(Fs0, Num, [r|Fs], Args0, [Arg|Args]) },
|
||||||
!,
|
!,
|
||||||
{ integer_to_radix(Arg, Num, lowercase, Cs) },
|
{ integer_to_radix(Arg, Num, lowercase, Cs) },
|
||||||
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, ['R'|Fs], Args0, [Arg|Args]) },
|
{ numeric_argument(Fs0, Num, ['R'|Fs], Args0, [Arg|Args]) },
|
||||||
!,
|
!,
|
||||||
{ integer_to_radix(Arg, Num, uppercase, Cs) },
|
{ integer_to_radix(Arg, Num, uppercase, Cs) },
|
||||||
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||||
cells([~,'`',Char,t|Fs], Args, Tab, Es) --> !,
|
cells([~,'`',Char,t|Fs], Args, Tab, Es, VNs) --> !,
|
||||||
cells(Fs, Args, Tab, [glue(Char,_)|Es]).
|
cells(Fs, Args, Tab, [glue(Char,_)|Es], VNs).
|
||||||
cells([~,t|Fs], Args, Tab, Es) --> !,
|
cells([~,t|Fs], Args, Tab, Es, VNs) --> !,
|
||||||
cells(Fs, Args, Tab, [glue(' ',_)|Es]).
|
cells(Fs, Args, Tab, [glue(' ',_)|Es], VNs).
|
||||||
cells([~|Fs0], Args0, Tab, Es) -->
|
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
|
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
|
||||||
!,
|
!,
|
||||||
cell(Tab, Num, Es),
|
cell(Tab, Num, Es),
|
||||||
cells(Fs, Args, Num, []).
|
cells(Fs, Args, Num, [], VNs).
|
||||||
cells([~|Fs0], Args0, Tab0, Es) -->
|
cells([~|Fs0], Args0, Tab0, Es, VNs) -->
|
||||||
{ numeric_argument(Fs0, Num, [+|Fs], Args0, Args) },
|
{ numeric_argument(Fs0, Num, [+|Fs], Args0, Args) },
|
||||||
!,
|
!,
|
||||||
{ Tab is Tab0 + Num },
|
{ Tab is Tab0 + Num },
|
||||||
cell(Tab0, Tab, Es),
|
cell(Tab0, Tab, Es),
|
||||||
cells(Fs, Args, Tab, []).
|
cells(Fs, Args, Tab, [], VNs).
|
||||||
cells([~,C|_], _, _, _) -->
|
cells([~,C|_], _, _, _, _) -->
|
||||||
{ atom_chars(A, [~,C]),
|
{ atom_chars(A, [~,C]),
|
||||||
domain_error(format_string, A, format_//2) }.
|
domain_error(format_string, A, format_//2) }.
|
||||||
cells(Fs0, Args, Tab, Es) -->
|
cells(Fs0, Args, Tab, Es, VNs) -->
|
||||||
{ phrase(upto_what(Fs1, ~), Fs0, Fs),
|
{ phrase(upto_what(Fs1, ~), Fs0, Fs),
|
||||||
Fs1 = [_|_] },
|
Fs1 = [_|_] },
|
||||||
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
|
cells(Fs, Args, Tab, [chars(Fs1)|Es], VNs).
|
||||||
|
|
||||||
format_number_chars(N0, Chars) :-
|
format_number_chars(N0, Chars) :-
|
||||||
N is N0, % evaluate compound expression
|
N is N0, % evaluate compound expression
|
||||||
@@ -390,14 +391,14 @@ format(Stream, Fs, Args) :-
|
|||||||
|
|
||||||
?- phrase(cells("~`at~50|", [], 0, []), Cs),
|
?- phrase(cells("~`at~50|", [], 0, []), Cs),
|
||||||
phrase(format_cells(Cs), Ls).
|
phrase(format_cells(Cs), Ls).
|
||||||
?- phrase(cells("~ta~t~tb~tc~21|", [], 0, []), Cs).
|
?- phrase(format:cells("~ta~t~tb~tc~21|", [], 0, [], []), Cs).
|
||||||
Cs = [cell(0,21,[glue(' ',_38),chars([a]),glue(' ',_62),glue(' ',_67),chars([b]),glue(' ',_91),chars([c])])].
|
Cs = [cell(0,21,[glue(' ',_A),chars("a"),glue(' ',_B),glue(' ',_C),chars("b"),glue(' ',_D),chars("c ...")])]
|
||||||
?- phrase(cells("~ta~t~4|", [], 0, []), Cs).
|
?- phrase(format:cells("~ta~t~4|", [], 0, [], []), Cs).
|
||||||
Cs = [cell(0,4,[glue(' ',_38),chars([a]),glue(' ',_62)])].
|
Cs = [cell(0,4,[glue(' ',_A),chars("a"),glue(' ',_B)])]
|
||||||
|
|
||||||
?- phrase(format_cell(cell(0,1,[glue(a,_94)])), Ls).
|
?- phrase(format:format_cell(cell(0,1,[glue(a,_94)])), Ls).
|
||||||
|
|
||||||
?- phrase(format_cell(cell(0,50,[chars("hello")])), Ls).
|
?- phrase(format:format_cell(cell(0,50,[chars("hello")])), Ls).
|
||||||
|
|
||||||
?- phrase(format_("~`at~50|~n", []), Ls).
|
?- phrase(format_("~`at~50|~n", []), Ls).
|
||||||
?- phrase(format_("hello~n~tthere~6|", []), Ls).
|
?- phrase(format_("hello~n~tthere~6|", []), Ls).
|
||||||
@@ -462,10 +463,13 @@ portray_clause(Stream, Term) :-
|
|||||||
format(Stream, "~s", [Ls]).
|
format(Stream, "~s", [Ls]).
|
||||||
|
|
||||||
portray_clause_(Term) -->
|
portray_clause_(Term) -->
|
||||||
{ term_variables(Term, Vs),
|
{ unique_variable_names(Term, VNs) },
|
||||||
foldl(var_name, Vs, VNs, 0, _) },
|
|
||||||
portray_(Term, VNs), ".\n".
|
portray_(Term, VNs), ".\n".
|
||||||
|
|
||||||
|
unique_variable_names(Term, VNs) :-
|
||||||
|
term_variables(Term, Vs),
|
||||||
|
foldl(var_name, Vs, VNs, 0, _).
|
||||||
|
|
||||||
var_name(V, Name=V, Num0, Num) :-
|
var_name(V, Name=V, Num0, Num) :-
|
||||||
charsio:fabricate_var_name(numbervars, Name, Num0),
|
charsio:fabricate_var_name(numbervars, Name, Num0),
|
||||||
Num is Num0 + 1.
|
Num is Num0 + 1.
|
||||||
|
|||||||
@@ -7,7 +7,9 @@
|
|||||||
call_with_inference_limit/3, forall/2,
|
call_with_inference_limit/3, forall/2,
|
||||||
partial_string/1, partial_string/3,
|
partial_string/1, partial_string/3,
|
||||||
partial_string_tail/2, setup_call_cleanup/3,
|
partial_string_tail/2, setup_call_cleanup/3,
|
||||||
variant/2]).
|
call_nth/2, variant/2]).
|
||||||
|
|
||||||
|
:- use_module(library(error), [can_be/2,domain_error/3]).
|
||||||
|
|
||||||
forall(Generate, Test) :-
|
forall(Generate, Test) :-
|
||||||
\+ (Generate, \+ Test).
|
\+ (Generate, \+ Test).
|
||||||
@@ -161,3 +163,35 @@ partial_string_tail(String, Tail) :-
|
|||||||
'$partial_string_tail'(String, Tail)
|
'$partial_string_tail'(String, Tail)
|
||||||
; throw(error(type_error(partial_string, String), partial_string_tail/2))
|
; throw(error(type_error(partial_string, String), partial_string_tail/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
:- dynamic(i_call_nth_nesting/2).
|
||||||
|
:- dynamic(i_call_nth_counter/1).
|
||||||
|
|
||||||
|
call_nth(Goal, N) :-
|
||||||
|
can_be(integer, N),
|
||||||
|
( integer(N), N =< 0,
|
||||||
|
domain_error(positive_integer, N, call_nth/2)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
setup_call_cleanup(call_nth_nesting(ID),
|
||||||
|
( Goal,
|
||||||
|
retract(i_call_nth_nesting(ID,N0)),
|
||||||
|
N1 is N0 + 1,
|
||||||
|
asserta(i_call_nth_nesting(ID,N1)),
|
||||||
|
( integer(N) ->
|
||||||
|
N = N1,
|
||||||
|
!
|
||||||
|
; N = N1
|
||||||
|
)
|
||||||
|
),
|
||||||
|
( retract(i_call_nth_nesting(ID,_)),
|
||||||
|
retract(i_call_nth_counter(ID))
|
||||||
|
)).
|
||||||
|
|
||||||
|
call_nth_nesting(ID) :-
|
||||||
|
( i_call_nth_counter(ID0) ->
|
||||||
|
ID is ID0 + 1
|
||||||
|
; ID = 0
|
||||||
|
),
|
||||||
|
asserta(i_call_nth_nesting(ID, 0)),
|
||||||
|
asserta(i_call_nth_counter(ID)).
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ wkl_p_swap_answer_continuation(Worklist,InnerAnswerClusterPointer,SuspensionClus
|
|||||||
wkl_p_update_righmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer).
|
wkl_p_update_righmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer).
|
||||||
|
|
||||||
% Update the pointer if the answer cluster it points to is no longer the rightmost inner answer cluster.
|
% Update the pointer if the answer cluster it points to is no longer the rightmost inner answer cluster.
|
||||||
|
% Strangely, this predicate was intentionally named "wkl_p_update_righmost_inner_answer_cluster_pointer"
|
||||||
|
% in the original library.
|
||||||
wkl_p_update_righmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer) :-
|
wkl_p_update_righmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer) :-
|
||||||
( wkl_p_answer_cluster_currently_moved_completely(Worklist,InnerAnswerClusterPointer) ->
|
( wkl_p_answer_cluster_currently_moved_completely(Worklist,InnerAnswerClusterPointer) ->
|
||||||
wkl_p_find_new_rightmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer,NewRiacPointer),
|
wkl_p_find_new_rightmost_inner_answer_cluster_pointer(Worklist,InnerAnswerClusterPointer,NewRiacPointer),
|
||||||
|
|||||||
@@ -840,5 +840,4 @@ impl From<ParserError> for EvalSession {
|
|||||||
fn from(err: ParserError) -> Self {
|
fn from(err: ParserError) -> Self {
|
||||||
EvalSession::from(SessionError::ParserError(err))
|
EvalSession::from(SessionError::ParserError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,18 +272,6 @@ impl Addr {
|
|||||||
&Addr::Float(f) => {
|
&Addr::Float(f) => {
|
||||||
Some(Constant::Float(f))
|
Some(Constant::Float(f))
|
||||||
}
|
}
|
||||||
addr @ &Addr::PStrLocation(..) | addr @ &Addr::Lis(_) => {
|
|
||||||
let mut heap_pstr_iter = machine_st.heap_pstr_iter(*addr);
|
|
||||||
|
|
||||||
let buf = heap_pstr_iter.to_string();
|
|
||||||
let end_addr = heap_pstr_iter.focus();
|
|
||||||
|
|
||||||
if end_addr == Addr::EmptyList {
|
|
||||||
Some(Constant::String(Rc::new(buf)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Addr::Usize(n) => {
|
&Addr::Usize(n) => {
|
||||||
Some(Constant::Usize(n))
|
Some(Constant::Usize(n))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -636,11 +636,10 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut orig_stream = stream.clone();
|
let mut orig_stream = stream.clone();
|
||||||
let mut stream = self.open_parsing_stream(stream, "read_term", 3)?;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.read(
|
match self.read(
|
||||||
&mut stream,
|
stream.clone(),
|
||||||
indices.atom_tbl.clone(),
|
indices.atom_tbl.clone(),
|
||||||
&indices.op_dir,
|
&indices.op_dir,
|
||||||
) {
|
) {
|
||||||
@@ -1337,14 +1336,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
|
|||||||
return_from_clause!(machine_st.last_call, machine_st)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
}
|
}
|
||||||
&BuiltInClauseType::Read => {
|
&BuiltInClauseType::Read => {
|
||||||
let mut stream = machine_st.open_parsing_stream(
|
|
||||||
current_input_stream.clone(),
|
|
||||||
"read",
|
|
||||||
1,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
match machine_st.read(
|
match machine_st.read(
|
||||||
&mut stream,
|
current_input_stream.clone(),
|
||||||
indices.atom_tbl.clone(),
|
indices.atom_tbl.clone(),
|
||||||
&indices.op_dir,
|
&indices.op_dir,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ use std::cell::RefCell;
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::mem;
|
||||||
use std::net::{Shutdown, TcpStream};
|
use std::net::{Shutdown, TcpStream};
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -92,20 +94,87 @@ impl EOFAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parser_top_to_bytes(mut buf: Vec<io::Result<char>>) -> io::Result<Vec<u8>> {
|
||||||
|
let mut str_buf = String::new();
|
||||||
|
|
||||||
|
while let Some(c) = buf.pop() {
|
||||||
|
str_buf.push(c?);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let array = str_buf.as_bytes_mut();
|
||||||
|
array.reverse();
|
||||||
|
Ok(Vec::from(array))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* all these streams are closed automatically when the instance is
|
/* all these streams are closed automatically when the instance is
|
||||||
* dropped. */
|
* dropped. */
|
||||||
pub enum StreamInstance {
|
enum StreamInstance {
|
||||||
Bytes(Cursor<Vec<u8>>),
|
Bytes(Cursor<Vec<u8>>),
|
||||||
DynReadSource(Box<dyn Read>),
|
|
||||||
InputFile(ClauseName, File),
|
InputFile(ClauseName, File),
|
||||||
OutputFile(ClauseName, File, bool), // File, append.
|
OutputFile(ClauseName, File, bool), // File, append.
|
||||||
Null,
|
Null,
|
||||||
|
PausedPrologStream(Vec<u8>, Box<StreamInstance>),
|
||||||
ReadlineStream(ReadlineStream),
|
ReadlineStream(ReadlineStream),
|
||||||
|
StaticStr(Cursor<&'static str>),
|
||||||
Stdout,
|
Stdout,
|
||||||
TcpStream(ClauseName, TcpStream),
|
TcpStream(ClauseName, TcpStream),
|
||||||
TlsStream(ClauseName, TlsStream<TcpStream>)
|
TlsStream(ClauseName, TlsStream<TcpStream>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StreamInstance {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
match self {
|
||||||
|
StreamInstance::PausedPrologStream(ref mut put_back, ref mut stream) => {
|
||||||
|
let mut index = 0;
|
||||||
|
|
||||||
|
while index < buf.len() {
|
||||||
|
if let Some(b) = put_back.pop() {
|
||||||
|
buf[index] = b;
|
||||||
|
index += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == buf.len() {
|
||||||
|
Ok(buf.len())
|
||||||
|
} else {
|
||||||
|
stream.read(&mut buf[index ..])
|
||||||
|
.map(|bytes_read| bytes_read + index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
|
file.read(buf)
|
||||||
|
}
|
||||||
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
||||||
|
tcp_stream.read(buf)
|
||||||
|
}
|
||||||
|
StreamInstance::TlsStream(_, ref mut tls_stream) => {
|
||||||
|
tls_stream.read(buf)
|
||||||
|
}
|
||||||
|
StreamInstance::ReadlineStream(ref mut rl_stream) => {
|
||||||
|
rl_stream.read(buf)
|
||||||
|
}
|
||||||
|
StreamInstance::StaticStr(ref mut src) => {
|
||||||
|
src.read(buf)
|
||||||
|
}
|
||||||
|
StreamInstance::Bytes(ref mut cursor) => {
|
||||||
|
cursor.read(buf)
|
||||||
|
}
|
||||||
|
StreamInstance::OutputFile(..) |
|
||||||
|
StreamInstance::Stdout |
|
||||||
|
StreamInstance::Null => {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
ErrorKind::PermissionDenied,
|
||||||
|
StreamError::ReadFromOutputStream,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for StreamInstance {
|
impl Drop for StreamInstance {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
@@ -126,15 +195,20 @@ impl fmt::Debug for StreamInstance {
|
|||||||
match self {
|
match self {
|
||||||
&StreamInstance::Bytes(ref bytes) =>
|
&StreamInstance::Bytes(ref bytes) =>
|
||||||
write!(fmt, "Bytes({:?})", bytes),
|
write!(fmt, "Bytes({:?})", bytes),
|
||||||
&StreamInstance::DynReadSource(_) =>
|
&StreamInstance::StaticStr(_) =>
|
||||||
write!(fmt, "DynReadSource(_)"), // Hacky solution.
|
write!(fmt, "StaticStr(_)"), // Hacky solution.
|
||||||
&StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file),
|
&StreamInstance::InputFile(_, ref file) =>
|
||||||
&StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file),
|
write!(fmt, "InputFile({:?})", file),
|
||||||
&StreamInstance::Null => write!(fmt, "Null"),
|
&StreamInstance::OutputFile(_, ref file, _) =>
|
||||||
|
write!(fmt, "OutputFile({:?})", file),
|
||||||
|
&StreamInstance::Null =>
|
||||||
|
write!(fmt, "Null"),
|
||||||
|
&StreamInstance::PausedPrologStream(ref put_back, ref stream) =>
|
||||||
|
write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream),
|
||||||
&StreamInstance::ReadlineStream(ref readline_stream) =>
|
&StreamInstance::ReadlineStream(ref readline_stream) =>
|
||||||
write!(fmt, "ReadlineStream({:?})", readline_stream),
|
write!(fmt, "ReadlineStream({:?})", readline_stream),
|
||||||
// &StreamInstance::Stdin => write!(fmt, "Stdin"),
|
&StreamInstance::Stdout =>
|
||||||
&StreamInstance::Stdout => write!(fmt, "Stdout"),
|
write!(fmt, "Stdout"),
|
||||||
&StreamInstance::TcpStream(_, ref tcp_stream) =>
|
&StreamInstance::TcpStream(_, ref tcp_stream) =>
|
||||||
write!(fmt, "TcpStream({:?})", tcp_stream),
|
write!(fmt, "TcpStream({:?})", tcp_stream),
|
||||||
&StreamInstance::TlsStream(_, ref tls_stream) =>
|
&StreamInstance::TlsStream(_, ref tls_stream) =>
|
||||||
@@ -282,7 +356,7 @@ impl From<ReadlineStream> for Stream {
|
|||||||
|
|
||||||
impl From<&'static str> for Stream {
|
impl From<&'static str> for Stream {
|
||||||
fn from(src: &'static str) -> Stream {
|
fn from(src: &'static str) -> Stream {
|
||||||
Stream::from_inst(StreamInstance::DynReadSource(Box::new(src.as_bytes())))
|
Stream::from_inst(StreamInstance::StaticStr(Cursor::new(src)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,8 +487,9 @@ impl Stream {
|
|||||||
fn mode(&self) -> &'static str {
|
fn mode(&self) -> &'static str {
|
||||||
match self.stream_inst.0.borrow().1 {
|
match self.stream_inst.0.borrow().1 {
|
||||||
StreamInstance::Bytes(_) |
|
StreamInstance::Bytes(_) |
|
||||||
|
StreamInstance::PausedPrologStream(..) |
|
||||||
StreamInstance::ReadlineStream(_) |
|
StreamInstance::ReadlineStream(_) |
|
||||||
StreamInstance::DynReadSource(_) |
|
StreamInstance::StaticStr(_) |
|
||||||
StreamInstance::InputFile(..) => {
|
StreamInstance::InputFile(..) => {
|
||||||
"read"
|
"read"
|
||||||
}
|
}
|
||||||
@@ -493,7 +568,6 @@ impl Stream {
|
|||||||
pub(crate)
|
pub(crate)
|
||||||
fn is_stdin(&self) -> bool {
|
fn is_stdin(&self) -> bool {
|
||||||
match self.stream_inst.0.borrow().1 {
|
match self.stream_inst.0.borrow().1 {
|
||||||
//StreamInstance::Stdin |
|
|
||||||
StreamInstance::ReadlineStream(_) => {
|
StreamInstance::ReadlineStream(_) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -523,12 +597,12 @@ impl Stream {
|
|||||||
pub(crate)
|
pub(crate)
|
||||||
fn is_input_stream(&self) -> bool {
|
fn is_input_stream(&self) -> bool {
|
||||||
match self.stream_inst.0.borrow().1 {
|
match self.stream_inst.0.borrow().1 {
|
||||||
// StreamInstance::Stdin |
|
|
||||||
StreamInstance::TcpStream(..) |
|
StreamInstance::TcpStream(..) |
|
||||||
StreamInstance::TlsStream(..) |
|
StreamInstance::TlsStream(..) |
|
||||||
StreamInstance::Bytes(_) |
|
StreamInstance::Bytes(_) |
|
||||||
|
StreamInstance::PausedPrologStream(..) |
|
||||||
StreamInstance::ReadlineStream(_) |
|
StreamInstance::ReadlineStream(_) |
|
||||||
StreamInstance::DynReadSource(_) |
|
StreamInstance::StaticStr(_) |
|
||||||
StreamInstance::InputFile(..) => {
|
StreamInstance::InputFile(..) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -555,27 +629,49 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unpause_stream(&mut self) {
|
||||||
|
let stream_inst =
|
||||||
|
match self.stream_inst.0.borrow_mut().1 {
|
||||||
|
StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst)
|
||||||
|
if put_back.is_empty() => {
|
||||||
|
mem::replace(&mut **stream_inst, StreamInstance::Null)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.stream_inst.0.borrow_mut().1 = stream_inst;
|
||||||
|
}
|
||||||
|
|
||||||
// returns true on success.
|
// returns true on success.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super)
|
pub(super)
|
||||||
fn reset(&mut self) -> bool {
|
fn reset(&mut self) -> bool {
|
||||||
self.stream_inst.0.borrow_mut().0 = false;
|
self.stream_inst.0.borrow_mut().0 = false;
|
||||||
|
|
||||||
match self.stream_inst.0.borrow_mut().1 {
|
loop {
|
||||||
StreamInstance::Bytes(ref mut cursor) => {
|
match self.stream_inst.0.borrow_mut().1 {
|
||||||
cursor.set_position(0);
|
StreamInstance::Bytes(ref mut cursor) => {
|
||||||
true
|
cursor.set_position(0);
|
||||||
}
|
return true;
|
||||||
StreamInstance::InputFile(_, ref mut file) => {
|
}
|
||||||
file.seek(SeekFrom::Start(0)).unwrap();
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
true
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
}
|
return true;
|
||||||
StreamInstance::ReadlineStream(_) => {
|
}
|
||||||
true
|
StreamInstance::PausedPrologStream(ref mut put_back, _) => {
|
||||||
}
|
put_back.clear();
|
||||||
_ => {
|
}
|
||||||
false
|
StreamInstance::ReadlineStream(_) => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.unpause_stream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,6 +783,34 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn pause_stream(&mut self, buf: Vec<io::Result<char>>) -> io::Result<()> {
|
||||||
|
match self.stream_inst.0.borrow_mut().1 {
|
||||||
|
StreamInstance::PausedPrologStream(ref mut inner_buf, _) => {
|
||||||
|
inner_buf.extend(parser_top_to_bytes(buf)?.into_iter());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
let stream_inst = mem::replace(
|
||||||
|
&mut self.stream_inst.0.borrow_mut().1,
|
||||||
|
StreamInstance::Null,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.stream_inst.0.borrow_mut().1 =
|
||||||
|
StreamInstance::PausedPrologStream(
|
||||||
|
parser_top_to_bytes(buf)?,
|
||||||
|
Box::new(stream_inst),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@@ -883,7 +1007,7 @@ impl MachineState {
|
|||||||
stub_name: &'static str,
|
stub_name: &'static str,
|
||||||
stub_arity: usize,
|
stub_arity: usize,
|
||||||
) -> Result<PrologStream, MachineStub> {
|
) -> Result<PrologStream, MachineStub> {
|
||||||
match parsing_stream(stream.clone()) {
|
match parsing_stream(stream) {
|
||||||
Ok(parsing_stream) => {
|
Ok(parsing_stream) => {
|
||||||
Ok(parsing_stream)
|
Ok(parsing_stream)
|
||||||
}
|
}
|
||||||
@@ -1045,38 +1169,11 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Read for Stream {
|
impl Read for Stream {
|
||||||
|
#[inline]
|
||||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
match self.stream_inst.0.borrow_mut().1 {
|
let bytes_read = self.stream_inst.0.borrow_mut().1.read(buf)?;
|
||||||
StreamInstance::InputFile(_, ref mut file) => {
|
self.unpause_stream();
|
||||||
file.read(buf)
|
Ok(bytes_read)
|
||||||
}
|
|
||||||
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
|
||||||
tcp_stream.read(buf)
|
|
||||||
}
|
|
||||||
StreamInstance::TlsStream(_, ref mut tls_stream) => {
|
|
||||||
tls_stream.read(buf)
|
|
||||||
}
|
|
||||||
StreamInstance::ReadlineStream(ref mut rl_stream) => {
|
|
||||||
rl_stream.read(buf)
|
|
||||||
}
|
|
||||||
StreamInstance::DynReadSource(ref mut src) => {
|
|
||||||
src.read(buf)
|
|
||||||
}
|
|
||||||
StreamInstance::Bytes(ref mut cursor) => {
|
|
||||||
cursor.read(buf)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
StreamInstance::Stdin => {
|
|
||||||
stdin().read(buf)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
StreamInstance::OutputFile(..) | StreamInstance::Stdout | StreamInstance::Null => {
|
|
||||||
Err(std::io::Error::new(
|
|
||||||
ErrorKind::PermissionDenied,
|
|
||||||
StreamError::ReadFromOutputStream,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1098,8 +1195,11 @@ impl Write for Stream {
|
|||||||
StreamInstance::Stdout => {
|
StreamInstance::Stdout => {
|
||||||
stdout().write(buf)
|
stdout().write(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
StreamInstance::PausedPrologStream(..) |
|
||||||
StreamInstance::InputFile(..) | StreamInstance::Null => {
|
StreamInstance::StaticStr(_) |
|
||||||
|
StreamInstance::ReadlineStream(_) |
|
||||||
|
StreamInstance::InputFile(..) |
|
||||||
|
StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::WriteToInputStream,
|
StreamError::WriteToInputStream,
|
||||||
@@ -1125,8 +1225,11 @@ impl Write for Stream {
|
|||||||
StreamInstance::Stdout => {
|
StreamInstance::Stdout => {
|
||||||
stdout().flush()
|
stdout().flush()
|
||||||
}
|
}
|
||||||
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
StreamInstance::PausedPrologStream(..) |
|
||||||
StreamInstance::InputFile(..) | StreamInstance::Null => {
|
StreamInstance::StaticStr(_) |
|
||||||
|
StreamInstance::ReadlineStream(_) |
|
||||||
|
StreamInstance::InputFile(..) |
|
||||||
|
StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::FlushToInputStream,
|
StreamError::FlushToInputStream,
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ use crate::openssl::ec::{EcGroup, EcPoint};
|
|||||||
use crate::openssl::bn::{BigNum, BigNumContext};
|
use crate::openssl::bn::{BigNum, BigNumContext};
|
||||||
use crate::openssl::nid::Nid;
|
use crate::openssl::nid::Nid;
|
||||||
|
|
||||||
|
use sodiumoxide::crypto::scalarmult::curve25519::*;
|
||||||
|
|
||||||
use crate::native_tls::TlsConnector;
|
use crate::native_tls::TlsConnector;
|
||||||
|
|
||||||
extern crate select;
|
extern crate select;
|
||||||
@@ -373,6 +375,113 @@ impl MachineState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stream_from_file_spec(
|
||||||
|
&self,
|
||||||
|
file_spec: ClauseName,
|
||||||
|
indices: &mut IndexStore,
|
||||||
|
options: &StreamOptions,
|
||||||
|
) -> Result<Stream, MachineStub> {
|
||||||
|
if file_spec.as_str().is_empty() {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
||||||
|
let err = MachineError::domain_error(
|
||||||
|
DomainErrorType::SourceSink,
|
||||||
|
self[temp_v!(1)],
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8.11.5.3l)
|
||||||
|
if let Some(ref alias) = &options.alias {
|
||||||
|
if indices.stream_aliases.contains_key(alias) {
|
||||||
|
return Err(self.occupied_alias_permission_error(
|
||||||
|
alias.clone(),
|
||||||
|
"open",
|
||||||
|
4,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mode =
|
||||||
|
atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)])));
|
||||||
|
|
||||||
|
let mut open_options = fs::OpenOptions::new();
|
||||||
|
|
||||||
|
let (is_input_file, in_append_mode) =
|
||||||
|
match mode.as_str() {
|
||||||
|
"read" => {
|
||||||
|
open_options.read(true).write(false).create(false);
|
||||||
|
(true, false)
|
||||||
|
}
|
||||||
|
"write" => {
|
||||||
|
open_options.read(false).write(true).truncate(true).create(true);
|
||||||
|
(false, false)
|
||||||
|
}
|
||||||
|
"append" => {
|
||||||
|
open_options.read(false).write(true).create(true).append(true);
|
||||||
|
(false, true)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
||||||
|
let err = MachineError::domain_error(
|
||||||
|
DomainErrorType::IOMode,
|
||||||
|
self[temp_v!(2)],
|
||||||
|
);
|
||||||
|
|
||||||
|
// 8.11.5.3h)
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let file =
|
||||||
|
match open_options.open(file_spec.as_str()) {
|
||||||
|
Ok(file) => {
|
||||||
|
file
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
match err.kind() {
|
||||||
|
ErrorKind::NotFound => {
|
||||||
|
// 8.11.5.3j)
|
||||||
|
let stub = MachineError::functor_stub(
|
||||||
|
clause_name!("open"),
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
|
||||||
|
let err = MachineError::existence_error(
|
||||||
|
self.heap.h(),
|
||||||
|
ExistenceError::SourceSink(self[temp_v!(1)]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
ErrorKind::PermissionDenied => {
|
||||||
|
// 8.11.5.3k)
|
||||||
|
return Err(self.open_permission_error(self[temp_v!(1)], "open", 4));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let stub = MachineError::functor_stub(
|
||||||
|
clause_name!("open"),
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
|
||||||
|
let err = MachineError::syntax_error(
|
||||||
|
self.heap.h(),
|
||||||
|
ParserError::IO(err),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(if is_input_file {
|
||||||
|
Stream::from_file_as_input(file_spec, file)
|
||||||
|
} else {
|
||||||
|
Stream::from_file_as_output(file_spec, file, in_append_mode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn install_new_block(&mut self, r: RegType) -> usize {
|
fn install_new_block(&mut self, r: RegType) -> usize {
|
||||||
self.block = self.b;
|
self.block = self.b;
|
||||||
@@ -1027,20 +1136,24 @@ impl MachineState {
|
|||||||
|
|
||||||
match iter.focus() {
|
match iter.focus() {
|
||||||
Addr::EmptyList => {
|
Addr::EmptyList => {
|
||||||
let chars = clause_name!(string, indices.atom_tbl);
|
if &string == "[]" {
|
||||||
let atom = self.heap.to_unifiable(
|
self.unify(addr, Addr::EmptyList);
|
||||||
HeapCellValue::Atom(chars, None)
|
} else {
|
||||||
);
|
let chars = clause_name!(string, indices.atom_tbl);
|
||||||
|
let atom = self.heap.to_unifiable(
|
||||||
|
HeapCellValue::Atom(chars, None)
|
||||||
|
);
|
||||||
|
|
||||||
self.unify(addr, atom);
|
self.unify(addr, atom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
focus => {
|
focus => {
|
||||||
let stub = MachineError::functor_stub(
|
|
||||||
clause_name!("atom_chars"),
|
|
||||||
2,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Addr::Lis(l) = focus {
|
if let Addr::Lis(l) = focus {
|
||||||
|
let stub = MachineError::functor_stub(
|
||||||
|
clause_name!("atom_chars"),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
|
||||||
let err = MachineError::type_error(
|
let err = MachineError::type_error(
|
||||||
self.heap.h(),
|
self.heap.h(),
|
||||||
ValidType::Character,
|
ValidType::Character,
|
||||||
@@ -1669,6 +1782,12 @@ impl MachineState {
|
|||||||
Ok(Number::Integer(n)) => {
|
Ok(Number::Integer(n)) => {
|
||||||
n.to_string()
|
n.to_string()
|
||||||
}
|
}
|
||||||
|
Ok(Number::Rational(r)) => {
|
||||||
|
// n has already been confirmed as an integer, and
|
||||||
|
// internally, Rational is assumed reduced, so its denominator
|
||||||
|
// must be 1.
|
||||||
|
r.numer().to_string()
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -1694,6 +1813,12 @@ impl MachineState {
|
|||||||
Ok(Number::Integer(n)) => {
|
Ok(Number::Integer(n)) => {
|
||||||
n.to_string()
|
n.to_string()
|
||||||
}
|
}
|
||||||
|
Ok(Number::Rational(r)) => {
|
||||||
|
// n has already been confirmed as an integer, and
|
||||||
|
// internally, Rational is assumed reduced, so its
|
||||||
|
// denominator must be 1.
|
||||||
|
r.numer().to_string()
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -2119,7 +2244,7 @@ impl MachineState {
|
|||||||
bytes = string.into_bytes();
|
bytes = string.into_bytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
match stream.write(&bytes) {
|
match stream.write_all(&bytes) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
return return_from_clause!(self.last_call, self);
|
return return_from_clause!(self.last_call, self);
|
||||||
}
|
}
|
||||||
@@ -2468,10 +2593,11 @@ impl MachineState {
|
|||||||
string.push(c as char);
|
string.push(c as char);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut iter = self.open_parsing_stream(stream.clone(),
|
let mut iter = self.open_parsing_stream(
|
||||||
"get_n_chars",
|
stream.clone(),
|
||||||
2,
|
"get_n_chars",
|
||||||
)?;
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
let result = iter.next();
|
let result = iter.next();
|
||||||
@@ -3349,12 +3475,12 @@ impl MachineState {
|
|||||||
let options =
|
let options =
|
||||||
self.to_stream_options(alias, eof_action, reposition, stream_type);
|
self.to_stream_options(alias, eof_action, reposition, stream_type);
|
||||||
|
|
||||||
let file_spec =
|
let mut stream =
|
||||||
match self.store(self.deref(self[temp_v!(1)])) {
|
match self.store(self.deref(self[temp_v!(1)])) {
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
match &self.heap[h] {
|
match &self.heap[h] {
|
||||||
&HeapCellValue::Atom(ref atom, _) => {
|
&HeapCellValue::Atom(ref atom, _) => {
|
||||||
atom.clone()
|
self.stream_from_file_spec(atom.clone(), indices, &options)?
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -3367,109 +3493,24 @@ impl MachineState {
|
|||||||
let mut heap_pstr_iter =
|
let mut heap_pstr_iter =
|
||||||
self.heap_pstr_iter(Addr::PStrLocation(h, n));
|
self.heap_pstr_iter(Addr::PStrLocation(h, n));
|
||||||
|
|
||||||
clause_name!(
|
let file_spec =
|
||||||
heap_pstr_iter.to_string(),
|
clause_name!(
|
||||||
indices.atom_tbl.clone()
|
heap_pstr_iter.to_string(),
|
||||||
)
|
indices.atom_tbl.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
self.stream_from_file_spec(file_spec, indices, &options)?
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
clause_name!("")
|
self.stream_from_file_spec(clause_name!(""), indices, &options)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
clause_name!("")
|
self.stream_from_file_spec(clause_name!(""), indices, &options)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if file_spec.as_str().is_empty() {
|
|
||||||
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
|
||||||
let err = MachineError::domain_error(
|
|
||||||
DomainErrorType::SourceSink,
|
|
||||||
self[temp_v!(1)],
|
|
||||||
);
|
|
||||||
|
|
||||||
return Err(self.error_form(err, stub));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8.11.5.3l)
|
|
||||||
if let Some(ref alias) = &options.alias {
|
|
||||||
if indices.stream_aliases.contains_key(alias) {
|
|
||||||
return Err(self.occupied_alias_permission_error(
|
|
||||||
alias.clone(),
|
|
||||||
"open",
|
|
||||||
4,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mode =
|
|
||||||
atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)])));
|
|
||||||
|
|
||||||
let mut open_options = fs::OpenOptions::new();
|
|
||||||
|
|
||||||
let (is_input_file, in_append_mode) =
|
|
||||||
match mode.as_str() {
|
|
||||||
"read" => {
|
|
||||||
open_options.read(true).write(false).create(false);
|
|
||||||
(true, false)
|
|
||||||
}
|
|
||||||
"write" => {
|
|
||||||
open_options.read(false).write(true).truncate(true).create(true);
|
|
||||||
(false, false)
|
|
||||||
}
|
|
||||||
"append" => {
|
|
||||||
open_options.read(false).write(true).create(true).append(true);
|
|
||||||
(false, true)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
|
||||||
let err = MachineError::domain_error(
|
|
||||||
DomainErrorType::IOMode,
|
|
||||||
self[temp_v!(2)],
|
|
||||||
);
|
|
||||||
|
|
||||||
// 8.11.5.3h)
|
|
||||||
return Err(self.error_form(err, stub));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let file =
|
|
||||||
match open_options.open(file_spec.as_str()).map_err(|e| e.kind()) {
|
|
||||||
Ok(file) => {
|
|
||||||
file
|
|
||||||
}
|
|
||||||
Err(ErrorKind::NotFound) => {
|
|
||||||
// 8.11.5.3j)
|
|
||||||
let stub = MachineError::functor_stub(
|
|
||||||
clause_name!("open"),
|
|
||||||
4,
|
|
||||||
);
|
|
||||||
|
|
||||||
let err = MachineError::existence_error(
|
|
||||||
self.heap.h(),
|
|
||||||
ExistenceError::SourceSink(self[temp_v!(1)]),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Err(self.error_form(err, stub));
|
|
||||||
}
|
|
||||||
Err(ErrorKind::PermissionDenied) => {
|
|
||||||
// 8.11.5.3k)
|
|
||||||
return Err(self.open_permission_error(self[temp_v!(1)], "open", 4));
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
// for now, just fail. expand to meaningful error messages later.
|
|
||||||
self.fail = true;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut stream = if is_input_file {
|
|
||||||
Stream::from_file_as_input(file_spec, file)
|
|
||||||
} else {
|
|
||||||
Stream::from_file_as_output(file_spec, file, in_append_mode)
|
|
||||||
};
|
|
||||||
|
|
||||||
stream.options = options;
|
stream.options = options;
|
||||||
|
|
||||||
indices.streams.insert(stream.clone());
|
indices.streams.insert(stream.clone());
|
||||||
@@ -3753,6 +3794,12 @@ impl MachineState {
|
|||||||
let code = match Number::try_from((code, &self.heap)) {
|
let code = match Number::try_from((code, &self.heap)) {
|
||||||
Ok(Number::Fixnum(n)) => n as i32,
|
Ok(Number::Fixnum(n)) => n as i32,
|
||||||
Ok(Number::Integer(n)) => n.to_i32().unwrap(),
|
Ok(Number::Integer(n)) => n.to_i32().unwrap(),
|
||||||
|
Ok(Number::Rational(r)) => {
|
||||||
|
// n has already been confirmed as an integer, and
|
||||||
|
// internally, Rational is assumed reduced, so its
|
||||||
|
// denominator must be 1.
|
||||||
|
r.numer().to_i32().unwrap()
|
||||||
|
}
|
||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4473,16 +4520,10 @@ impl MachineState {
|
|||||||
let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]);
|
let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]);
|
||||||
let chars = heap_pstr_iter.to_string();
|
let chars = heap_pstr_iter.to_string();
|
||||||
|
|
||||||
let mut stream = self.open_parsing_stream(
|
|
||||||
Stream::from(chars),
|
|
||||||
"read_term_from_chars",
|
|
||||||
2,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let Addr::EmptyList = heap_pstr_iter.focus() {
|
if let Addr::EmptyList = heap_pstr_iter.focus() {
|
||||||
let term_write_result =
|
let term_write_result =
|
||||||
match self.read(
|
match self.read(
|
||||||
&mut stream,
|
Stream::from(chars),
|
||||||
indices.atom_tbl.clone(),
|
indices.atom_tbl.clone(),
|
||||||
&indices.op_dir,
|
&indices.op_dir,
|
||||||
) {
|
) {
|
||||||
@@ -5387,23 +5428,13 @@ impl MachineState {
|
|||||||
self.unify(arg, byte);
|
self.unify(arg, byte);
|
||||||
}
|
}
|
||||||
&SystemClauseType::CryptoDataHash => {
|
&SystemClauseType::CryptoDataHash => {
|
||||||
let bytes = self.string_encoding_bytes(1, 2);
|
let encoding = self.atom_argument_to_string(2);
|
||||||
|
let bytes = self.string_encoding_bytes(1, &encoding);
|
||||||
|
|
||||||
let algorithm_str = match self.store(self.deref(self[temp_v!(4)])) {
|
let algorithm = self.atom_argument_to_string(4);
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
|
||||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
|
||||||
atom.as_str()
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let ints_list =
|
let ints_list =
|
||||||
match algorithm_str {
|
match algorithm.as_str() {
|
||||||
"sha3_224" => { let mut context = Sha3_224::new();
|
"sha3_224" => { let mut context = Sha3_224::new();
|
||||||
context.input(&bytes);
|
context.input(&bytes);
|
||||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
||||||
@@ -5426,7 +5457,7 @@ impl MachineState {
|
|||||||
context.input(&bytes);
|
context.input(&bytes);
|
||||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
||||||
_ => { let ints = digest::digest(
|
_ => { let ints = digest::digest(
|
||||||
match algorithm_str {
|
match algorithm.as_str() {
|
||||||
"sha256" => { &digest::SHA256 }
|
"sha256" => { &digest::SHA256 }
|
||||||
"sha384" => { &digest::SHA384 }
|
"sha384" => { &digest::SHA384 }
|
||||||
"sha512" => { &digest::SHA512 }
|
"sha512" => { &digest::SHA512 }
|
||||||
@@ -5441,27 +5472,19 @@ impl MachineState {
|
|||||||
self.unify(self[temp_v!(3)], ints_list);
|
self.unify(self[temp_v!(3)], ints_list);
|
||||||
}
|
}
|
||||||
&SystemClauseType::CryptoDataHKDF => {
|
&SystemClauseType::CryptoDataHKDF => {
|
||||||
let data = self.string_encoding_bytes(1, 2);
|
let encoding = self.atom_argument_to_string(2);
|
||||||
|
let data = self.string_encoding_bytes(1, &encoding);
|
||||||
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4);
|
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4);
|
||||||
let salt = self.integers_to_bytevec(temp_v!(3), stub1);
|
let salt = self.integers_to_bytevec(temp_v!(3), stub1);
|
||||||
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4);
|
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4);
|
||||||
let info = self.integers_to_bytevec(temp_v!(4), stub2);
|
let info = self.integers_to_bytevec(temp_v!(4), stub2);
|
||||||
|
|
||||||
let algorithm = match self.store(self.deref(self[temp_v!(5)])) {
|
let algorithm = self.atom_argument_to_string(5);
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
|
||||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
let length = self.store(self.deref(self[temp_v!(6)]));
|
||||||
atom.as_str()
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let length =
|
let length =
|
||||||
match Number::try_from((self[temp_v!(6)], &self.heap)) {
|
match Number::try_from((length, &self.heap)) {
|
||||||
Ok(Number::Fixnum(n)) => {
|
Ok(Number::Fixnum(n)) => {
|
||||||
usize::try_from(n).unwrap()
|
usize::try_from(n).unwrap()
|
||||||
}
|
}
|
||||||
@@ -5476,7 +5499,7 @@ impl MachineState {
|
|||||||
|
|
||||||
let ints_list =
|
let ints_list =
|
||||||
{ let digest_alg =
|
{ let digest_alg =
|
||||||
match algorithm {
|
match algorithm.as_str() {
|
||||||
"sha256" => { hkdf::HKDF_SHA256 }
|
"sha256" => { hkdf::HKDF_SHA256 }
|
||||||
"sha384" => { hkdf::HKDF_SHA384 }
|
"sha384" => { hkdf::HKDF_SHA384 }
|
||||||
"sha512" => { hkdf::HKDF_SHA512 }
|
"sha512" => { hkdf::HKDF_SHA512 }
|
||||||
@@ -5501,15 +5524,20 @@ impl MachineState {
|
|||||||
let stub2 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3);
|
let stub2 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3);
|
||||||
let salt = self.integers_to_bytevec(temp_v!(2), stub2);
|
let salt = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||||
|
|
||||||
|
let iterations = self.store(self.deref(self[temp_v!(3)]));
|
||||||
|
|
||||||
let iterations =
|
let iterations =
|
||||||
match Number::try_from((self[temp_v!(3)], &self.heap)) {
|
match Number::try_from((iterations, &self.heap)) {
|
||||||
Ok(Number::Fixnum(n)) => {
|
Ok(Number::Fixnum(n)) => {
|
||||||
u64::try_from(n).unwrap()
|
u64::try_from(n).unwrap()
|
||||||
}
|
}
|
||||||
Ok(Number::Integer(n)) => {
|
Ok(Number::Integer(n)) => {
|
||||||
match n.to_u64() {
|
match n.to_u64() {
|
||||||
Some(i) => { i }
|
Some(i) => { i }
|
||||||
None => { self.fail = true; return Ok(()); }
|
None => {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -5529,11 +5557,13 @@ impl MachineState {
|
|||||||
self.unify(self[temp_v!(4)], ints_list);
|
self.unify(self[temp_v!(4)], ints_list);
|
||||||
}
|
}
|
||||||
&SystemClauseType::CryptoDataEncrypt => {
|
&SystemClauseType::CryptoDataEncrypt => {
|
||||||
let data = self.string_encoding_bytes(1, 2);
|
let encoding = self.atom_argument_to_string(3);
|
||||||
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
let data = self.string_encoding_bytes(1, &encoding);
|
||||||
let key = self.integers_to_bytevec(temp_v!(3), stub2);
|
let aad = self.string_encoding_bytes(2, &encoding);
|
||||||
let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7);
|
||||||
let iv = self.integers_to_bytevec(temp_v!(4), stub3);
|
let key = self.integers_to_bytevec(temp_v!(4), stub2);
|
||||||
|
let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7);
|
||||||
|
let iv = self.integers_to_bytevec(temp_v!(5), stub3);
|
||||||
|
|
||||||
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||||
let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
|
let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
|
||||||
@@ -5541,7 +5571,7 @@ impl MachineState {
|
|||||||
|
|
||||||
let mut in_out = data.clone();
|
let mut in_out = data.clone();
|
||||||
let tag =
|
let tag =
|
||||||
match key.seal_in_place_separate_tag(nonce, aead::Aad::empty(), &mut in_out) {
|
match key.seal_in_place_separate_tag(nonce, aead::Aad::from(aad), &mut in_out) {
|
||||||
Ok(d) => { d }
|
Ok(d) => { d }
|
||||||
_ => { self.fail = true; return Ok(()); }
|
_ => { self.fail = true; return Ok(()); }
|
||||||
};
|
};
|
||||||
@@ -5554,29 +5584,18 @@ impl MachineState {
|
|||||||
self.heap.put_complete_string(&buffer)
|
self.heap.put_complete_string(&buffer)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.unify(self[temp_v!(5)], tag_list);
|
self.unify(self[temp_v!(6)], tag_list);
|
||||||
self.unify(self[temp_v!(6)], complete_string);
|
self.unify(self[temp_v!(7)], complete_string);
|
||||||
}
|
}
|
||||||
&SystemClauseType::CryptoDataDecrypt => {
|
&SystemClauseType::CryptoDataDecrypt => {
|
||||||
let data = self.string_encoding_bytes(1, 2);
|
let data = self.string_encoding_bytes(1, "octet");
|
||||||
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
let encoding = self.atom_argument_to_string(5);
|
||||||
|
let aad = self.string_encoding_bytes(2, &encoding);
|
||||||
|
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7);
|
||||||
let key = self.integers_to_bytevec(temp_v!(3), stub1);
|
let key = self.integers_to_bytevec(temp_v!(3), stub1);
|
||||||
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7);
|
||||||
let iv = self.integers_to_bytevec(temp_v!(4), stub2);
|
let iv = self.integers_to_bytevec(temp_v!(4), stub2);
|
||||||
|
|
||||||
let encoding = match self.store(self.deref(self[temp_v!(5)])) {
|
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
|
||||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
|
||||||
atom.as_str()
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||||
let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
|
let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
|
||||||
let key = aead::LessSafeKey::new(unbound_key);
|
let key = aead::LessSafeKey::new(unbound_key);
|
||||||
@@ -5585,12 +5604,12 @@ impl MachineState {
|
|||||||
|
|
||||||
let complete_string = {
|
let complete_string = {
|
||||||
let decrypted_data =
|
let decrypted_data =
|
||||||
match key.open_in_place(nonce, aead::Aad::empty(), &mut in_out) {
|
match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) {
|
||||||
Ok(d) => { d }
|
Ok(d) => { d }
|
||||||
_ => { self.fail = true; return Ok(()); }
|
_ => { self.fail = true; return Ok(()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = match encoding {
|
let buffer = match encoding.as_str() {
|
||||||
"octet" => { String::from_iter(decrypted_data.iter().map(|b| *b as char)) }
|
"octet" => { String::from_iter(decrypted_data.iter().map(|b| *b as char)) }
|
||||||
"utf8" => { match String::from_utf8(decrypted_data.to_vec()) {
|
"utf8" => { match String::from_utf8(decrypted_data.to_vec()) {
|
||||||
Ok(str) => { str }
|
Ok(str) => { str }
|
||||||
@@ -5606,26 +5625,17 @@ impl MachineState {
|
|||||||
self.unify(self[temp_v!(6)], complete_string);
|
self.unify(self[temp_v!(6)], complete_string);
|
||||||
}
|
}
|
||||||
&SystemClauseType::CryptoCurveScalarMult => {
|
&SystemClauseType::CryptoCurveScalarMult => {
|
||||||
let curve = match self.store(self.deref(self[temp_v!(1)])) {
|
let curve = self.atom_argument_to_string(1);
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
let curve_id = match curve.as_str() {
|
||||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
|
||||||
atom.as_str()
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let curve_id = match curve {
|
|
||||||
"secp112r1" => { Nid::SECP112R1 }
|
"secp112r1" => { Nid::SECP112R1 }
|
||||||
"secp256k1" => { Nid::SECP256K1 }
|
"secp256k1" => { Nid::SECP256K1 }
|
||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let scalar = self.store(self.deref(self[temp_v!(2)]));
|
||||||
|
|
||||||
let scalar =
|
let scalar =
|
||||||
match Number::try_from((self[temp_v!(2)], &self.heap)) {
|
match Number::try_from((scalar, &self.heap)) {
|
||||||
Ok(Number::Fixnum(n)) => {
|
Ok(Number::Fixnum(n)) => {
|
||||||
Integer::from(n)
|
Integer::from(n)
|
||||||
}
|
}
|
||||||
@@ -5664,7 +5674,7 @@ impl MachineState {
|
|||||||
self.unify(self[temp_v!(1)], complete_string);
|
self.unify(self[temp_v!(1)], complete_string);
|
||||||
}
|
}
|
||||||
&SystemClauseType::Ed25519KeyPairPublicKey => {
|
&SystemClauseType::Ed25519KeyPairPublicKey => {
|
||||||
let bytes = self.string_encoding_bytes(1, 2);
|
let bytes = self.string_encoding_bytes(1, "octet");
|
||||||
|
|
||||||
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
|
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
|
||||||
Ok(kp) => { kp }
|
Ok(kp) => { kp }
|
||||||
@@ -5676,11 +5686,12 @@ impl MachineState {
|
|||||||
self.heap.put_complete_string(&buffer)
|
self.heap.put_complete_string(&buffer)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.unify(self[temp_v!(3)], complete_string);
|
self.unify(self[temp_v!(2)], complete_string);
|
||||||
}
|
}
|
||||||
&SystemClauseType::Ed25519Sign => {
|
&SystemClauseType::Ed25519Sign => {
|
||||||
let key = self.string_encoding_bytes(1, 2);
|
let key = self.string_encoding_bytes(1, "octet");
|
||||||
let data = self.string_encoding_bytes(3, 4);
|
let encoding = self.atom_argument_to_string(3);
|
||||||
|
let data = self.string_encoding_bytes(2, &encoding);
|
||||||
|
|
||||||
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
|
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
|
||||||
Ok(kp) => { kp }
|
Ok(kp) => { kp }
|
||||||
@@ -5692,13 +5703,14 @@ impl MachineState {
|
|||||||
let sig_list =
|
let sig_list =
|
||||||
Addr::HeapCell(self.heap.to_list(sig.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))));
|
Addr::HeapCell(self.heap.to_list(sig.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))));
|
||||||
|
|
||||||
self.unify(self[temp_v!(5)], sig_list);
|
self.unify(self[temp_v!(4)], sig_list);
|
||||||
}
|
}
|
||||||
&SystemClauseType::Ed25519Verify => {
|
&SystemClauseType::Ed25519Verify => {
|
||||||
let key = self.string_encoding_bytes(1, 2);
|
let key = self.string_encoding_bytes(1, "octet");
|
||||||
let data = self.string_encoding_bytes(3, 4);
|
let encoding = self.atom_argument_to_string(3);
|
||||||
|
let data = self.string_encoding_bytes(2, &encoding);
|
||||||
let stub = MachineError::functor_stub(clause_name!("ed25519_verify"), 5);
|
let stub = MachineError::functor_stub(clause_name!("ed25519_verify"), 5);
|
||||||
let signature = self.integers_to_bytevec(temp_v!(5), stub);
|
let signature = self.integers_to_bytevec(temp_v!(4), stub);
|
||||||
|
|
||||||
let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
|
let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
|
||||||
match peer_public_key.verify(&data, &signature) {
|
match peer_public_key.verify(&data, &signature) {
|
||||||
@@ -5706,6 +5718,21 @@ impl MachineState {
|
|||||||
_ => { self.fail = true; return Ok(()); }
|
_ => { self.fail = true; return Ok(()); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::Curve25519ScalarMult => {
|
||||||
|
let stub1 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3);
|
||||||
|
let scalar_bytes = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||||
|
let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
|
||||||
|
|
||||||
|
let stub2 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3);
|
||||||
|
let point_bytes = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||||
|
let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
|
||||||
|
|
||||||
|
let result = scalarmult(&scalar, &point).unwrap();
|
||||||
|
|
||||||
|
let string = String::from_iter(result[..].iter().map(|b| *b as char));
|
||||||
|
let cstr = self.heap.put_complete_string(&string);
|
||||||
|
self.unify(self[temp_v!(3)], cstr);
|
||||||
|
}
|
||||||
&SystemClauseType::LoadHTML => {
|
&SystemClauseType::LoadHTML => {
|
||||||
let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
|
let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
|
||||||
let doc = select::document::Document::from_read(string.as_bytes()).unwrap();
|
let doc = select::document::Document::from_read(string.as_bytes()).unwrap();
|
||||||
@@ -5747,32 +5774,18 @@ impl MachineState {
|
|||||||
env::remove_var(key);
|
env::remove_var(key);
|
||||||
}
|
}
|
||||||
&SystemClauseType::CharsBase64 => {
|
&SystemClauseType::CharsBase64 => {
|
||||||
let mut options = vec![];
|
let padding = self.atom_argument_to_string(3);
|
||||||
|
let charset = self.atom_argument_to_string(4);
|
||||||
for i in 3..5 {
|
|
||||||
match self.store(self.deref(self[temp_v!(i)])) {
|
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
|
||||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
|
||||||
options.push(atom.as_str());
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let config =
|
let config =
|
||||||
if options[0] == "true" {
|
if padding == "true" {
|
||||||
if options[1] == "standard" {
|
if charset == "standard" {
|
||||||
base64::STANDARD
|
base64::STANDARD
|
||||||
} else {
|
} else {
|
||||||
base64::URL_SAFE
|
base64::URL_SAFE
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if options[1] == "standard" {
|
if charset == "standard" {
|
||||||
base64::STANDARD_NO_PAD
|
base64::STANDARD_NO_PAD
|
||||||
} else {
|
} else {
|
||||||
base64::URL_SAFE_NO_PAD
|
base64::URL_SAFE_NO_PAD
|
||||||
@@ -5785,10 +5798,7 @@ impl MachineState {
|
|||||||
|
|
||||||
match bytes {
|
match bytes {
|
||||||
Ok(bs) => {
|
Ok(bs) => {
|
||||||
let mut string = String::new();
|
let string = String::from_iter(bs.iter().map(|b| *b as char));
|
||||||
for c in bs {
|
|
||||||
string.push(c as char);
|
|
||||||
}
|
|
||||||
let cstr = self.heap.put_complete_string(&string);
|
let cstr = self.heap.put_complete_string(&string);
|
||||||
self.unify(self[temp_v!(1)], cstr);
|
self.unify(self[temp_v!(1)], cstr);
|
||||||
}
|
}
|
||||||
@@ -5844,17 +5854,14 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super)
|
pub(super)
|
||||||
fn string_encoding_bytes(
|
fn atom_argument_to_string(
|
||||||
&mut self,
|
&mut self,
|
||||||
data_arg: usize,
|
atom_arg: usize,
|
||||||
encoding_arg: usize,
|
) -> String {
|
||||||
) -> Vec<u8> {
|
match self.store(self.deref(self[temp_v!(atom_arg)])) {
|
||||||
let data = self.heap_pstr_iter(self[temp_v!(data_arg)]).to_string();
|
|
||||||
|
|
||||||
let encoding_str = match self.store(self.deref(self[temp_v!(encoding_arg)])) {
|
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
||||||
atom.as_str()
|
atom.as_str().to_string()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@@ -5862,9 +5869,18 @@ impl MachineState {
|
|||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match encoding_str {
|
pub(super)
|
||||||
|
fn string_encoding_bytes(
|
||||||
|
&mut self,
|
||||||
|
data_arg: usize,
|
||||||
|
encoding: &str,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let data = self.heap_pstr_iter(self[temp_v!(data_arg)]).to_string();
|
||||||
|
|
||||||
|
match encoding {
|
||||||
"utf8" => { data.into_bytes() }
|
"utf8" => { data.into_bytes() }
|
||||||
"octet" => {
|
"octet" => {
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
@@ -5883,7 +5899,10 @@ impl MachineState {
|
|||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
node: roxmltree::Node,
|
node: roxmltree::Node,
|
||||||
) -> Addr {
|
) -> Addr {
|
||||||
if node.has_children() {
|
if node.is_text() {
|
||||||
|
let string = String::from(node.text().unwrap());
|
||||||
|
self.heap.put_complete_string(&string)
|
||||||
|
} else {
|
||||||
let mut avec = Vec::new();
|
let mut avec = Vec::new();
|
||||||
for attr in node.attributes() {
|
for attr in node.attributes() {
|
||||||
let chars = clause_name!(String::from(attr.name()), indices.atom_tbl);
|
let chars = clause_name!(String::from(attr.name()), indices.atom_tbl);
|
||||||
@@ -5920,9 +5939,6 @@ impl MachineState {
|
|||||||
self.heap.push(HeapCellValue::Addr(children));
|
self.heap.push(HeapCellValue::Addr(children));
|
||||||
|
|
||||||
result
|
result
|
||||||
} else {
|
|
||||||
let string = String::from(node.text().unwrap());
|
|
||||||
self.heap.put_complete_string(&string)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ impl<'a> TermStream<'a> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn eof(&mut self) -> Result<bool, ParserError> {
|
pub fn eof(&mut self) -> Result<bool, ParserError> {
|
||||||
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
|
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
|
||||||
Ok(self.stack.is_empty() && self.parser.eof()?)
|
Ok(self.stack.is_empty() && self.parser.eof()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
src/read.rs
22
src/read.rs
@@ -67,7 +67,10 @@ pub mod readline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*self.pending_input.get_mut() += "\n";
|
if self.pending_input.get_ref().chars().last() != Some('\n') {
|
||||||
|
*self.pending_input.get_mut() += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
self.pending_input.read(buf)
|
self.pending_input.read(buf)
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Eof) => {
|
Err(ReadlineError::Eof) => {
|
||||||
@@ -157,12 +160,23 @@ pub mod readline {
|
|||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub fn read(
|
pub fn read(
|
||||||
&mut self,
|
&mut self,
|
||||||
inner: &mut PrologStream,
|
mut inner: Stream,
|
||||||
atom_tbl: TabledData<Atom>,
|
atom_tbl: TabledData<Atom>,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Result<TermWriteResult, ParserError> {
|
) -> Result<TermWriteResult, ParserError> {
|
||||||
let mut parser = Parser::new(inner, atom_tbl, self.flags);
|
let mut stream = parsing_stream(inner.clone())?;
|
||||||
let term = parser.read_term(composite_op!(op_dir))?;
|
|
||||||
|
let term = {
|
||||||
|
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
|
||||||
|
parser.read_term(composite_op!(op_dir))?
|
||||||
|
};
|
||||||
|
|
||||||
|
// 'pausing' the stream saves the pending top buffer
|
||||||
|
// created by the parsing stream, which was created in this
|
||||||
|
// scope and is about to be destroyed in it.
|
||||||
|
|
||||||
|
let buf = stream.take_buf();
|
||||||
|
inner.pause_stream(buf)?;
|
||||||
|
|
||||||
Ok(write_term_to_heap(&term, self))
|
Ok(write_term_to_heap(&term, self))
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/tests/clpz/combination.pl
Normal file
17
src/tests/clpz/combination.pl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
:- module(combination, [combination/2, combinationr/2]).
|
||||||
|
|
||||||
|
combination([], []).
|
||||||
|
combination([L|Ls], [L|Ms]) :-
|
||||||
|
combination(Ls, Ms).
|
||||||
|
combination([_|Ls], Ms) :-
|
||||||
|
combination(Ls, Ms).
|
||||||
|
|
||||||
|
combinationr([], []).
|
||||||
|
combinationr([L|Ls], Ms) :-
|
||||||
|
combinationr_(Ms, [L|Ls]).
|
||||||
|
|
||||||
|
combinationr_([], _).
|
||||||
|
combinationr_([M|Ms], [M|Ls]) :-
|
||||||
|
combinationr_(Ms, [M|Ls]).
|
||||||
|
combinationr_([M|Ms], [_|Ls]) :-
|
||||||
|
combinationr_([M|Ms], Ls).
|
||||||
27
src/tests/clpz/permutation.pl
Normal file
27
src/tests/clpz/permutation.pl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
:- module(permutation, [arrangement/2, arrangementr/2, permutation/2]).
|
||||||
|
:- use_module(library(lists), [member/2, same_length/2, select/3]).
|
||||||
|
|
||||||
|
permutation(As, Bs) :-
|
||||||
|
same_length(As, Bs),
|
||||||
|
permutation_(Bs, As).
|
||||||
|
|
||||||
|
permutation_([B|Bs], As) :- select(B, As, Cs), permutation_(Bs, Cs).
|
||||||
|
permutation_([], []).
|
||||||
|
|
||||||
|
arrangement([], []).
|
||||||
|
arrangement([A|As], [B|Bs]) :-
|
||||||
|
arrangement_([B|Bs], [A|As]).
|
||||||
|
|
||||||
|
arrangement_([], _).
|
||||||
|
arrangement_([B|Bs], As) :-
|
||||||
|
select(B, As, Cs),
|
||||||
|
arrangement_(Bs, Cs).
|
||||||
|
|
||||||
|
arrangementr([], []).
|
||||||
|
arrangementr([A|As], Bs) :-
|
||||||
|
arrangementr_(Bs, [A|As]).
|
||||||
|
|
||||||
|
arrangementr_([], _).
|
||||||
|
arrangementr_([B|Bs], As) :-
|
||||||
|
member(B, As),
|
||||||
|
arrangementr_(Bs, As).
|
||||||
129
src/tests/clpz/test_clpz.pl
Normal file
129
src/tests/clpz/test_clpz.pl
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
:- use_module(library(debug)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(tabling)).
|
||||||
|
:- use_module('../../lib/clpz').
|
||||||
|
:- use_module(combination).
|
||||||
|
:- use_module(permutation).
|
||||||
|
|
||||||
|
nat(N) :-
|
||||||
|
nat_(0, N).
|
||||||
|
|
||||||
|
nat_(N, N).
|
||||||
|
nat_(N0, N) :-
|
||||||
|
N1 #= N0 + 1,
|
||||||
|
nat_(N1, N).
|
||||||
|
|
||||||
|
n_factorial(0, 1).
|
||||||
|
n_factorial(N, F) :-
|
||||||
|
F #= N * F1,
|
||||||
|
N1 #= N - 1,
|
||||||
|
n_factorial(N1, F1).
|
||||||
|
|
||||||
|
pmod(G, X, Y, Z) :- G = (X mod Y #= Z).
|
||||||
|
pplus(G, X, Y, Z) :- G = (X + Y #= Z).
|
||||||
|
rel(G, X, Y) :- G = (X #=< Y).
|
||||||
|
|
||||||
|
operation(2, Op, [X, Y], G) :-
|
||||||
|
call(Op, G, X, Y).
|
||||||
|
|
||||||
|
operation(3, Op, [X, Y, Z], G) :-
|
||||||
|
call(Op, G, X, Y, Z).
|
||||||
|
|
||||||
|
/*
|
||||||
|
operation(Op, Vs, G) :-
|
||||||
|
Goal =.. [Op, G|Vs],
|
||||||
|
call(Goal).
|
||||||
|
% */
|
||||||
|
|
||||||
|
conjonction(G1, G2, G) :-
|
||||||
|
G = (G2, G1).
|
||||||
|
|
||||||
|
run :-
|
||||||
|
$nat(N),
|
||||||
|
NegN #= -N,
|
||||||
|
Settings = [Nv, Niv, Nr, Nm],
|
||||||
|
|
||||||
|
Settings ins 0..N,
|
||||||
|
Nm #> 0, % Testing Powers.
|
||||||
|
|
||||||
|
label([Nv]),
|
||||||
|
length(Vs, Nv),
|
||||||
|
Vs ins inf..sup, % No labeling.
|
||||||
|
( Nv > 1 ->
|
||||||
|
bagof(Pr, (length(Pr, 2), arrangement(Vs, Pr)), V2s) % No repetitions.
|
||||||
|
; % Allow repetitions.
|
||||||
|
bagof(Pr, (length(Pr, 2), arrangementr(Vs, Pr)), V2s)
|
||||||
|
),
|
||||||
|
bagof(Pr, (length(Pr, 3), arrangementr(Vs, Pr)), V3s),
|
||||||
|
|
||||||
|
( Nv > 1 ->
|
||||||
|
Nr #=< Nv
|
||||||
|
; Nr #= 0
|
||||||
|
),
|
||||||
|
label([Nm, Nr]),
|
||||||
|
length(Gs1, Nm),
|
||||||
|
( Nv > 1 ->
|
||||||
|
length(Gs3, Nr)
|
||||||
|
; length(Gs3, 0)
|
||||||
|
),
|
||||||
|
append(Gs3, Gs1, Gs4),
|
||||||
|
|
||||||
|
length(MVs, Nm),
|
||||||
|
combinationr(V3s, MVs),
|
||||||
|
maplist(operation(3, pmod), MVs, Gs1),
|
||||||
|
|
||||||
|
( Nv > 1 ->
|
||||||
|
length(RVs, Nr),
|
||||||
|
combination(V2s, RVs),
|
||||||
|
maplist(operation(2, rel), RVs, Gs3)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
|
||||||
|
label([Niv]),
|
||||||
|
length(Vs1, Niv),
|
||||||
|
length(Vs2, Niv),
|
||||||
|
combination(Vs, Vs1),
|
||||||
|
Vs2 ins NegN..N,
|
||||||
|
label(Vs2),
|
||||||
|
Vs1 = Vs2,
|
||||||
|
|
||||||
|
% portray_clause([N, Settings, Vs, Gs4]), nl,
|
||||||
|
catch(
|
||||||
|
findall(
|
||||||
|
Ds,
|
||||||
|
( permutation(Gs4, Gs),
|
||||||
|
foldl(conjonction, Gs, true, G),
|
||||||
|
call(G),
|
||||||
|
maplist(fd_dom, Vs, Ds)
|
||||||
|
),
|
||||||
|
Dss
|
||||||
|
),
|
||||||
|
E,
|
||||||
|
( write('caugth: '), write(E), nl,
|
||||||
|
portray_clause([N, Settings, Vs, Gs4, Dss]), nl,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
),
|
||||||
|
length(Dss, Dn),
|
||||||
|
length(Gs4, Gs4n),
|
||||||
|
( Dn == 0 -> true % All false.
|
||||||
|
; ( n_factorial(Gs4n, Dn) -> true
|
||||||
|
; write('Not a factorial: '), write([Gs4n, Dn]), nl,
|
||||||
|
portray_clause([N, Settings, Vs, Gs4, Dss]), nl,
|
||||||
|
*halt(1)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
( \+ maplist(=(_), Dss) ->
|
||||||
|
write('Bound issue:'), nl,
|
||||||
|
write(Dss), nl,
|
||||||
|
transpose(Dss, Dss1),
|
||||||
|
maplist(sort, Dss1, Dss2),
|
||||||
|
portray_clause(Dss2),
|
||||||
|
portray_clause([N, Settings, Vs, Gs4]), nl,
|
||||||
|
% Not easy to solve due to the fact that multiple variables
|
||||||
|
% can not have the right bound.
|
||||||
|
*halt(1)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
false.
|
||||||
@@ -108,28 +108,28 @@ read_and_match :-
|
|||||||
'$read_query_term'(_, Term, _, _, VarList),
|
'$read_query_term'(_, Term, _, _, VarList),
|
||||||
instruction_match(Term, VarList).
|
instruction_match(Term, VarList).
|
||||||
|
|
||||||
|
|
||||||
% make compile_batch, a system routine, callable.
|
% make compile_batch, a system routine, callable.
|
||||||
compile_batch :- '$compile_batch'.
|
compile_batch :- '$compile_batch'.
|
||||||
|
|
||||||
instruction_match(Term, VarList) :-
|
instruction_match(Term, VarList) :-
|
||||||
( var(Term) ->
|
( var(Term) ->
|
||||||
throw(error(instantiation_error, repl/0))
|
throw(error(instantiation_error, repl/0))
|
||||||
;
|
; Term = [Item] ->
|
||||||
Term = [Item] -> !,
|
!,
|
||||||
( atom(Item) ->
|
( atom(Item) ->
|
||||||
( Item == user ->
|
( Item == user ->
|
||||||
catch(compile_batch, E, print_exception_with_check(E))
|
catch(compile_batch, E, print_exception_with_check(E))
|
||||||
; consult(Item)
|
; consult(Item)
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
catch(throw(error(type_error(atom, Item), repl/0)),
|
catch(throw(error(type_error(atom, Item), repl/0)),
|
||||||
E,
|
E,
|
||||||
print_exception_with_check(E))
|
print_exception_with_check(E))
|
||||||
)
|
)
|
||||||
;
|
; Term = end_of_file ->
|
||||||
Term = end_of_file -> halt
|
halt
|
||||||
;
|
; submit_query_and_print_results(Term, VarList)
|
||||||
submit_query_and_print_results(Term, VarList)
|
|
||||||
).
|
).
|
||||||
|
|
||||||
:- use_module(library(iso_ext)).
|
:- use_module(library(iso_ext)).
|
||||||
@@ -159,10 +159,10 @@ needs_bracketing(Value, Op) :-
|
|||||||
false),
|
false),
|
||||||
( EqPrec < FPrec ->
|
( EqPrec < FPrec ->
|
||||||
true
|
true
|
||||||
; '$quoted_token'(F) ->
|
|
||||||
true
|
|
||||||
; FPrec > 0, F == Value, graphic_token_char(F) ->
|
; FPrec > 0, F == Value, graphic_token_char(F) ->
|
||||||
true
|
true
|
||||||
|
; F \== '.', '$quoted_token'(F) ->
|
||||||
|
true
|
||||||
; EqPrec == FPrec,
|
; EqPrec == FPrec,
|
||||||
memberchk(EqSpec, [fx,xfx,yfx])
|
memberchk(EqSpec, [fx,xfx,yfx])
|
||||||
).
|
).
|
||||||
|
|||||||
Reference in New Issue
Block a user