Merge branch 'master' of https://github.com/mthom/rusty-wam into master

This commit is contained in:
Mark Thom
2020-09-14 10:46:11 -06:00
27 changed files with 1195 additions and 571 deletions

29
Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -272,7 +272,7 @@ the exact same internal representation, and has the advantage that
only the standard predicate&nbsp;`(=)/2` is used. only the standard predicate&nbsp;`(=)/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&nbsp;Prolog are also called
Predicates for reasoning about environment&nbsp;variables. Predicates for reasoning about environment&nbsp;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&nbsp;standard, such as `setup_call_cleanup/3` and ISO&nbsp;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&nbsp;(HKDF), password-based key derivation&nbsp;(PBKDF2), derivation&nbsp;(HKDF), password-based key derivation&nbsp;(PBKDF2),
public key signatures and signature verification with&nbsp;Ed25519, public key signatures and signature verification with&nbsp;Ed25519,
authenticated symmetric encryption with ChaCha20-Poly1305, and ECDH key&nbsp;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:

View File

@@ -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),

View File

@@ -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

View File

@@ -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));
} }
_ => {} _ => {
}
}; };
} }

View File

@@ -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))

View File

@@ -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)]
). ).

View File

@@ -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

View File

@@ -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.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@@ -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]).

View File

@@ -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) -->

View File

@@ -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).

View File

@@ -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.

View File

@@ -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)).

View File

@@ -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),

View File

@@ -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))
} }
} }

View File

@@ -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))
} }

View File

@@ -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,
) { ) {

View File

@@ -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,

View File

@@ -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)
} }
} }

View File

@@ -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()?)
} }

View File

@@ -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))
} }

View 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).

View 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
View 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.

View File

@@ -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])
). ).