eyeprolog 1.5.80 → 1.5.81
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/explain.js +14 -21
- package/src/iso.js +47 -134
- package/src/parser.js +63 -46
- package/src/program.js +54 -101
- package/src/quads.js +50 -27
- package/src/solver.js +14 -298
- package/src/term.js +24 -30
- package/test/conformance/NEUMERKEL-LATEST.md +3 -3
- package/test/neumerkel.mjs +18 -2
- package/test/regression/cases-regression.mjs +22 -8
package/package.json
CHANGED
package/src/explain.js
CHANGED
|
@@ -69,7 +69,7 @@ function* proveGoalAll(program, goal, env, depth, maxDepth, registry, active, de
|
|
|
69
69
|
env: proofEnv,
|
|
70
70
|
node: {
|
|
71
71
|
goal: resolveForProof(goal, proofEnv),
|
|
72
|
-
method:
|
|
72
|
+
method: goalMethod('builtin', goal),
|
|
73
73
|
sourceHead: resolveForProof(goal, proofEnv),
|
|
74
74
|
sourceBody: [],
|
|
75
75
|
bindings: [],
|
|
@@ -97,7 +97,7 @@ function* proveGoalAll(program, goal, env, depth, maxDepth, registry, active, de
|
|
|
97
97
|
env: proofEnv,
|
|
98
98
|
node: {
|
|
99
99
|
goal: resolveForProof(goal, proofEnv),
|
|
100
|
-
method:
|
|
100
|
+
method: goalMethod('library', goal),
|
|
101
101
|
sourceHead: resolveForProof(goal, proofEnv),
|
|
102
102
|
sourceBody: [],
|
|
103
103
|
bindings: [],
|
|
@@ -254,17 +254,9 @@ function sourceMethod(clause, kind) {
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
function
|
|
257
|
+
function goalMethod(type, goal) {
|
|
258
258
|
return {
|
|
259
|
-
type
|
|
260
|
-
name: goal.type === COMPOUND ? goal.name : 'goal',
|
|
261
|
-
arity: goal.type === COMPOUND ? goal.arity : 0,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function libraryMethod(goal) {
|
|
266
|
-
return {
|
|
267
|
-
type: 'library',
|
|
259
|
+
type,
|
|
268
260
|
name: goal.type === COMPOUND ? goal.name : 'goal',
|
|
269
261
|
arity: goal.type === COMPOUND ? goal.arity : 0,
|
|
270
262
|
};
|
|
@@ -380,15 +372,15 @@ function certificateText(term) {
|
|
|
380
372
|
throw new Error('expected certificate text');
|
|
381
373
|
}
|
|
382
374
|
|
|
383
|
-
function
|
|
384
|
-
|
|
385
|
-
return node.children.some(containsLibraryBoundary);
|
|
375
|
+
function proofTreeContains(node, predicate) {
|
|
376
|
+
return predicate(node) || node.children.some((child) => proofTreeContains(child, predicate));
|
|
386
377
|
}
|
|
387
378
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
379
|
+
const containsLibraryBoundary = (node) => proofTreeContains(node, (n) => n.method?.type === 'library');
|
|
380
|
+
|
|
381
|
+
const containsExpandedLibrarySource = (node) => proofTreeContains(
|
|
382
|
+
node, (n) => n.method?.type === 'source' && String(n.method.filename ?? '').startsWith('src/lib/'),
|
|
383
|
+
);
|
|
392
384
|
|
|
393
385
|
export function verifyProof(program, input, options = {}) {
|
|
394
386
|
const certificate = input?.certificate ?? input;
|
|
@@ -557,8 +549,9 @@ function verifyBindings(bindings, variables, env, program) {
|
|
|
557
549
|
|
|
558
550
|
function renderMethodTerm(method) {
|
|
559
551
|
if (method && method.type === 'source') return `${method.kind}(${quoteString(method.filename)}, clause(${method.clause}))`;
|
|
560
|
-
if (method && method.type === 'builtin'
|
|
561
|
-
|
|
552
|
+
if (method && (method.type === 'builtin' || method.type === 'library')) {
|
|
553
|
+
return `${method.type}(${quoteAtomText(method.name)}, ${method.arity})`;
|
|
554
|
+
}
|
|
562
555
|
return String(method);
|
|
563
556
|
}
|
|
564
557
|
|
package/src/iso.js
CHANGED
|
@@ -680,10 +680,7 @@ function validPredicateIndicator(term) {
|
|
|
680
680
|
(term.args[1].type === NUMBER && isDecimalInteger(term.args[1].name) && BigInt(term.args[1].name) >= 0n));
|
|
681
681
|
}
|
|
682
682
|
|
|
683
|
-
|
|
684
|
-
const state = { pending: false };
|
|
685
|
-
return withPendingState(currentPredicateSolutions(context, state), state);
|
|
686
|
-
}
|
|
683
|
+
const currentPredicateBuiltin = pendingBuiltin(currentPredicateSolutions);
|
|
687
684
|
|
|
688
685
|
function* currentPredicateSolutions({ solver, goal, env }, state) {
|
|
689
686
|
const indicator = copyResolved(goal.args[0], env);
|
|
@@ -719,10 +716,7 @@ function clauseBodyTerm(body) {
|
|
|
719
716
|
return result;
|
|
720
717
|
}
|
|
721
718
|
|
|
722
|
-
|
|
723
|
-
const state = { pending: false };
|
|
724
|
-
return withPendingState(clauseSolutions(context, state), state);
|
|
725
|
-
}
|
|
719
|
+
const clauseBuiltin = pendingBuiltin(clauseSolutions);
|
|
726
720
|
|
|
727
721
|
function* clauseSolutions({ solver, goal, env }, state) {
|
|
728
722
|
const head = deref(goal.args[0], env);
|
|
@@ -851,12 +845,7 @@ function assertBuiltin(atStart) {
|
|
|
851
845
|
};
|
|
852
846
|
}
|
|
853
847
|
|
|
854
|
-
|
|
855
|
-
const state = { pending: true };
|
|
856
|
-
const iterator = retractSolutions(context, state);
|
|
857
|
-
iterator.hasPendingAlternatives = () => state.pending;
|
|
858
|
-
return iterator;
|
|
859
|
-
}
|
|
848
|
+
const retractBuiltin = pendingBuiltin(retractSolutions, true);
|
|
860
849
|
|
|
861
850
|
function* retractSolutions({ solver, goal, env }, state) {
|
|
862
851
|
const parts = clauseParts(goal.args[0], env);
|
|
@@ -941,10 +930,7 @@ function* abolishBuiltin({ solver, goal, env }) {
|
|
|
941
930
|
yield env;
|
|
942
931
|
}
|
|
943
932
|
|
|
944
|
-
|
|
945
|
-
const state = { pending: false };
|
|
946
|
-
return withPendingState(currentPrologFlagSolutions(context, state), state);
|
|
947
|
-
}
|
|
933
|
+
const currentPrologFlagBuiltin = pendingBuiltin(currentPrologFlagSolutions);
|
|
948
934
|
|
|
949
935
|
function* currentPrologFlagSolutions({ solver, goal, env }, state) {
|
|
950
936
|
const flag = deref(goal.args[0], env);
|
|
@@ -1058,10 +1044,7 @@ function* opBuiltin({ solver, goal, env }) {
|
|
|
1058
1044
|
yield env;
|
|
1059
1045
|
}
|
|
1060
1046
|
|
|
1061
|
-
|
|
1062
|
-
const state = { pending: false };
|
|
1063
|
-
return withPendingState(currentOpSolutions(context, state), state);
|
|
1064
|
-
}
|
|
1047
|
+
const currentOpBuiltin = pendingBuiltin(currentOpSolutions);
|
|
1065
1048
|
|
|
1066
1049
|
function* currentOpSolutions({ solver, goal, env }, state) {
|
|
1067
1050
|
const priority = deref(goal.args[0], env);
|
|
@@ -1124,10 +1107,7 @@ function* charConversionBuiltin({ solver, goal, env }) {
|
|
|
1124
1107
|
else solver.charConversions.set(input.name, output.name);
|
|
1125
1108
|
yield env;
|
|
1126
1109
|
}
|
|
1127
|
-
|
|
1128
|
-
const state = { pending: false };
|
|
1129
|
-
return withPendingState(currentCharConversionSolutions(context, state), state);
|
|
1130
|
-
}
|
|
1110
|
+
const currentCharConversionBuiltin = pendingBuiltin(currentCharConversionSolutions);
|
|
1131
1111
|
|
|
1132
1112
|
function* currentCharConversionSolutions({ solver, goal, env }, state) {
|
|
1133
1113
|
const input = conversionCharacter(goal.args[0], env, true, solver);
|
|
@@ -1355,28 +1335,23 @@ function* closeBuiltin({ solver, goal, env }) {
|
|
|
1355
1335
|
yield env;
|
|
1356
1336
|
}
|
|
1357
1337
|
|
|
1358
|
-
function
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
if (
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
if (value.type !== VAR) {
|
|
1373
|
-
const id = streamTermReference(goal.args[0], env);
|
|
1374
|
-
if (id === solver.io.currentOutput) yield env;
|
|
1375
|
-
return;
|
|
1376
|
-
}
|
|
1377
|
-
const next = env.clone();
|
|
1378
|
-
if (unify(goal.args[0], streamHandle(solver.io.currentOutput), next)) yield next;
|
|
1338
|
+
function currentStreamBuiltin(which) {
|
|
1339
|
+
// A closed handle is still a stream-term, but cannot be current (#107).
|
|
1340
|
+
// Validate its shape, then test identity rather than requiring an open stream.
|
|
1341
|
+
return function* ({ solver, goal, env }) {
|
|
1342
|
+
const value = deref(goal.args[0], env);
|
|
1343
|
+
const current = solver.io[which];
|
|
1344
|
+
if (value.type !== VAR) {
|
|
1345
|
+
const id = streamTermReference(goal.args[0], env);
|
|
1346
|
+
if (id === current) yield env;
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
const next = env.clone();
|
|
1350
|
+
if (unify(goal.args[0], streamHandle(current), next)) yield next;
|
|
1351
|
+
};
|
|
1379
1352
|
}
|
|
1353
|
+
const currentInputBuiltin = currentStreamBuiltin('currentInput');
|
|
1354
|
+
const currentOutputBuiltin = currentStreamBuiltin('currentOutput');
|
|
1380
1355
|
|
|
1381
1356
|
function setCurrentStreamBuiltin(mode) {
|
|
1382
1357
|
return function* ({ solver, goal, env }) {
|
|
@@ -1456,10 +1431,7 @@ function isStreamPropertyPattern(value) {
|
|
|
1456
1431
|
].includes(value.name);
|
|
1457
1432
|
}
|
|
1458
1433
|
|
|
1459
|
-
|
|
1460
|
-
const state = { pending: false };
|
|
1461
|
-
return withPendingState(streamPropertySolutions(context, state), state);
|
|
1462
|
-
}
|
|
1434
|
+
const streamPropertyBuiltin = pendingBuiltin(streamPropertySolutions);
|
|
1463
1435
|
|
|
1464
1436
|
function* streamPropertySolutions({ solver, goal, env }, state) {
|
|
1465
1437
|
const reference = deref(goal.args[0], env);
|
|
@@ -2068,14 +2040,6 @@ function* writeTermBuiltin({ solver, goal, env }) {
|
|
|
2068
2040
|
yield env;
|
|
2069
2041
|
}
|
|
2070
2042
|
|
|
2071
|
-
function resolvedOrVariable(term, env, expected) {
|
|
2072
|
-
const value = deref(term, env);
|
|
2073
|
-
if (value.type !== VAR && value.type !== expected) {
|
|
2074
|
-
throw new PrologError(`type_error(${expected === ATOM ? 'atom' : 'number'})`, value);
|
|
2075
|
-
}
|
|
2076
|
-
return value;
|
|
2077
|
-
}
|
|
2078
|
-
|
|
2079
2043
|
function characters(text) {
|
|
2080
2044
|
return Array.from(text);
|
|
2081
2045
|
}
|
|
@@ -2095,10 +2059,7 @@ function* atomLengthBuiltin({ goal, env }) {
|
|
|
2095
2059
|
if (unify(goal.args[1], numberTerm(characters(value.name).length), next)) yield next;
|
|
2096
2060
|
}
|
|
2097
2061
|
|
|
2098
|
-
|
|
2099
|
-
const state = { pending: false };
|
|
2100
|
-
return withPendingState(atomConcatSolutions(context, state), state);
|
|
2101
|
-
}
|
|
2062
|
+
const atomConcatBuiltin = pendingBuiltin(atomConcatSolutions);
|
|
2102
2063
|
|
|
2103
2064
|
function* atomConcatSolutions({ goal, env }, state) {
|
|
2104
2065
|
const first = deref(goal.args[0], env);
|
|
@@ -2142,10 +2103,7 @@ function optionalInteger(term, env) {
|
|
|
2142
2103
|
return BigInt(value.name);
|
|
2143
2104
|
}
|
|
2144
2105
|
|
|
2145
|
-
|
|
2146
|
-
const state = { pending: false };
|
|
2147
|
-
return withPendingState(subAtomSolutions(context, state), state);
|
|
2148
|
-
}
|
|
2106
|
+
const subAtomBuiltin = pendingBuiltin(subAtomSolutions);
|
|
2149
2107
|
|
|
2150
2108
|
function* subAtomSolutions({ goal, env }, state) {
|
|
2151
2109
|
const source = deref(goal.args[0], env);
|
|
@@ -2625,10 +2583,7 @@ function sortedUnique(items) {
|
|
|
2625
2583
|
}
|
|
2626
2584
|
|
|
2627
2585
|
function allSolutionsBuiltin(asSet) {
|
|
2628
|
-
return
|
|
2629
|
-
const state = { pending: false };
|
|
2630
|
-
return withPendingState(allSolutionsGroups(context, asSet, state), state);
|
|
2631
|
-
};
|
|
2586
|
+
return pendingBuiltin((context, state) => allSolutionsGroups(context, asSet, state));
|
|
2632
2587
|
}
|
|
2633
2588
|
|
|
2634
2589
|
function* allSolutionsGroups({ solver, goal, env }, asSet, state) {
|
|
@@ -2697,6 +2652,15 @@ function withPendingState(iterator, state) {
|
|
|
2697
2652
|
iterator.hasPendingAlternatives = () => state.pending;
|
|
2698
2653
|
return iterator;
|
|
2699
2654
|
}
|
|
2655
|
+
|
|
2656
|
+
// Most builtins share this shape: create a { pending } cell, run a solutions
|
|
2657
|
+
// generator against it, and expose that cell through hasPendingAlternatives.
|
|
2658
|
+
function pendingBuiltin(solutionsFn, initialPending = false) {
|
|
2659
|
+
return (context) => {
|
|
2660
|
+
const state = { pending: initialPending };
|
|
2661
|
+
return withPendingState(solutionsFn(context, state), state);
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2700
2664
|
function validateControlCallable(term, culprit, env) {
|
|
2701
2665
|
// Only control constructs need their nested goals validated at meta-call
|
|
2702
2666
|
// entry. Walk them iteratively and dereference each nested goal lazily so
|
|
@@ -2770,9 +2734,9 @@ function expandCallGoal({ goal, env }) {
|
|
|
2770
2734
|
if (converted.module == null) converted.module = module;
|
|
2771
2735
|
return converted;
|
|
2772
2736
|
}
|
|
2773
|
-
function*
|
|
2737
|
+
function* invokeExpandedGoal(context, expand) {
|
|
2774
2738
|
const { solver, env } = context;
|
|
2775
|
-
const invoked =
|
|
2739
|
+
const invoked = expand(context);
|
|
2776
2740
|
const child = solver.cloneForInnerGoal();
|
|
2777
2741
|
try {
|
|
2778
2742
|
yield* child.solve([invoked], env, 0);
|
|
@@ -2780,6 +2744,9 @@ function* callBuiltin(context) {
|
|
|
2780
2744
|
solver.absorbStatsFrom(child);
|
|
2781
2745
|
}
|
|
2782
2746
|
}
|
|
2747
|
+
function* callBuiltin(context) {
|
|
2748
|
+
yield* invokeExpandedGoal(context, expandCallGoal);
|
|
2749
|
+
}
|
|
2783
2750
|
function expandCallClosureGoal({ goal, env }) {
|
|
2784
2751
|
const closure = callable(goal.args[0], env);
|
|
2785
2752
|
const existing = closure.type === COMPOUND ? closure.args : [];
|
|
@@ -2792,14 +2759,7 @@ function expandCallClosureGoal({ goal, env }) {
|
|
|
2792
2759
|
return invoked;
|
|
2793
2760
|
}
|
|
2794
2761
|
function* callClosureBuiltin(context) {
|
|
2795
|
-
|
|
2796
|
-
const invoked = expandCallClosureGoal(context);
|
|
2797
|
-
const child = solver.cloneForInnerGoal();
|
|
2798
|
-
try {
|
|
2799
|
-
yield* child.solve([invoked], env, 0);
|
|
2800
|
-
} finally {
|
|
2801
|
-
solver.absorbStatsFrom(child);
|
|
2802
|
-
}
|
|
2762
|
+
yield* invokeExpandedGoal(context, expandCallClosureGoal);
|
|
2803
2763
|
}
|
|
2804
2764
|
|
|
2805
2765
|
export function* countAllBuiltin({ solver, goal, env }) {
|
|
@@ -2846,10 +2806,7 @@ function writeElapsedTime(solver, startedAt, inferences) {
|
|
|
2846
2806
|
);
|
|
2847
2807
|
}
|
|
2848
2808
|
|
|
2849
|
-
export
|
|
2850
|
-
const state = { pending: true };
|
|
2851
|
-
return withPendingState(timeSolutions(context, state), state);
|
|
2852
|
-
}
|
|
2809
|
+
export const timeBuiltin = pendingBuiltin(timeSolutions, true);
|
|
2853
2810
|
|
|
2854
2811
|
function* timeSolutions({ solver, goal, env }, state) {
|
|
2855
2812
|
const invoked = callable(goal.args[0], env);
|
|
@@ -2877,10 +2834,7 @@ function* timeSolutions({ solver, goal, env }, state) {
|
|
|
2877
2834
|
}
|
|
2878
2835
|
}
|
|
2879
2836
|
|
|
2880
|
-
export
|
|
2881
|
-
const state = { pending: true };
|
|
2882
|
-
return withPendingState(callNthSolutions(context, state), state);
|
|
2883
|
-
}
|
|
2837
|
+
export const callNthBuiltin = pendingBuiltin(callNthSolutions, true);
|
|
2884
2838
|
|
|
2885
2839
|
function* callNthSolutions({ solver, goal, env }, state) {
|
|
2886
2840
|
const requestedTerm = deref(goal.args[1], env);
|
|
@@ -3005,37 +2959,7 @@ export function callResidueVarsBuiltin({ solver, goal, env }) {
|
|
|
3005
2959
|
return iterator;
|
|
3006
2960
|
}
|
|
3007
2961
|
|
|
3008
|
-
|
|
3009
|
-
const state = { pending: true };
|
|
3010
|
-
return withPendingState(freezeSolutions(context, state), state);
|
|
3011
|
-
}
|
|
3012
|
-
|
|
3013
|
-
function* freezeSolutions({ solver, goal, env }, state) {
|
|
3014
|
-
const watched = deref(goal.args[0], env);
|
|
3015
|
-
if (watched.type !== VAR) {
|
|
3016
|
-
const child = solver.cloneForInnerGoal();
|
|
3017
|
-
try {
|
|
3018
|
-
for (const answerEnv of child.solve([callable(goal.args[1], env)], env, 0)) {
|
|
3019
|
-
state.pending = child.hasPendingAlternatives();
|
|
3020
|
-
yield answerEnv;
|
|
3021
|
-
if (!state.pending) return;
|
|
3022
|
-
}
|
|
3023
|
-
state.pending = false;
|
|
3024
|
-
} finally {
|
|
3025
|
-
solver.absorbStatsFrom(child);
|
|
3026
|
-
}
|
|
3027
|
-
return;
|
|
3028
|
-
}
|
|
3029
|
-
const next = env.clone();
|
|
3030
|
-
next.delay(watched.name, goal.args[1], goal.module ?? 'user');
|
|
3031
|
-
state.pending = false;
|
|
3032
|
-
yield next;
|
|
3033
|
-
}
|
|
3034
|
-
|
|
3035
|
-
function phraseBuiltin(context) {
|
|
3036
|
-
const state = { pending: true };
|
|
3037
|
-
return withPendingState(phraseSolutions(context, state), state);
|
|
3038
|
-
}
|
|
2962
|
+
const phraseBuiltin = pendingBuiltin(phraseSolutions, true);
|
|
3039
2963
|
|
|
3040
2964
|
function* phraseSolutions({ solver, goal, env }, state) {
|
|
3041
2965
|
const grammarBody0 = deref(goal.args[0], env);
|
|
@@ -3161,10 +3085,7 @@ function prologErrorBall(error) {
|
|
|
3161
3085
|
if (hasDefaultGroundErrorShape(error) || termIsGround(term)) return term;
|
|
3162
3086
|
return freshCopy(term, new Env());
|
|
3163
3087
|
}
|
|
3164
|
-
|
|
3165
|
-
const state = { pending: true };
|
|
3166
|
-
return withPendingState(catchSolutions(context, state), state);
|
|
3167
|
-
}
|
|
3088
|
+
const catchBuiltin = pendingBuiltin(catchSolutions, true);
|
|
3168
3089
|
|
|
3169
3090
|
function* catchSolutions({ solver, goal, env }, state) {
|
|
3170
3091
|
let child = null;
|
|
@@ -3293,12 +3214,7 @@ function* solveControlBranch(solver, goal, env, observePending = null) {
|
|
|
3293
3214
|
yield answer;
|
|
3294
3215
|
}
|
|
3295
3216
|
}
|
|
3296
|
-
|
|
3297
|
-
const state = { pending: true };
|
|
3298
|
-
const iterator = disjunctionSolutions(context, state);
|
|
3299
|
-
iterator.hasPendingAlternatives = () => state.pending;
|
|
3300
|
-
return iterator;
|
|
3301
|
-
}
|
|
3217
|
+
const disjunctionBuiltin = pendingBuiltin(disjunctionSolutions, true);
|
|
3302
3218
|
function* disjunctionSolutions({ solver, goal, env }, state) {
|
|
3303
3219
|
const left = deref(goal.args[0], env);
|
|
3304
3220
|
if (left.type === COMPOUND && left.name === '->' && left.arity === 2) {
|
|
@@ -3333,10 +3249,7 @@ function* disjunctionSolutions({ solver, goal, env }, state) {
|
|
|
3333
3249
|
(pending) => { state.pending = pending; });
|
|
3334
3250
|
state.pending = false;
|
|
3335
3251
|
}
|
|
3336
|
-
|
|
3337
|
-
const state = { pending: true };
|
|
3338
|
-
return withPendingState(ifThenSolutions(context, state), state);
|
|
3339
|
-
}
|
|
3252
|
+
const ifThenBuiltin = pendingBuiltin(ifThenSolutions, true);
|
|
3340
3253
|
|
|
3341
3254
|
function* ifThenSolutions({ solver, goal, env }, state) {
|
|
3342
3255
|
for (const conditionEnv of solver.cloneForInnerGoal(1).solve([callable(goal.args[0], env)], env.clone(), 0)) {
|