eyeprolog 1.2.42 → 1.2.43
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/standard-library.js +39 -2
- package/test/run-regression.mjs +35 -1
- package/the-art-of-eyeprolog.md +15 -4
package/package.json
CHANGED
package/src/standard-library.js
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
// The sources are registered here so library(Name) works in Node and browsers;
|
|
3
3
|
// unlike the former autoloader, no clauses are added unless use_module/1 or
|
|
4
4
|
// use_module/2 requests their module.
|
|
5
|
-
import { createDefaultRegistry, eyePrologLibraryBuiltins } from './iso.js';
|
|
5
|
+
import { PrologError, createDefaultRegistry, eyePrologLibraryBuiltins } from './iso.js';
|
|
6
6
|
import { clpzBuiltins } from './clpz.js';
|
|
7
|
-
import { fs, isNode } from './platform.js';
|
|
7
|
+
import { fs, isNode, memoryStatistics } from './platform.js';
|
|
8
|
+
import { ATOM, VAR, atom, deref, numberTerm, unify } from './term.js';
|
|
8
9
|
|
|
9
10
|
const moduleFiles = Object.freeze({
|
|
10
11
|
aggregate: 'aggregate.pl',
|
|
@@ -73,8 +74,44 @@ export const eyePrologLibraryIndicators = Object.freeze([
|
|
|
73
74
|
...eyePrologNativeLibraryIndicators,
|
|
74
75
|
]);
|
|
75
76
|
|
|
77
|
+
function runtimeStatistics(solver) {
|
|
78
|
+
return { ...solver.stats, ...memoryStatistics() };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function* statisticsBuiltin({ solver, env }) {
|
|
82
|
+
const stream = solver.io.resolve(solver.io.currentOutput);
|
|
83
|
+
if (stream?.type !== 'text') throw new PrologError('permission_error(output, binary_stream)');
|
|
84
|
+
solver.io.writeUnit(stream, 'eyeprolog stats:\n');
|
|
85
|
+
for (const [key, value] of Object.entries(runtimeStatistics(solver))) {
|
|
86
|
+
solver.io.writeUnit(stream, ` ${key}: ${value}\n`);
|
|
87
|
+
}
|
|
88
|
+
yield env;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function* statisticsValueBuiltin({ solver, goal, env }) {
|
|
92
|
+
const snapshot = runtimeStatistics(solver);
|
|
93
|
+
const key = deref(goal.args[0], env);
|
|
94
|
+
const entries = key.type === VAR
|
|
95
|
+
? Object.entries(snapshot)
|
|
96
|
+
: key.type === ATOM && Object.hasOwn(snapshot, key.name)
|
|
97
|
+
? [[key.name, snapshot[key.name]]]
|
|
98
|
+
: null;
|
|
99
|
+
|
|
100
|
+
if (entries == null) {
|
|
101
|
+
if (key.type !== ATOM) throw new PrologError('type_error(atom)', key);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const [name, value] of entries) {
|
|
106
|
+
const next = env.clone();
|
|
107
|
+
if (unify(goal.args[0], atom(name), next) && unify(goal.args[1], numberTerm(value), next)) yield next;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
76
111
|
export function createEyePrologRegistry() {
|
|
77
112
|
const registry = createDefaultRegistry();
|
|
113
|
+
registry.add('statistics', 0, statisticsBuiltin, { deterministic: true });
|
|
114
|
+
registry.add('statistics', 2, statisticsValueBuiltin);
|
|
78
115
|
eyePrologLibraryBuiltins.register(registry);
|
|
79
116
|
clpzBuiltins.register(registry);
|
|
80
117
|
registry.eyePrologLibrary = true;
|
package/test/run-regression.mjs
CHANGED
|
@@ -1975,6 +1975,36 @@ c4 ?- call((!;1)).
|
|
|
1975
1975
|
assertIncludes(result.stderr, ' solve_goals_calls:', 'stderr');
|
|
1976
1976
|
},
|
|
1977
1977
|
},
|
|
1978
|
+
{
|
|
1979
|
+
name: 'statistics/0 prints snapshots during execution',
|
|
1980
|
+
run: () => {
|
|
1981
|
+
const input = '%% goal: live\nlive :- statistics, statistics.\n';
|
|
1982
|
+
const result = runCli(['-'], { input });
|
|
1983
|
+
assertEqual(result.status, 0, 'exit status');
|
|
1984
|
+
assertEqual((result.stdout.match(/eyeprolog stats:/g) ?? []).length, 2, 'in-run snapshot count');
|
|
1985
|
+
assertIncludes(result.stdout, ' memory_guard_used_bytes:', 'stdout');
|
|
1986
|
+
assertIncludes(result.stdout, 'live.\n', 'stdout');
|
|
1987
|
+
assertEqual(result.stderr, '', 'stderr');
|
|
1988
|
+
},
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
name: 'statistics/2 exposes current counters and memory values',
|
|
1992
|
+
run: () => {
|
|
1993
|
+
const input = '%% goal: live(Used)\nlive(Used) :- statistics(memory_guard_used_bytes, Used).\n';
|
|
1994
|
+
const result = runCli(['-'], { input });
|
|
1995
|
+
assertEqual(result.status, 0, 'exit status');
|
|
1996
|
+
assertEqual(/^live\(\d+\)\.\n$/.test(result.stdout), true, 'numeric memory statistic');
|
|
1997
|
+
assertEqual(result.stderr, '', 'stderr');
|
|
1998
|
+
},
|
|
1999
|
+
},
|
|
2000
|
+
{
|
|
2001
|
+
name: 'statistics predicates are excluded from strict ISO mode',
|
|
2002
|
+
run: () => {
|
|
2003
|
+
const result = runCli(['--iso-strict', '-'], { input: '%% goal: statistics\n' });
|
|
2004
|
+
assertEqual(result.status, 1, 'exit status');
|
|
2005
|
+
assertIncludes(result.stderr, 'existence_error(procedure)', 'stderr');
|
|
2006
|
+
},
|
|
2007
|
+
},
|
|
1978
2008
|
{
|
|
1979
2009
|
name: '--warnings prints unstratified negation diagnostics without failing',
|
|
1980
2010
|
run: () => {
|
|
@@ -3205,9 +3235,13 @@ open(X) :- candidate(X), \\+ closed(X).
|
|
|
3205
3235
|
assertEqual(Boolean(registry.get('is', 2)), true, 'ISO is/2 exists');
|
|
3206
3236
|
assertEqual(Boolean(registry.get('append', 3)), false, 'append/3 is not ISO core');
|
|
3207
3237
|
assertEqual(library.eyePrologLibrary, true, 'complete registry marker');
|
|
3208
|
-
assertEqual(library.defs.size,
|
|
3238
|
+
assertEqual(library.defs.size, 155, 'EyeProlog registry contains ISO definitions, observability extensions, and private library adapters');
|
|
3209
3239
|
assertEqual(Boolean(registry.get('phrase', 2)), true, 'Part 3 phrase/2 exists');
|
|
3210
3240
|
assertEqual(Boolean(registry.get('phrase', 3)), true, 'Part 3 phrase/3 exists');
|
|
3241
|
+
assertEqual(registry.get('statistics', 0), null, 'statistics/0 is absent from the ISO registry');
|
|
3242
|
+
assertEqual(registry.get('statistics', 2), null, 'statistics/2 is absent from the ISO registry');
|
|
3243
|
+
assertEqual(Boolean(library.get('statistics', 0)), true, 'statistics/0 is an EyeProlog observability extension');
|
|
3244
|
+
assertEqual(Boolean(library.get('statistics', 2)), true, 'statistics/2 is an EyeProlog observability extension');
|
|
3211
3245
|
assertEqual(registeredNativeEyePrologLibraryNames().length, 40, 'public native EyeProlog builtin count');
|
|
3212
3246
|
assertEqual(eyePrologPortableLibraryIndicators.length, 59, 'portable Prolog library count');
|
|
3213
3247
|
assertEqual(eyePrologNativeLibraryIndicators.length, 40, 'native host library count');
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -4635,9 +4635,20 @@ may indicate a generator that should be constrained. Many table hits may show
|
|
|
4635
4635
|
effective reuse; many distinct table entries may reveal an argument that
|
|
4636
4636
|
prevents calls from sharing. On the Node CLI it also reports current heap use,
|
|
4637
4637
|
non-young/old-generation use, the amount currently compared with the memory
|
|
4638
|
-
guard, resident-set size, and the soft and hard memory ceilings in bytes. These
|
|
4639
|
-
|
|
4640
|
-
|
|
4638
|
+
guard, resident-set size, and the soft and hard memory ceilings in bytes. These
|
|
4639
|
+
memory figures are printed even when execution ends by raising a Prolog error.
|
|
4640
|
+
|
|
4641
|
+
`--stats` is an end-of-run summary. For a deliberately non-terminating or very
|
|
4642
|
+
long computation, call the EyeProlog extension `statistics/0` at the points
|
|
4643
|
+
where a live snapshot is useful. For example, a long-running loop can include
|
|
4644
|
+
`statistics` as one of its goals, as in `loop :- work, statistics, loop.`
|
|
4645
|
+
|
|
4646
|
+
`statistics/0` writes the current solver counters and memory figures
|
|
4647
|
+
immediately to the current output stream. `statistics/2` makes an individual
|
|
4648
|
+
value available to the program, for example
|
|
4649
|
+
`statistics(memory_guard_used_bytes, Used)`. With an unbound first argument it
|
|
4650
|
+
enumerates the available statistic keys and values. These predicates are
|
|
4651
|
+
EyeProlog observability extensions and are not available under `--iso-strict`.
|
|
4641
4652
|
|
|
4642
4653
|
Compare statistics only between runs with the same query, data, and observable
|
|
4643
4654
|
answer contract. A faster program that silently loses answers is not an
|
|
@@ -6410,7 +6421,7 @@ make the observed question explicit.
|
|
|
6410
6421
|
| `-p`, `--proof` | Print `why/2` explanations |
|
|
6411
6422
|
| `-q`, `--quads` | Run embedded quad tests and fail if any do not hold |
|
|
6412
6423
|
| `--iso-strict` | Restrict parsing and execution to ISO/IEC 13211-1:1995 + Corrigenda 1–3; reject EyeProlog language extensions and disable automatic tabling |
|
|
6413
|
-
| `-s`, `--stats` | Print solver
|
|
6424
|
+
| `-s`, `--stats` | Print final solver and memory statistics to stderr after execution |
|
|
6414
6425
|
| `-v`, `--version` | Print the package version |
|
|
6415
6426
|
| `-w`, `--warnings` | Print non-fatal portability warnings |
|
|
6416
6427
|
| `-g`, `--goal Goal` | Solve a callable goal; may be repeated; overrides `%% goal:` comments |
|