eyeprolog 1.5.28 → 1.5.29
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/iso.js +1 -1
- package/src/solver.js +78 -40
- package/src/term.js +246 -0
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -860,7 +860,7 @@ function* retractSolutions({ solver, goal, env }, state) {
|
|
|
860
860
|
if (!unify(parts.head, copied.args[0], next)) continue;
|
|
861
861
|
if (parts.rule && !unify(parts.body, copied.args[1], next)) continue;
|
|
862
862
|
if (!parts.rule && !(copied.args[1].type === ATOM && copied.args[1].name === 'true')) continue;
|
|
863
|
-
matches.push({ clause, next });
|
|
863
|
+
matches.push({ clause, next: next._toPersistentEnv?.() ?? next });
|
|
864
864
|
}
|
|
865
865
|
for (let index = 0; index < matches.length; index++) {
|
|
866
866
|
const { clause, next } = matches[index];
|
package/src/solver.js
CHANGED
|
@@ -392,6 +392,8 @@ export class Solver {
|
|
|
392
392
|
|
|
393
393
|
*solve(goals, env = new Env(), depth = 0) {
|
|
394
394
|
if (!Array.isArray(goals)) goals = [goals];
|
|
395
|
+
const ownsSolverBindings = env._isSolverEnv?.() !== true;
|
|
396
|
+
if (ownsSolverBindings) env = env._asSolverEnv();
|
|
395
397
|
env.setOccursCheckHandler(this.occursCheckHandler);
|
|
396
398
|
env.setAttributeHookRunner(this.attributeHookRunner);
|
|
397
399
|
if (this.isoStrict) rejectStrictIsoStringTerms(goals, env);
|
|
@@ -437,6 +439,42 @@ export class Solver {
|
|
|
437
439
|
});
|
|
438
440
|
continue;
|
|
439
441
|
}
|
|
442
|
+
if (frame.kind === 'unifyArgsBranch') {
|
|
443
|
+
if (this.solutionsSeen >= this.solutionLimit) continue;
|
|
444
|
+
const next = frame.env.clone();
|
|
445
|
+
const sourceArgs = frame.freshNonGround && !frame.args.every((arg) => termIsGround(arg))
|
|
446
|
+
? freshTerm(compound('$branch_args', frame.args), nextFreshId()).args
|
|
447
|
+
: frame.args;
|
|
448
|
+
let ok = true;
|
|
449
|
+
for (let i = 0; i < frame.goal.arity; i++) {
|
|
450
|
+
this.stats.unify_calls++;
|
|
451
|
+
if (!unify(frame.goal.args[i], sourceArgs[i], next)) { ok = false; break; }
|
|
452
|
+
}
|
|
453
|
+
if (ok) {
|
|
454
|
+
stack.push({
|
|
455
|
+
kind: 'goals',
|
|
456
|
+
goals: frame.goals,
|
|
457
|
+
env: next,
|
|
458
|
+
depth: frame.depth,
|
|
459
|
+
active: frame.active,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (frame.kind === 'bindBranch') {
|
|
465
|
+
if (this.solutionsSeen >= this.solutionLimit) continue;
|
|
466
|
+
const next = frame.env.clone();
|
|
467
|
+
for (let i = 0; i < frame.names.length; i++) next.bind(frame.names[i], frame.values[i]);
|
|
468
|
+
if (next._variableConstraints != null && !next.validateVariableConstraints()) continue;
|
|
469
|
+
stack.push({
|
|
470
|
+
kind: 'goals',
|
|
471
|
+
goals: frame.goals,
|
|
472
|
+
env: next,
|
|
473
|
+
depth: frame.depth,
|
|
474
|
+
active: frame.active,
|
|
475
|
+
});
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
440
478
|
if (frame.kind === 'userClause') {
|
|
441
479
|
if (this.solutionsSeen >= this.solutionLimit) continue;
|
|
442
480
|
const { clause, goal: clauseGoal, rest: clauseRest, env: clauseEnv, depth: clauseDepth,
|
|
@@ -585,7 +623,7 @@ export class Solver {
|
|
|
585
623
|
this.solutionsSeen++;
|
|
586
624
|
this.stats.completed_goal_lists++;
|
|
587
625
|
this.active = active;
|
|
588
|
-
yield env;
|
|
626
|
+
yield ownsSolverBindings && env._isSolverEnv?.() === true ? env._toPersistentEnv() : env;
|
|
589
627
|
break;
|
|
590
628
|
}
|
|
591
629
|
|
|
@@ -673,7 +711,7 @@ export class Solver {
|
|
|
673
711
|
// pending exactly as they do for a direct call. A fresh active marker
|
|
674
712
|
// keeps cut opaque at the call/N boundary.
|
|
675
713
|
const expanded = def.expandGoal({ solver: this, goal, env });
|
|
676
|
-
const invocation = { goal, env };
|
|
714
|
+
const invocation = { goal, env: env._snapshotForSolverRead() };
|
|
677
715
|
active = [...active, invocation];
|
|
678
716
|
goals = [expanded, { kind: 'releaseActive' }, ...rest];
|
|
679
717
|
depth++;
|
|
@@ -1096,12 +1134,12 @@ export class Solver {
|
|
|
1096
1134
|
// expansion of the current rule body, but it must be released before
|
|
1097
1135
|
// the caller's remaining goals are solved. Keeping the goal active
|
|
1098
1136
|
// through rest goals over-prunes valid transitive/recursive derivations.
|
|
1099
|
-
this.active.push({ goal, env: goalEnv });
|
|
1137
|
+
this.active.push({ goal, env: goalEnv._snapshotForSolverRead() });
|
|
1100
1138
|
for (const bodyEnv of this.solve(body, env, depth + 1)) {
|
|
1101
1139
|
if (this.solutionsSeen > 0) this.solutionsSeen--;
|
|
1102
1140
|
this.active.pop();
|
|
1103
1141
|
yield* this.solve(rest, bodyEnv, depth + 1);
|
|
1104
|
-
this.active.push({ goal, env: goalEnv });
|
|
1142
|
+
this.active.push({ goal, env: goalEnv._snapshotForSolverRead() });
|
|
1105
1143
|
if (this.solutionsSeen >= this.solutionLimit) break;
|
|
1106
1144
|
}
|
|
1107
1145
|
this.active.pop();
|
|
@@ -1231,25 +1269,24 @@ function pushMemoAnswerFrames(stack, entry, goal, rest, env, depth, active, solv
|
|
|
1231
1269
|
selected = { bucket, fallback, length: candidateLength };
|
|
1232
1270
|
}
|
|
1233
1271
|
}
|
|
1234
|
-
const
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
:
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
}
|
|
1245
|
-
if (ok) stack.push({ kind: 'goals', goals: rest, env: next, depth: depth + 1, active });
|
|
1272
|
+
const pushReplay = (answerIndex) => {
|
|
1273
|
+
stack.push({
|
|
1274
|
+
kind: 'unifyArgsBranch',
|
|
1275
|
+
goal,
|
|
1276
|
+
args: entry.answers[answerIndex],
|
|
1277
|
+
freshNonGround: true,
|
|
1278
|
+
goals: rest,
|
|
1279
|
+
env,
|
|
1280
|
+
depth: depth + 1,
|
|
1281
|
+
active,
|
|
1282
|
+
});
|
|
1246
1283
|
};
|
|
1247
1284
|
if (selected != null) {
|
|
1248
|
-
for (let i = selected.fallback.length - 1; i >= 0; i--)
|
|
1249
|
-
for (let i = selected.bucket.length - 1; i >= 0; i--)
|
|
1285
|
+
for (let i = selected.fallback.length - 1; i >= 0; i--) pushReplay(selected.fallback[i]);
|
|
1286
|
+
for (let i = selected.bucket.length - 1; i >= 0; i--) pushReplay(selected.bucket[i]);
|
|
1250
1287
|
return;
|
|
1251
1288
|
}
|
|
1252
|
-
for (let answerIndex = entry.answers.length - 1; answerIndex >= 0; answerIndex--)
|
|
1289
|
+
for (let answerIndex = entry.answers.length - 1; answerIndex >= 0; answerIndex--) pushReplay(answerIndex);
|
|
1253
1290
|
}
|
|
1254
1291
|
|
|
1255
1292
|
function pushUserGoalUncachedFrames(stack, solver, group, goal, rest, env, depth, active) {
|
|
@@ -1258,7 +1295,7 @@ function pushUserGoalUncachedFrames(stack, solver, group, goal, rest, env, depth
|
|
|
1258
1295
|
if (tryPushGroundChainFrames(stack, solver, group, goal, rest, env, depth, active)) return;
|
|
1259
1296
|
const candidates = selectClauseCandidates(group, goal, env);
|
|
1260
1297
|
const frames = [];
|
|
1261
|
-
const invocation = { goal, env };
|
|
1298
|
+
const invocation = { goal, env: env._snapshotForSolverRead() };
|
|
1262
1299
|
// Active frames serve two purposes: they delimit cut and detect variants in
|
|
1263
1300
|
// recursive user predicates. Cut-free, non-recursive library helpers need
|
|
1264
1301
|
// neither. Copying their full active stack at every recursive step made
|
|
@@ -1535,18 +1572,20 @@ function pushWfsAnswerFrames(stack, model, group, goal, rest, env, depth, active
|
|
|
1535
1572
|
if (!relation) return;
|
|
1536
1573
|
for (let rowIndex = relation.rows.length - 1; rowIndex >= 0; rowIndex--) {
|
|
1537
1574
|
const row = relation.rows[rowIndex];
|
|
1538
|
-
const next = env.clone();
|
|
1539
|
-
let ok = true;
|
|
1540
|
-
for (let i = 0; i < goal.arity; i++) {
|
|
1541
|
-
solver.stats.unify_calls++;
|
|
1542
|
-
if (!unify(goal.args[i], row[i], next)) { ok = false; break; }
|
|
1543
|
-
}
|
|
1544
|
-
if (!ok) continue;
|
|
1545
1575
|
if (!lower?.has(row)) {
|
|
1546
1576
|
solver.stats.wfs_undefined_answers++;
|
|
1547
1577
|
continue;
|
|
1548
1578
|
}
|
|
1549
|
-
stack.push({
|
|
1579
|
+
stack.push({
|
|
1580
|
+
kind: 'unifyArgsBranch',
|
|
1581
|
+
goal,
|
|
1582
|
+
args: row,
|
|
1583
|
+
freshNonGround: false,
|
|
1584
|
+
goals: rest,
|
|
1585
|
+
env,
|
|
1586
|
+
depth: depth + 1,
|
|
1587
|
+
active,
|
|
1588
|
+
});
|
|
1550
1589
|
}
|
|
1551
1590
|
}
|
|
1552
1591
|
|
|
@@ -2030,14 +2069,8 @@ function termReferencesResolvedVariable(term, variableName, env) {
|
|
|
2030
2069
|
}
|
|
2031
2070
|
|
|
2032
2071
|
function envHasObservableAliasTo(variableName, env) {
|
|
2033
|
-
for (
|
|
2034
|
-
if (
|
|
2035
|
-
termReferencesResolvedVariable(state.bindingValue, variableName, env)) return true;
|
|
2036
|
-
if (state.bindings) {
|
|
2037
|
-
for (const [name, value] of state.bindings) {
|
|
2038
|
-
if (name !== variableName && termReferencesResolvedVariable(value, variableName, env)) return true;
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2072
|
+
for (const [name, value] of env?._bindingEntries?.() ?? []) {
|
|
2073
|
+
if (name !== variableName && termReferencesResolvedVariable(value, variableName, env)) return true;
|
|
2041
2074
|
}
|
|
2042
2075
|
return false;
|
|
2043
2076
|
}
|
|
@@ -2315,10 +2348,15 @@ function tryPushScalarFactRunFrames(stack, solver, goals, env, depth, active) {
|
|
|
2315
2348
|
const state = localStack.pop();
|
|
2316
2349
|
solver.stats.max_depth = Math.max(solver.stats.max_depth, state.depth);
|
|
2317
2350
|
if (state.index === runLength) {
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2351
|
+
frames.push({
|
|
2352
|
+
kind: 'bindBranch',
|
|
2353
|
+
names: state.names,
|
|
2354
|
+
values: state.values,
|
|
2355
|
+
goals: rest,
|
|
2356
|
+
env,
|
|
2357
|
+
depth: state.depth,
|
|
2358
|
+
active,
|
|
2359
|
+
});
|
|
2322
2360
|
if (frames.length > frameLimit) {
|
|
2323
2361
|
// Do not repeat the old bug of abandoning the optimization and then
|
|
2324
2362
|
// re-solving through the generic engine. Restart this rare oversized
|
package/src/term.js
CHANGED
|
@@ -167,6 +167,15 @@ export class Env {
|
|
|
167
167
|
this._attributeHookRunner = typeof handler === 'function' ? handler : null;
|
|
168
168
|
return this;
|
|
169
169
|
}
|
|
170
|
+
_asSolverEnv() {
|
|
171
|
+
return SolverEnv.from(this);
|
|
172
|
+
}
|
|
173
|
+
_isSolverEnv() {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
_snapshotForSolverRead() {
|
|
177
|
+
return this.clone();
|
|
178
|
+
}
|
|
170
179
|
adopt(other) {
|
|
171
180
|
if (!(other instanceof Env)) throw new TypeError('Env.adopt expects Env');
|
|
172
181
|
this._state = other._state;
|
|
@@ -333,6 +342,22 @@ export class Env {
|
|
|
333
342
|
}
|
|
334
343
|
return undefined;
|
|
335
344
|
}
|
|
345
|
+
*_bindingEntries() {
|
|
346
|
+
const seen = new Set();
|
|
347
|
+
for (let state = this._state; state != null; state = state.parent) {
|
|
348
|
+
if (state.bindingName != null && !seen.has(state.bindingName)) {
|
|
349
|
+
seen.add(state.bindingName);
|
|
350
|
+
yield [state.bindingName, state.bindingValue];
|
|
351
|
+
}
|
|
352
|
+
if (state.bindings) {
|
|
353
|
+
for (const [name, value] of state.bindings) {
|
|
354
|
+
if (seen.has(name)) continue;
|
|
355
|
+
seen.add(name);
|
|
356
|
+
yield [name, value];
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
336
361
|
compactForDeepContinuation(segmentLimit = 16) {
|
|
337
362
|
if ((this._state.segmentCount ?? 0) < segmentLimit) return false;
|
|
338
363
|
const flattened = new Map();
|
|
@@ -648,6 +673,227 @@ export class Env {
|
|
|
648
673
|
}
|
|
649
674
|
}
|
|
650
675
|
|
|
676
|
+
|
|
677
|
+
class SolverBindingStore {
|
|
678
|
+
constructor(bindings) {
|
|
679
|
+
this.slots = new Map();
|
|
680
|
+
this.names = [];
|
|
681
|
+
this.values = [];
|
|
682
|
+
this.baseValues = [];
|
|
683
|
+
this.slotLastTrail = [];
|
|
684
|
+
this.freeSlots = [];
|
|
685
|
+
this.trailNames = [];
|
|
686
|
+
this.trailSlots = [];
|
|
687
|
+
this.trailOldValues = [];
|
|
688
|
+
this.trailNewValues = [];
|
|
689
|
+
this.trailPreviousForSlot = [];
|
|
690
|
+
this.trailCreated = [];
|
|
691
|
+
if (bindings != null) {
|
|
692
|
+
for (const [name, value] of bindings) {
|
|
693
|
+
const slot = this.names.length;
|
|
694
|
+
this.slots.set(name, slot);
|
|
695
|
+
this.names.push(name);
|
|
696
|
+
this.values.push(value);
|
|
697
|
+
this.baseValues.push(value);
|
|
698
|
+
this.slotLastTrail.push(-1);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
mark() {
|
|
704
|
+
return this.trailSlots.length;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
rollback(mark) {
|
|
708
|
+
if (mark > this.trailSlots.length) {
|
|
709
|
+
throw new Error('stale solver binding mark');
|
|
710
|
+
}
|
|
711
|
+
while (this.trailSlots.length > mark) {
|
|
712
|
+
const created = this.trailCreated.pop();
|
|
713
|
+
const previousForSlot = this.trailPreviousForSlot.pop();
|
|
714
|
+
this.trailNewValues.pop();
|
|
715
|
+
const oldValue = this.trailOldValues.pop();
|
|
716
|
+
const slot = this.trailSlots.pop();
|
|
717
|
+
const name = this.trailNames.pop();
|
|
718
|
+
this.slotLastTrail[slot] = previousForSlot;
|
|
719
|
+
if (created) {
|
|
720
|
+
this.slots.delete(name);
|
|
721
|
+
this.values[slot] = ENV_UNBOUND;
|
|
722
|
+
this.baseValues[slot] = ENV_UNBOUND;
|
|
723
|
+
this.names[slot] = null;
|
|
724
|
+
this.freeSlots.push(slot);
|
|
725
|
+
} else {
|
|
726
|
+
this.values[slot] = oldValue;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
bind(name, value) {
|
|
732
|
+
let slot = this.slots.get(name);
|
|
733
|
+
const created = slot === undefined;
|
|
734
|
+
if (created) {
|
|
735
|
+
slot = this.freeSlots.length === 0 ? this.values.length : this.freeSlots.pop();
|
|
736
|
+
this.slots.set(name, slot);
|
|
737
|
+
this.names[slot] = name;
|
|
738
|
+
this.values[slot] = ENV_UNBOUND;
|
|
739
|
+
this.baseValues[slot] = ENV_UNBOUND;
|
|
740
|
+
this.slotLastTrail[slot] = -1;
|
|
741
|
+
}
|
|
742
|
+
const entry = this.trailSlots.length;
|
|
743
|
+
this.trailNames.push(name);
|
|
744
|
+
this.trailSlots.push(slot);
|
|
745
|
+
this.trailOldValues.push(this.values[slot]);
|
|
746
|
+
this.trailNewValues.push(value);
|
|
747
|
+
this.trailPreviousForSlot.push(this.slotLastTrail[slot] ?? -1);
|
|
748
|
+
this.trailCreated.push(created);
|
|
749
|
+
this.slotLastTrail[slot] = entry;
|
|
750
|
+
this.values[slot] = value;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
getAtMark(name, mark) {
|
|
754
|
+
if (mark > this.trailSlots.length) throw new Error('stale solver binding mark');
|
|
755
|
+
const slot = this.slots.get(name);
|
|
756
|
+
if (slot === undefined) return undefined;
|
|
757
|
+
let entry = this.slotLastTrail[slot] ?? -1;
|
|
758
|
+
while (entry >= mark) entry = this.trailPreviousForSlot[entry] ?? -1;
|
|
759
|
+
const value = entry >= 0 ? this.trailNewValues[entry] : this.baseValues[slot];
|
|
760
|
+
return value === ENV_UNBOUND ? undefined : value;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function copyEnvBranchState(source, target) {
|
|
765
|
+
target._delays = source._delays;
|
|
766
|
+
target._variableConstraints = source._variableConstraints;
|
|
767
|
+
target._variableAnnotations = source._variableAnnotations;
|
|
768
|
+
target._prologAttributes = source._prologAttributes;
|
|
769
|
+
target._attributeHookRunner = source._attributeHookRunner;
|
|
770
|
+
target._pendingAttributeGoals = source._pendingAttributeGoals;
|
|
771
|
+
target._backtrackableBlackboard = source._backtrackableBlackboard;
|
|
772
|
+
target._occursCheckHandler = source._occursCheckHandler;
|
|
773
|
+
target._localVariables = source._localVariables;
|
|
774
|
+
target._compactVariableOrigins = source._compactVariableOrigins;
|
|
775
|
+
target._compactVariableRisks = source._compactVariableRisks;
|
|
776
|
+
return target;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
class SolverEnvReadView {
|
|
780
|
+
constructor(source) {
|
|
781
|
+
this._solverBindings = source._solverBindings;
|
|
782
|
+
this._solverBindingMark = source._solverBindingMark;
|
|
783
|
+
this._localVariables = source._localVariables;
|
|
784
|
+
}
|
|
785
|
+
get(name) {
|
|
786
|
+
return this._solverBindings.getAtMark(name, this._solverBindingMark);
|
|
787
|
+
}
|
|
788
|
+
has(name) {
|
|
789
|
+
return this.get(name) !== undefined;
|
|
790
|
+
}
|
|
791
|
+
isLocalVariable(name) {
|
|
792
|
+
return this._localVariables?.has(name) === true;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// SolverEnv replaces persistent binding layers with one solver-owned mutable
|
|
797
|
+
// slot store and a linear trail. Clones are just trail marks plus the existing
|
|
798
|
+
// copy-on-write logical side stores. The solver explores these marks in depth-
|
|
799
|
+
// first order, so rollback can discard unreachable branch history immediately.
|
|
800
|
+
// Public Env remains persistent and is used for stable API snapshots.
|
|
801
|
+
class SolverEnv extends Env {
|
|
802
|
+
constructor() {
|
|
803
|
+
super();
|
|
804
|
+
this._solverBindings = new SolverBindingStore();
|
|
805
|
+
this._solverBindingMark = 0;
|
|
806
|
+
this._state = null;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
static from(env) {
|
|
810
|
+
if (env instanceof SolverEnv) return env;
|
|
811
|
+
const solverEnv = Object.create(SolverEnv.prototype);
|
|
812
|
+
solverEnv._state = null;
|
|
813
|
+
solverEnv._solverBindings = new SolverBindingStore(env?._bindingEntries?.() ?? []);
|
|
814
|
+
solverEnv._solverBindingMark = 0;
|
|
815
|
+
copyEnvBranchState(env ?? new Env(), solverEnv);
|
|
816
|
+
return solverEnv;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
_asSolverEnv() {
|
|
820
|
+
return this;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
_isSolverEnv() {
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
_snapshotForSolverRead() {
|
|
828
|
+
return new SolverEnvReadView(this);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
_activateBindings() {
|
|
832
|
+
if (this._solverBindingMark !== this._solverBindings.trailSlots.length) {
|
|
833
|
+
this._solverBindings.rollback(this._solverBindingMark);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
clone() {
|
|
838
|
+
this._activateBindings();
|
|
839
|
+
const clone = Object.create(SolverEnv.prototype);
|
|
840
|
+
clone._state = null;
|
|
841
|
+
clone._solverBindings = this._solverBindings;
|
|
842
|
+
clone._solverBindingMark = this._solverBindingMark;
|
|
843
|
+
return copyEnvBranchState(this, clone);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
adopt(other) {
|
|
847
|
+
if (!(other instanceof Env)) throw new TypeError('Env.adopt expects Env');
|
|
848
|
+
if (other instanceof SolverEnv && other._solverBindings === this._solverBindings) {
|
|
849
|
+
other._activateBindings();
|
|
850
|
+
this._solverBindingMark = other._solverBindingMark;
|
|
851
|
+
} else {
|
|
852
|
+
const replacement = SolverEnv.from(other);
|
|
853
|
+
this._solverBindings = replacement._solverBindings;
|
|
854
|
+
this._solverBindingMark = replacement._solverBindingMark;
|
|
855
|
+
}
|
|
856
|
+
copyEnvBranchState(other, this);
|
|
857
|
+
return this;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
has(name) {
|
|
861
|
+
return this.get(name) !== undefined;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
get(name) {
|
|
865
|
+
this._activateBindings();
|
|
866
|
+
const slot = this._solverBindings.slots.get(name);
|
|
867
|
+
if (slot === undefined) return undefined;
|
|
868
|
+
const value = this._solverBindings.values[slot];
|
|
869
|
+
return value === ENV_UNBOUND ? undefined : value;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
*_bindingEntries() {
|
|
873
|
+
this._activateBindings();
|
|
874
|
+
for (const [name, slot] of this._solverBindings.slots) {
|
|
875
|
+
const value = this._solverBindings.values[slot];
|
|
876
|
+
if (value !== ENV_UNBOUND) yield [name, value];
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
bind(name, term) {
|
|
881
|
+
this._activateBindings();
|
|
882
|
+
this._solverBindings.bind(name, term);
|
|
883
|
+
this._solverBindingMark = this._solverBindings.mark();
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
compactForDeepContinuation() {
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
_toPersistentEnv() {
|
|
891
|
+
const stable = new Env(this._bindingEntries());
|
|
892
|
+
copyEnvBranchState(this, stable);
|
|
893
|
+
return stable;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
651
897
|
export function deref(term, env) {
|
|
652
898
|
// Follow variable bindings until a non-variable term is reached. The seen set
|
|
653
899
|
// protects readback from accidental cycles in partially constructed terms.
|