eyeprolog 1.5.61 → 1.5.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/error.pl +24 -19
- package/src/lib/random.pl +14 -11
- package/test/regression/cases-regression.mjs +18 -0
package/package.json
CHANGED
package/src/lib/error.pl
CHANGED
|
@@ -21,34 +21,39 @@
|
|
|
21
21
|
% raise site: the raise sites throw with [] and this wrapper prepends its
|
|
22
22
|
% element, so contexts stay proper lists and compose with any enclosing
|
|
23
23
|
% call_with_error_context/2 (issue #98).
|
|
24
|
+
% The context is named in exactly one place -- error__must_be_throw/1 -- so no
|
|
25
|
+
% raise site hands one over (issue #98). It is a throw helper rather than a
|
|
26
|
+
% call_with_error_context/2 wrapper because wrapping a Prolog goal in catch/3
|
|
27
|
+
% costs a child Solver on every call, and must_be/2 succeeds almost always.
|
|
24
28
|
must_be(Type, Term) :-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
( var(Type) -> error__must_be_throw(instantiation_error)
|
|
30
|
+
; error__must_be(Type, Term)
|
|
31
|
+
).
|
|
32
|
+
|
|
33
|
+
error__must_be_throw(Formal) :-
|
|
34
|
+
throw(error(Formal, [predicate-must_be/2])).
|
|
30
35
|
|
|
31
36
|
error__must_be(integer, Term) :- !,
|
|
32
|
-
( var(Term) -> instantiation_error
|
|
37
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
33
38
|
; integer(Term) -> true
|
|
34
|
-
; type_error(integer, Term)
|
|
39
|
+
; error__must_be_throw(type_error(integer, Term))
|
|
35
40
|
).
|
|
36
41
|
error__must_be(atom, Term) :- !,
|
|
37
|
-
( var(Term) -> instantiation_error
|
|
42
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
38
43
|
; atom(Term) -> true
|
|
39
|
-
; type_error(atom, Term)
|
|
44
|
+
; error__must_be_throw(type_error(atom, Term))
|
|
40
45
|
).
|
|
41
46
|
error__must_be(number, Term) :- !,
|
|
42
|
-
( var(Term) -> instantiation_error
|
|
47
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
43
48
|
; number(Term) -> true
|
|
44
|
-
; type_error(number, Term)
|
|
49
|
+
; error__must_be_throw(type_error(number, Term))
|
|
45
50
|
).
|
|
46
51
|
error__must_be(var, Term) :- !,
|
|
47
52
|
( var(Term) -> true
|
|
48
53
|
; throw(error(uninstantiation_error(Term), []))
|
|
49
54
|
).
|
|
50
55
|
error__must_be(ground, Term) :- !,
|
|
51
|
-
( ground(Term) -> true ; instantiation_error ).
|
|
56
|
+
( ground(Term) -> true ; error__must_be_throw(instantiation_error) ).
|
|
52
57
|
error__must_be(acyclic, Term) :- !,
|
|
53
58
|
( acyclic_term(Term) -> true ; type_error(acyclic_term, Term) ).
|
|
54
59
|
error__must_be(list, Term) :- !,
|
|
@@ -56,23 +61,23 @@ error__must_be(list, Term) :- !,
|
|
|
56
61
|
error__must_be(list(Type), Term) :- !,
|
|
57
62
|
error__proper_list_of(Term, Type).
|
|
58
63
|
error__must_be(pair, Term) :- !,
|
|
59
|
-
( var(Term) -> instantiation_error
|
|
64
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
60
65
|
; Term = _-_ -> true
|
|
61
|
-
; type_error(pair, Term)
|
|
66
|
+
; error__must_be_throw(type_error(pair, Term))
|
|
62
67
|
).
|
|
63
68
|
error__must_be(not_less_than_zero, Term) :- !,
|
|
64
69
|
must_be(integer, Term),
|
|
65
70
|
( Term >= 0 -> true ; domain_error(not_less_than_zero, Term) ).
|
|
66
71
|
error__must_be(Type, Term) :-
|
|
67
|
-
( var(Term) -> instantiation_error
|
|
68
|
-
; type_error(Type, Term)
|
|
72
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
73
|
+
; error__must_be_throw(type_error(Type, Term))
|
|
69
74
|
).
|
|
70
75
|
|
|
71
76
|
error__proper_list([]) :- !.
|
|
72
77
|
error__proper_list([_|Tail]) :- !, error__proper_list(Tail).
|
|
73
78
|
error__proper_list(Term) :-
|
|
74
|
-
( var(Term) -> instantiation_error
|
|
75
|
-
; type_error(list, Term)
|
|
79
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
80
|
+
; error__must_be_throw(type_error(list, Term))
|
|
76
81
|
).
|
|
77
82
|
|
|
78
83
|
error__proper_list_of([], _) :- !.
|
|
@@ -80,7 +85,7 @@ error__proper_list_of([Head|Tail], Type) :- !,
|
|
|
80
85
|
must_be(Type, Head),
|
|
81
86
|
error__proper_list_of(Tail, Type).
|
|
82
87
|
error__proper_list_of(Term, _) :-
|
|
83
|
-
( var(Term) -> instantiation_error
|
|
88
|
+
( var(Term) -> error__must_be_throw(instantiation_error)
|
|
84
89
|
; type_error(list, Term)
|
|
85
90
|
).
|
|
86
91
|
|
package/src/lib/random.pl
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
:- module(random, [maybe/0, maybe/1, maybe/2, random/1, random/3, random_integer/3, set_random/1]).
|
|
11
11
|
|
|
12
12
|
:- use_module(library(iso_ext), [bb_get/2, bb_put/2]).
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
|
|
15
15
|
maybe :-
|
|
16
16
|
random_integer(0, 2, 0).
|
|
@@ -31,7 +31,7 @@ random(Value) :-
|
|
|
31
31
|
% Context declared once per predicate instead of at each raise site, so the
|
|
32
32
|
% raise sites throw with [] and contexts stay proper composable lists.
|
|
33
33
|
random_integer(Lower, Upper, R) :-
|
|
34
|
-
|
|
34
|
+
random__check_integer_range(Lower, Upper),
|
|
35
35
|
Lower < Upper,
|
|
36
36
|
random__current_seed(Seed0),
|
|
37
37
|
random(Seed0, _, Seed),
|
|
@@ -39,28 +39,31 @@ random_integer(Lower, Upper, R) :-
|
|
|
39
39
|
R is Lower + Seed mod (Upper - Lower).
|
|
40
40
|
|
|
41
41
|
set_random(Seed) :-
|
|
42
|
-
|
|
42
|
+
random__set_seed(Seed).
|
|
43
|
+
|
|
44
|
+
random__throw(Formal, Predicate) :-
|
|
45
|
+
throw(error(Formal, [predicate-Predicate])).
|
|
43
46
|
|
|
44
47
|
random__check_integer_range(Lower, Upper) :-
|
|
45
|
-
( var(Lower) -> instantiation_error
|
|
46
|
-
; var(Upper) -> instantiation_error
|
|
48
|
+
( var(Lower) -> random__throw(instantiation_error, random_integer/3)
|
|
49
|
+
; var(Upper) -> random__throw(instantiation_error, random_integer/3)
|
|
47
50
|
; integer(Lower) -> true
|
|
48
|
-
; type_error(integer, Lower)
|
|
51
|
+
; random__throw(type_error(integer, Lower), random_integer/3)
|
|
49
52
|
),
|
|
50
53
|
( integer(Upper) -> true
|
|
51
|
-
; type_error(integer, Upper)
|
|
54
|
+
; random__throw(type_error(integer, Upper), random_integer/3)
|
|
52
55
|
).
|
|
53
56
|
|
|
54
57
|
random__set_seed(Seed) :-
|
|
55
|
-
( var(Seed) -> instantiation_error
|
|
58
|
+
( var(Seed) -> random__throw(instantiation_error, set_random/1)
|
|
56
59
|
; Seed = seed(S) ->
|
|
57
|
-
( var(S) -> instantiation_error
|
|
60
|
+
( var(S) -> random__throw(instantiation_error, set_random/1)
|
|
58
61
|
; integer(S) ->
|
|
59
62
|
random__random_normalize_seed(S, Normalized),
|
|
60
63
|
bb_put('$random_seed', Normalized)
|
|
61
|
-
; type_error(integer, S)
|
|
64
|
+
; random__throw(type_error(integer, S), set_random/1)
|
|
62
65
|
)
|
|
63
|
-
; type_error(random_state, Seed)
|
|
66
|
+
; random__throw(type_error(random_state, Seed), set_random/1)
|
|
64
67
|
).
|
|
65
68
|
|
|
66
69
|
random__current_seed(Seed) :- bb_get('$random_seed', Seed), !.
|
|
@@ -4510,6 +4510,24 @@ answer(Result) :- countdown(2048, Result), Result = 2048.
|
|
|
4510
4510
|
assertIncludes(repl.stdout, 'throw(foo)', 'non-error ball keeps the wrapper');
|
|
4511
4511
|
},
|
|
4512
4512
|
},
|
|
4513
|
+
{
|
|
4514
|
+
// must_be/2 is called constantly by library code, so its context must be
|
|
4515
|
+
// supplied without a catch/3 frame: wrapping a Prolog goal in catch/3
|
|
4516
|
+
// costs a child Solver per call and made the suite ~35% slower.
|
|
4517
|
+
name: 'must_be/2 does not pay for a catch frame on success',
|
|
4518
|
+
run: () => {
|
|
4519
|
+
const input = '%% goal: answer(X)\n' +
|
|
4520
|
+
'loop(0) :- !.\nloop(N) :- must_be(integer, N), M is N - 1, loop(M).\n' +
|
|
4521
|
+
'answer(ok) :- loop(20000).\n';
|
|
4522
|
+
const started = Date.now();
|
|
4523
|
+
const result = runCli(['-'], { input });
|
|
4524
|
+
const elapsed = Date.now() - started;
|
|
4525
|
+
assertEqual(result.status, 0, `exit status; stderr=${result.stderr}`);
|
|
4526
|
+
assertIncludes(result.stdout, 'answer(ok)', 'loop completes');
|
|
4527
|
+
// Generous bound: the catch/3 wrapper made this roughly 2x slower.
|
|
4528
|
+
if (elapsed >= 20000) throw new Error(`20k must_be/2 calls took ${elapsed}ms`);
|
|
4529
|
+
},
|
|
4530
|
+
},
|
|
4513
4531
|
{
|
|
4514
4532
|
// Issue #99: the context element must be a pair, as in Scryer and
|
|
4515
4533
|
// Trealla, and predicate contexts use the predicate-F/A convention.
|