@metta-ts/core 1.0.3 → 1.0.5
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/dist/index.d.ts +33 -2
- package/dist/index.js +574 -71
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -209,15 +209,26 @@ declare class FlatAtomSpace {
|
|
|
209
209
|
private readonly dead;
|
|
210
210
|
readonly liveCount: number;
|
|
211
211
|
readonly nonGroundCount: number;
|
|
212
|
+
private arr;
|
|
212
213
|
private constructor();
|
|
213
214
|
static empty(): FlatAtomSpace;
|
|
214
215
|
static fromAtoms(atoms: readonly Atom[]): FlatAtomSpace | undefined;
|
|
215
216
|
get size(): number;
|
|
216
|
-
|
|
217
|
+
/** Append a batch as new visible facts. Returns undefined when some atom is not flat-storable (a
|
|
218
|
+
* grounded executor/matcher); the caller keeps such a batch on the plain log instead. */
|
|
219
|
+
appendAll(atoms: readonly Atom[]): FlatAtomSpace | undefined;
|
|
217
220
|
removeOne(atom: Atom): FlatAtomSpace;
|
|
218
221
|
exactCount(atom: Atom): number;
|
|
219
222
|
candidatesFor(patternHead: string | undefined): Iterable<Atom>;
|
|
220
223
|
toArray(): Atom[];
|
|
224
|
+
/** Columnar mirror of the `&self` direct tally in eval.ts: over the visible facts the head filter
|
|
225
|
+
* admits (head symbol `patternHead` or no symbol head, same filter as `candidatesFor`), count the
|
|
226
|
+
* ones an all-distinct-variable pattern `(k $v..)` of `arity` items unifies with, without decoding
|
|
227
|
+
* any fact. `iterated` is the admitted total (it advances the candidate counter). */
|
|
228
|
+
countHeadArity(patternHead: string, arity: number): {
|
|
229
|
+
count: number;
|
|
230
|
+
iterated: number;
|
|
231
|
+
};
|
|
221
232
|
roundTrip(atom: Atom): Atom;
|
|
222
233
|
private decodeFact;
|
|
223
234
|
private visibleFactIds;
|
|
@@ -297,6 +308,20 @@ interface SymbolicHolder {
|
|
|
297
308
|
}
|
|
298
309
|
interface CompiledImpureOps {
|
|
299
310
|
readonly addAtom: (env: MinEnv, st: St, space: Atom, atom: Atom) => St | undefined;
|
|
311
|
+
/** Solutions of a `(match space pattern template)` under the current world: the instantiated
|
|
312
|
+
* template plus that solution's bindings, in the interpreter's own candidate order, and the
|
|
313
|
+
* fresh-variable counter advance the interpreted match would have cost. Undefined = not a space. */
|
|
314
|
+
readonly matchSolutions?: (env: MinEnv, st: St, space: Atom, pattern: Atom, template: Atom) => {
|
|
315
|
+
readonly pairs: ReadonlyArray<readonly [Atom, Bindings]>;
|
|
316
|
+
readonly counterDelta: number;
|
|
317
|
+
} | undefined;
|
|
318
|
+
/** The add-if-absent idiom on a ground atom: exact-membership probe, then append when absent.
|
|
319
|
+
* Undefined when the fast probe is unsound for this space (non-ground facts, static facts of the
|
|
320
|
+
* same head, state handles), sending the caller back to the interpreter. */
|
|
321
|
+
readonly addIfAbsent?: (env: MinEnv, st: St, space: Atom, atom: Atom) => {
|
|
322
|
+
readonly added: boolean;
|
|
323
|
+
readonly state: St;
|
|
324
|
+
} | undefined;
|
|
300
325
|
}
|
|
301
326
|
type ImpEval = {
|
|
302
327
|
readonly value: Atom;
|
|
@@ -308,7 +333,13 @@ interface ImperativeHolder {
|
|
|
308
333
|
clauseCount: number;
|
|
309
334
|
run: (partAtoms: readonly Atom[], st: St, ops: CompiledImpureOps, discard?: boolean) => ImpEval;
|
|
310
335
|
}
|
|
311
|
-
|
|
336
|
+
interface NondetHolder {
|
|
337
|
+
kind: "nondet";
|
|
338
|
+
arity: number;
|
|
339
|
+
clauseCount: number;
|
|
340
|
+
run: (env: MinEnv, partAtoms: readonly Atom[], st: St, ops: CompiledImpureOps) => CompiledRunResult | undefined;
|
|
341
|
+
}
|
|
342
|
+
type CompiledHolder = FunctionalHolder | RewriteHolder | SymbolicHolder | ImperativeHolder | NondetHolder;
|
|
312
343
|
type CompiledFns = Map<string, CompiledHolder>;
|
|
313
344
|
/** Compile every compilable pure single-clause function in `env` to a memoised native closure.
|
|
314
345
|
* Phase 1 infers return types (fixpoint, optimistic over recursion). Phase 2 compiles bodies with
|
package/dist/index.js
CHANGED
|
@@ -1048,6 +1048,7 @@ function canCompactAtom(a) {
|
|
|
1048
1048
|
return a.items.every(canCompactAtom);
|
|
1049
1049
|
}
|
|
1050
1050
|
}
|
|
1051
|
+
var NOT_COMPACT = new Error("flat-atomspace: atom has an executor or custom matcher");
|
|
1051
1052
|
var FlatAtomSpaceTable = class {
|
|
1052
1053
|
termKind = new Int32Chunks();
|
|
1053
1054
|
termStart = new Int32Chunks();
|
|
@@ -1057,7 +1058,17 @@ var FlatAtomSpaceTable = class {
|
|
|
1057
1058
|
termData = new Int32Chunks();
|
|
1058
1059
|
factRoot = new Int32Chunks();
|
|
1059
1060
|
factHeadSym = new Int32Chunks();
|
|
1060
|
-
|
|
1061
|
+
// Open-addressing intern table (linear probing over a power-of-two Int32Array; a slot holds
|
|
1062
|
+
// termId + 1, 0 means empty; append-only, so no tombstones). Replaces a Map<number, TermId[]>
|
|
1063
|
+
// whose per-hash bucket arrays were the dominant insert allocation on bulk loads.
|
|
1064
|
+
slots = new Int32Array(1 << 12);
|
|
1065
|
+
slotCount = 0;
|
|
1066
|
+
// The empty slot where the last failed lookup probe for `missHash` ended. intern* runs
|
|
1067
|
+
// lookup-then-push, so pushTerm claims this slot instead of re-probing the chain. Slots only ever
|
|
1068
|
+
// fill (append-only), so a chain never shortens and the recorded slot stays on its hash's chain;
|
|
1069
|
+
// pushTerm still re-checks the hash matches and the slot is still empty before trusting it.
|
|
1070
|
+
missSlot = -1;
|
|
1071
|
+
missHash = 0;
|
|
1061
1072
|
symByName = /* @__PURE__ */ new Map();
|
|
1062
1073
|
groundByKey = /* @__PURE__ */ new Map();
|
|
1063
1074
|
varByName = /* @__PURE__ */ new Map();
|
|
@@ -1065,6 +1076,15 @@ var FlatAtomSpaceTable = class {
|
|
|
1065
1076
|
symbols = [];
|
|
1066
1077
|
grounds = [];
|
|
1067
1078
|
vars = [];
|
|
1079
|
+
// One canonical Atom per term, filled on first decode. Terms are interned and append-only, so a
|
|
1080
|
+
// decoded atom is valid forever; without this, candidate enumeration rebuilt a fresh tree per fact
|
|
1081
|
+
// per match, which on deep terms (peano's S^n numerals) made matching O(n^3) instead of O(n^2).
|
|
1082
|
+
// Children resolve through the cache too, so the cached forest is maximally shared (hash-consed).
|
|
1083
|
+
decoded = [];
|
|
1084
|
+
// Reverse intern: an Atom object to its TermId. Weak, so the cache never pins an atom. Match
|
|
1085
|
+
// bindings hold decoded (canonical) subterms, so an atom derived from them re-interns in O(new
|
|
1086
|
+
// nodes) instead of O(depth), and a ground membership lookup is O(1) after its first walk.
|
|
1087
|
+
termIdOf = /* @__PURE__ */ new WeakMap();
|
|
1068
1088
|
get factCount() {
|
|
1069
1089
|
return this.factRoot.length;
|
|
1070
1090
|
}
|
|
@@ -1081,6 +1101,14 @@ var FlatAtomSpaceTable = class {
|
|
|
1081
1101
|
return this.termFacts.get(term) ?? [];
|
|
1082
1102
|
}
|
|
1083
1103
|
insertAtom(atom) {
|
|
1104
|
+
if (atom.kind !== "expr") return this.insertAtomUncached(atom);
|
|
1105
|
+
const known = this.termIdOf.get(atom);
|
|
1106
|
+
if (known !== void 0) return known;
|
|
1107
|
+
const term = this.insertAtomUncached(atom);
|
|
1108
|
+
this.termIdOf.set(atom, term);
|
|
1109
|
+
return term;
|
|
1110
|
+
}
|
|
1111
|
+
insertAtomUncached(atom) {
|
|
1084
1112
|
switch (atom.kind) {
|
|
1085
1113
|
case "sym":
|
|
1086
1114
|
return this.internLeaf(
|
|
@@ -1090,6 +1118,7 @@ var FlatAtomSpaceTable = class {
|
|
|
1090
1118
|
true
|
|
1091
1119
|
);
|
|
1092
1120
|
case "gnd": {
|
|
1121
|
+
if (atom.exec !== void 0 || atom.match !== void 0) throw NOT_COMPACT;
|
|
1093
1122
|
const key = groundKey(atom.value);
|
|
1094
1123
|
return this.internLeaf(
|
|
1095
1124
|
TERM_GND,
|
|
@@ -1112,6 +1141,13 @@ var FlatAtomSpaceTable = class {
|
|
|
1112
1141
|
}
|
|
1113
1142
|
}
|
|
1114
1143
|
lookupAtom(atom) {
|
|
1144
|
+
const known = this.termIdOf.get(atom);
|
|
1145
|
+
if (known !== void 0) return known;
|
|
1146
|
+
const term = this.lookupAtomUncached(atom);
|
|
1147
|
+
if (term !== void 0) this.termIdOf.set(atom, term);
|
|
1148
|
+
return term;
|
|
1149
|
+
}
|
|
1150
|
+
lookupAtomUncached(atom) {
|
|
1115
1151
|
switch (atom.kind) {
|
|
1116
1152
|
case "sym": {
|
|
1117
1153
|
const leaf = this.symByName.get(atom.name);
|
|
@@ -1139,6 +1175,14 @@ var FlatAtomSpaceTable = class {
|
|
|
1139
1175
|
}
|
|
1140
1176
|
}
|
|
1141
1177
|
decodeTerm(term) {
|
|
1178
|
+
const hit = this.decoded[term];
|
|
1179
|
+
if (hit !== void 0) return hit;
|
|
1180
|
+
const atom = this.decodeTermUncached(term);
|
|
1181
|
+
this.decoded[term] = atom;
|
|
1182
|
+
this.termIdOf.set(atom, term);
|
|
1183
|
+
return atom;
|
|
1184
|
+
}
|
|
1185
|
+
decodeTermUncached(term) {
|
|
1142
1186
|
const kind = this.termKind.get(term);
|
|
1143
1187
|
const start = this.termStart.get(term);
|
|
1144
1188
|
switch (kind) {
|
|
@@ -1203,11 +1247,22 @@ var FlatAtomSpaceTable = class {
|
|
|
1203
1247
|
return this.pushTerm(kind, leaf, 1, hash, ground);
|
|
1204
1248
|
}
|
|
1205
1249
|
lookupLeaf(kind, leaf, hash) {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1250
|
+
hash |= 0;
|
|
1251
|
+
const slots = this.slots;
|
|
1252
|
+
const mask = slots.length - 1;
|
|
1253
|
+
let i = hash & mask;
|
|
1254
|
+
for (; ; ) {
|
|
1255
|
+
const s = slots[i];
|
|
1256
|
+
if (s === 0) {
|
|
1257
|
+
this.missSlot = i;
|
|
1258
|
+
this.missHash = hash;
|
|
1259
|
+
return void 0;
|
|
1260
|
+
}
|
|
1261
|
+
const term = s - 1;
|
|
1262
|
+
if (this.termHash.get(term) === hash && this.termKind.get(term) === kind && this.termStart.get(term) === leaf)
|
|
1263
|
+
return term;
|
|
1264
|
+
i = i + 1 & mask;
|
|
1265
|
+
}
|
|
1211
1266
|
}
|
|
1212
1267
|
internExpr(children) {
|
|
1213
1268
|
const existing = this.lookupExpr(children);
|
|
@@ -1222,33 +1277,69 @@ var FlatAtomSpaceTable = class {
|
|
|
1222
1277
|
}
|
|
1223
1278
|
return this.pushTerm(TERM_EXPR, start, children.length, hash, ground);
|
|
1224
1279
|
}
|
|
1280
|
+
// The probe skeleton repeats lookupLeaf's on purpose: sharing it would take a per-call equality
|
|
1281
|
+
// closure, and avoiding that allocation on the intern path is why the open table exists.
|
|
1225
1282
|
lookupExpr(children) {
|
|
1226
1283
|
let hash = mixHash(1163415634, children.length);
|
|
1227
1284
|
for (const child of children) hash = mixHash(hash, child);
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1285
|
+
hash |= 0;
|
|
1286
|
+
const slots = this.slots;
|
|
1287
|
+
const mask = slots.length - 1;
|
|
1288
|
+
let i = hash & mask;
|
|
1289
|
+
probe: for (; ; ) {
|
|
1290
|
+
const s = slots[i];
|
|
1291
|
+
if (s === 0) {
|
|
1292
|
+
this.missSlot = i;
|
|
1293
|
+
this.missHash = hash;
|
|
1294
|
+
return void 0;
|
|
1295
|
+
}
|
|
1296
|
+
const term = s - 1;
|
|
1297
|
+
if (this.termHash.get(term) === hash && this.termKind.get(term) === TERM_EXPR && this.termLen.get(term) === children.length) {
|
|
1298
|
+
const start = this.termStart.get(term);
|
|
1299
|
+
for (let j = 0; j < children.length; j++)
|
|
1300
|
+
if (this.termData.get(start + j) !== children[j]) {
|
|
1301
|
+
i = i + 1 & mask;
|
|
1302
|
+
continue probe;
|
|
1303
|
+
}
|
|
1304
|
+
return term;
|
|
1305
|
+
}
|
|
1306
|
+
i = i + 1 & mask;
|
|
1237
1307
|
}
|
|
1238
|
-
return void 0;
|
|
1239
1308
|
}
|
|
1240
1309
|
pushTerm(kind, start, len, hash, ground) {
|
|
1310
|
+
hash |= 0;
|
|
1241
1311
|
const term = this.termKind.length;
|
|
1242
1312
|
this.termKind.push(kind);
|
|
1243
1313
|
this.termStart.push(start);
|
|
1244
1314
|
this.termLen.push(len);
|
|
1245
1315
|
this.termHash.push(hash);
|
|
1246
1316
|
this.termGround.push(ground ? 1 : 0);
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1317
|
+
if ((this.slotCount + 1) * 4 > this.slots.length * 3) {
|
|
1318
|
+
this.growSlots();
|
|
1319
|
+
this.missSlot = -1;
|
|
1320
|
+
}
|
|
1321
|
+
let i = this.missSlot;
|
|
1322
|
+
this.missSlot = -1;
|
|
1323
|
+
if (i < 0 || this.missHash !== hash || this.slots[i] !== 0) {
|
|
1324
|
+
const mask = this.slots.length - 1;
|
|
1325
|
+
i = hash & mask;
|
|
1326
|
+
while (this.slots[i] !== 0) i = i + 1 & mask;
|
|
1327
|
+
}
|
|
1328
|
+
this.slots[i] = term + 1;
|
|
1329
|
+
this.slotCount += 1;
|
|
1250
1330
|
return term;
|
|
1251
1331
|
}
|
|
1332
|
+
growSlots() {
|
|
1333
|
+
const next = new Int32Array(this.slots.length * 2);
|
|
1334
|
+
const mask = next.length - 1;
|
|
1335
|
+
for (const s of this.slots) {
|
|
1336
|
+
if (s === 0) continue;
|
|
1337
|
+
let i = this.termHash.get(s - 1) & mask;
|
|
1338
|
+
while (next[i] !== 0) i = i + 1 & mask;
|
|
1339
|
+
next[i] = s;
|
|
1340
|
+
}
|
|
1341
|
+
this.slots = next;
|
|
1342
|
+
}
|
|
1252
1343
|
};
|
|
1253
1344
|
var FlatAtomSpace = class _FlatAtomSpace {
|
|
1254
1345
|
constructor(table, ranges, dead, liveCount, nonGroundCount) {
|
|
@@ -1263,23 +1354,31 @@ var FlatAtomSpace = class _FlatAtomSpace {
|
|
|
1263
1354
|
dead;
|
|
1264
1355
|
liveCount;
|
|
1265
1356
|
nonGroundCount;
|
|
1357
|
+
// toArray memo for this version (see toArray).
|
|
1358
|
+
arr;
|
|
1266
1359
|
static empty() {
|
|
1267
1360
|
return new _FlatAtomSpace(new FlatAtomSpaceTable(), [], /* @__PURE__ */ new Set(), 0, 0);
|
|
1268
1361
|
}
|
|
1269
1362
|
static fromAtoms(atoms) {
|
|
1270
|
-
if (!atoms.every(canCompactAtom)) return void 0;
|
|
1271
1363
|
return _FlatAtomSpace.empty().appendAll(atoms);
|
|
1272
1364
|
}
|
|
1273
1365
|
get size() {
|
|
1274
1366
|
return this.liveCount;
|
|
1275
1367
|
}
|
|
1368
|
+
/** Append a batch as new visible facts. Returns undefined when some atom is not flat-storable (a
|
|
1369
|
+
* grounded executor/matcher); the caller keeps such a batch on the plain log instead. */
|
|
1276
1370
|
appendAll(atoms) {
|
|
1277
1371
|
if (atoms.length === 0) return this;
|
|
1278
1372
|
const start = this.table.factCount;
|
|
1279
1373
|
let nonGround = this.nonGroundCount;
|
|
1280
|
-
|
|
1281
|
-
const
|
|
1282
|
-
|
|
1374
|
+
try {
|
|
1375
|
+
for (const atom of atoms) {
|
|
1376
|
+
const fact = this.table.insertFact(atom);
|
|
1377
|
+
if (!this.table.isTermGround(this.table.factRoot.get(fact))) nonGround += 1;
|
|
1378
|
+
}
|
|
1379
|
+
} catch (e) {
|
|
1380
|
+
if (e === NOT_COMPACT) return void 0;
|
|
1381
|
+
throw e;
|
|
1283
1382
|
}
|
|
1284
1383
|
const end = this.table.factCount;
|
|
1285
1384
|
return new _FlatAtomSpace(
|
|
@@ -1293,8 +1392,8 @@ var FlatAtomSpace = class _FlatAtomSpace {
|
|
|
1293
1392
|
removeOne(atom) {
|
|
1294
1393
|
const term = this.table.lookupAtom(atom);
|
|
1295
1394
|
if (term === void 0) return this;
|
|
1296
|
-
for (const fact of this.
|
|
1297
|
-
if (this.
|
|
1395
|
+
for (const fact of this.table.factsForTerm(term)) {
|
|
1396
|
+
if (!this.factVisible(fact) || this.dead.has(fact)) continue;
|
|
1298
1397
|
const dead = new Set(this.dead);
|
|
1299
1398
|
dead.add(fact);
|
|
1300
1399
|
const nonGround = this.table.isTermGround(term) ? this.nonGroundCount : this.nonGroundCount - 1;
|
|
@@ -1328,9 +1427,38 @@ var FlatAtomSpace = class _FlatAtomSpace {
|
|
|
1328
1427
|
}
|
|
1329
1428
|
}
|
|
1330
1429
|
toArray() {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1430
|
+
if (this.arr === void 0) {
|
|
1431
|
+
const out = [];
|
|
1432
|
+
for (const fact of this.visibleFactIds()) out.push(this.decodeFact(fact));
|
|
1433
|
+
this.arr = out;
|
|
1434
|
+
}
|
|
1435
|
+
return this.arr;
|
|
1436
|
+
}
|
|
1437
|
+
/** Columnar mirror of the `&self` direct tally in eval.ts: over the visible facts the head filter
|
|
1438
|
+
* admits (head symbol `patternHead` or no symbol head, same filter as `candidatesFor`), count the
|
|
1439
|
+
* ones an all-distinct-variable pattern `(k $v..)` of `arity` items unifies with, without decoding
|
|
1440
|
+
* any fact. `iterated` is the admitted total (it advances the candidate counter). */
|
|
1441
|
+
countHeadArity(patternHead, arity) {
|
|
1442
|
+
const t = this.table;
|
|
1443
|
+
const headId = t.lookupHeadSym(patternHead);
|
|
1444
|
+
let count = 0;
|
|
1445
|
+
let iterated = 0;
|
|
1446
|
+
for (const fact of this.visibleFactIds()) {
|
|
1447
|
+
const fh = t.factHeadSym.get(fact);
|
|
1448
|
+
if (fh !== ABSENT && fh !== headId) continue;
|
|
1449
|
+
iterated += 1;
|
|
1450
|
+
const root = t.factRoot.get(fact);
|
|
1451
|
+
const kind = t.termKind.get(root);
|
|
1452
|
+
if (kind === TERM_VAR) {
|
|
1453
|
+
count += 1;
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
if (kind !== TERM_EXPR || t.termLen.get(root) !== arity) continue;
|
|
1457
|
+
if (fh !== ABSENT) count += 1;
|
|
1458
|
+
else if (arity > 0 && t.termKind.get(t.termData.get(t.termStart.get(root))) === TERM_VAR)
|
|
1459
|
+
count += 1;
|
|
1460
|
+
}
|
|
1461
|
+
return { count, iterated };
|
|
1334
1462
|
}
|
|
1335
1463
|
roundTrip(atom) {
|
|
1336
1464
|
return this.table.decodeTerm(this.table.insertAtom(atom));
|
|
@@ -2734,8 +2862,187 @@ function compileSymbolic(env, functor) {
|
|
|
2734
2862
|
};
|
|
2735
2863
|
return { kind: "symbolic", arity, clauseCount, run };
|
|
2736
2864
|
}
|
|
2865
|
+
var NONDET_CALL_CAP = 4e6;
|
|
2866
|
+
function nondetIsData(env, a) {
|
|
2867
|
+
if (a.kind !== "expr" || a.items.length === 0) return true;
|
|
2868
|
+
const h = a.items[0];
|
|
2869
|
+
if (h.kind === "expr" && h.items.length > 0) return false;
|
|
2870
|
+
if (h.kind === "sym" && (env.ruleIndex.has(h.name) || env.gt.has(h.name) || IMPURE_OPS.has(h.name)))
|
|
2871
|
+
return false;
|
|
2872
|
+
return a.items.every((x) => nondetIsData(env, x));
|
|
2873
|
+
}
|
|
2874
|
+
function nondetCall(env, functor, val) {
|
|
2875
|
+
if (val.kind !== "expr" || val.items.length === 0 || val.items[0].kind !== "sym")
|
|
2876
|
+
return void 0;
|
|
2877
|
+
const op = val.items[0].name;
|
|
2878
|
+
if (op === "match" && val.items.length === 4) {
|
|
2879
|
+
if (!nondetIsData(env, val.items[2]) || !nondetIsData(env, val.items[3])) return void 0;
|
|
2880
|
+
return {
|
|
2881
|
+
tag: "match",
|
|
2882
|
+
space: val.items[1],
|
|
2883
|
+
pattern: val.items[2],
|
|
2884
|
+
template: val.items[3]
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
if (op === functor) {
|
|
2888
|
+
const args = val.items.slice(1);
|
|
2889
|
+
if (!args.every((x) => nondetIsData(env, x))) return void 0;
|
|
2890
|
+
return { tag: "self", args };
|
|
2891
|
+
}
|
|
2892
|
+
return void 0;
|
|
2893
|
+
}
|
|
2894
|
+
function nondetUnwrap(env, functor, rhs) {
|
|
2895
|
+
const goals = [];
|
|
2896
|
+
let cur = rhs;
|
|
2897
|
+
for (; ; ) {
|
|
2898
|
+
if (cur.kind !== "expr" || cur.items.length === 0 || cur.items[0].kind !== "sym") break;
|
|
2899
|
+
const op = cur.items[0].name;
|
|
2900
|
+
if (op === "let*" && cur.items.length === 3 && cur.items[1].kind === "expr") {
|
|
2901
|
+
for (const pv of cur.items[1].items) {
|
|
2902
|
+
if (pv.kind !== "expr" || pv.items.length !== 2) return void 0;
|
|
2903
|
+
if (!nondetIsData(env, pv.items[0])) return void 0;
|
|
2904
|
+
const call = nondetCall(env, functor, pv.items[1]);
|
|
2905
|
+
if (call === void 0) return void 0;
|
|
2906
|
+
goals.push({ pat: pv.items[0], call });
|
|
2907
|
+
}
|
|
2908
|
+
cur = cur.items[2];
|
|
2909
|
+
continue;
|
|
2910
|
+
}
|
|
2911
|
+
if (op === "let" && cur.items.length === 4) {
|
|
2912
|
+
if (!nondetIsData(env, cur.items[1])) return void 0;
|
|
2913
|
+
const call = nondetCall(env, functor, cur.items[2]);
|
|
2914
|
+
if (call === void 0) return void 0;
|
|
2915
|
+
goals.push({ pat: cur.items[1], call });
|
|
2916
|
+
cur = cur.items[3];
|
|
2917
|
+
continue;
|
|
2918
|
+
}
|
|
2919
|
+
break;
|
|
2920
|
+
}
|
|
2921
|
+
const tailCall = nondetCall(env, functor, cur);
|
|
2922
|
+
if (tailCall !== void 0) return { goals, tail: tailCall };
|
|
2923
|
+
if (!nondetIsData(env, cur)) return void 0;
|
|
2924
|
+
return { goals, tail: { tag: "tpl", atom: cur } };
|
|
2925
|
+
}
|
|
2926
|
+
function compileNondet(env, functor) {
|
|
2927
|
+
if (env.varRulesVar.length !== 0) return void 0;
|
|
2928
|
+
const eqs = env.ruleIndex.get(functor);
|
|
2929
|
+
if (eqs === void 0 || eqs.length === 0) return void 0;
|
|
2930
|
+
const clauses = [];
|
|
2931
|
+
let arity;
|
|
2932
|
+
let hasCalls = false;
|
|
2933
|
+
for (const [lhs, rhs] of eqs) {
|
|
2934
|
+
if (lhs.kind !== "expr" || lhs.items.length === 0) return void 0;
|
|
2935
|
+
const h = lhs.items[0];
|
|
2936
|
+
if (h.kind !== "sym" || h.name !== functor) return void 0;
|
|
2937
|
+
const a = lhs.items.length - 1;
|
|
2938
|
+
if (arity === void 0) arity = a;
|
|
2939
|
+
else if (a !== arity) return void 0;
|
|
2940
|
+
if (!lhs.items.slice(1).every((x) => nondetIsData(env, x))) return void 0;
|
|
2941
|
+
const un = nondetUnwrap(env, functor, rhs);
|
|
2942
|
+
if (un === void 0) return void 0;
|
|
2943
|
+
if (un.goals.length > 0 || un.tail.tag !== "tpl") hasCalls = true;
|
|
2944
|
+
clauses.push({ lhs, goals: un.goals, tail: un.tail });
|
|
2945
|
+
}
|
|
2946
|
+
if (arity === void 0 || !hasCalls) return void 0;
|
|
2947
|
+
const clauseCount = clauses.length;
|
|
2948
|
+
const run = (envR, partAtoms, st, ops) => {
|
|
2949
|
+
const matchSolutions = ops.matchSolutions;
|
|
2950
|
+
if (matchSolutions === void 0) return void 0;
|
|
2951
|
+
const ctr = { c: st.counter };
|
|
2952
|
+
let dispatches = 0;
|
|
2953
|
+
const world = st.world;
|
|
2954
|
+
const walk = (b, a) => {
|
|
2955
|
+
let v = a;
|
|
2956
|
+
let hops = 0;
|
|
2957
|
+
while (v.kind === "var") {
|
|
2958
|
+
const next = lookupVal(b, v.name);
|
|
2959
|
+
if (next === void 0) return v;
|
|
2960
|
+
v = next;
|
|
2961
|
+
if (++hops > 1e4) throw BAIL;
|
|
2962
|
+
}
|
|
2963
|
+
return v;
|
|
2964
|
+
};
|
|
2965
|
+
const walkStar = (b, a) => {
|
|
2966
|
+
const v = walk(b, a);
|
|
2967
|
+
if (v.ground || v.kind !== "expr") return v;
|
|
2968
|
+
const its = v.items;
|
|
2969
|
+
let items = null;
|
|
2970
|
+
for (let i = 0; i < its.length; i++) {
|
|
2971
|
+
const it = its[i];
|
|
2972
|
+
const r = walkStar(b, it);
|
|
2973
|
+
if (items !== null) items.push(r);
|
|
2974
|
+
else if (r !== it) {
|
|
2975
|
+
items = its.slice(0, i);
|
|
2976
|
+
items.push(r);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
return items === null ? v : expr(items);
|
|
2980
|
+
};
|
|
2981
|
+
const resolve = (b, a, suffix) => walkStar(b, instantiate(b, a, suffix));
|
|
2982
|
+
const runMatch = (b, suffix, call) => {
|
|
2983
|
+
const m = matchSolutions(
|
|
2984
|
+
envR,
|
|
2985
|
+
{ counter: ctr.c, world },
|
|
2986
|
+
resolve(b, call.space, suffix),
|
|
2987
|
+
resolve(b, call.pattern, suffix),
|
|
2988
|
+
resolve(b, call.template, suffix)
|
|
2989
|
+
);
|
|
2990
|
+
if (m === void 0) throw BAIL;
|
|
2991
|
+
ctr.c += m.counterDelta;
|
|
2992
|
+
return m.pairs;
|
|
2993
|
+
};
|
|
2994
|
+
const solve = (clause, gi, b, suffix, out) => {
|
|
2995
|
+
if (gi === clause.goals.length) {
|
|
2996
|
+
if (clause.tail.tag === "tpl") {
|
|
2997
|
+
out.push([resolve(b, clause.tail.atom, suffix), b]);
|
|
2998
|
+
return;
|
|
2999
|
+
}
|
|
3000
|
+
const pairs2 = clause.tail.tag === "match" ? runMatch(b, suffix, clause.tail) : runCall(clause.tail.args.map((x) => resolve(b, x, suffix)));
|
|
3001
|
+
for (const [atom, vb] of pairs2)
|
|
3002
|
+
for (const mm of merge(b, vb)) if (!hasLoop(mm)) out.push([atom, mm]);
|
|
3003
|
+
return;
|
|
3004
|
+
}
|
|
3005
|
+
const goal = clause.goals[gi];
|
|
3006
|
+
const pat = resolve(b, goal.pat, suffix);
|
|
3007
|
+
const pairs = goal.call.tag === "match" ? runMatch(b, suffix, goal.call) : runCall(goal.call.args.map((x) => resolve(b, x, suffix)));
|
|
3008
|
+
for (const [atom, vb] of pairs)
|
|
3009
|
+
for (const withVal of merge(b, vb)) {
|
|
3010
|
+
if (hasLoop(withVal)) continue;
|
|
3011
|
+
for (const pm of matchAtoms(pat, atom))
|
|
3012
|
+
for (const mm of merge(withVal, pm))
|
|
3013
|
+
if (!hasLoop(mm)) solve(clause, gi + 1, mm, suffix, out);
|
|
3014
|
+
}
|
|
3015
|
+
};
|
|
3016
|
+
const runCall = (args) => {
|
|
3017
|
+
if (++dispatches > NONDET_CALL_CAP) throw BAIL;
|
|
3018
|
+
const app = expr([sym(functor), ...args]);
|
|
3019
|
+
const out = [];
|
|
3020
|
+
for (const clause of clauses) {
|
|
3021
|
+
const suffix = "#" + ctr.c;
|
|
3022
|
+
ctr.c += 1;
|
|
3023
|
+
for (const b0 of matchAtomsScoped(clause.lhs, app, suffix))
|
|
3024
|
+
if (!hasLoop(b0)) solve(clause, 0, b0, suffix, out);
|
|
3025
|
+
}
|
|
3026
|
+
return out;
|
|
3027
|
+
};
|
|
3028
|
+
try {
|
|
3029
|
+
const top = runCall(partAtoms);
|
|
3030
|
+
const results = top.map(([atom, bnd]) => ({ atom, bnd }));
|
|
3031
|
+
return { results, counterDelta: ctr.c - st.counter };
|
|
3032
|
+
} catch (e) {
|
|
3033
|
+
if (e === BAIL || e instanceof RangeError) return void 0;
|
|
3034
|
+
throw e;
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
3037
|
+
return { kind: "nondet", arity, clauseCount, run };
|
|
3038
|
+
}
|
|
2737
3039
|
var IMP_GROUNDED = /* @__PURE__ */ new Set(["==", "<", ">", "<=", ">=", "+", "-", "*", "%"]);
|
|
2738
|
-
var
|
|
3040
|
+
var DATA_DENY_CACHE;
|
|
3041
|
+
function dataDeny() {
|
|
3042
|
+
DATA_DENY_CACHE ??= /* @__PURE__ */ new Set([...KNOWN_OPS, ...IMPURE_OPS, "let*", "add-atom"]);
|
|
3043
|
+
return DATA_DENY_CACHE;
|
|
3044
|
+
}
|
|
3045
|
+
var EMPTY_VALUE = sym("Empty");
|
|
2739
3046
|
var addCounter = (st, n) => n === 0 ? st : { counter: st.counter + n, world: st.world };
|
|
2740
3047
|
var impBail = () => BAIL;
|
|
2741
3048
|
function impMeta(parts) {
|
|
@@ -2750,8 +3057,37 @@ function impMeta(parts) {
|
|
|
2750
3057
|
function impConst(atom) {
|
|
2751
3058
|
return { node: (_slots, st) => ({ value: atom, st }), directEffect: false, callees: /* @__PURE__ */ new Set() };
|
|
2752
3059
|
}
|
|
3060
|
+
function impAssembleExpr(parts) {
|
|
3061
|
+
return {
|
|
3062
|
+
node: (slots, st, ops) => {
|
|
3063
|
+
const out = [];
|
|
3064
|
+
let cur = st;
|
|
3065
|
+
for (const part of parts) {
|
|
3066
|
+
const r = part.node(slots, cur, ops);
|
|
3067
|
+
if (r === BAIL) return BAIL;
|
|
3068
|
+
out.push(r.value);
|
|
3069
|
+
cur = r.st;
|
|
3070
|
+
}
|
|
3071
|
+
return { value: expr(out), st: cur };
|
|
3072
|
+
},
|
|
3073
|
+
...impMeta(parts)
|
|
3074
|
+
};
|
|
3075
|
+
}
|
|
3076
|
+
function impEvalArgs(parts, slots, st, ops) {
|
|
3077
|
+
const vals = [];
|
|
3078
|
+
let cur = st;
|
|
3079
|
+
let empty = false;
|
|
3080
|
+
for (const part of parts) {
|
|
3081
|
+
const r = part.node(slots, cur, ops);
|
|
3082
|
+
if (r === BAIL) return BAIL;
|
|
3083
|
+
if (r.value === EMPTY_VALUE) empty = true;
|
|
3084
|
+
vals.push(r.value);
|
|
3085
|
+
cur = r.st;
|
|
3086
|
+
}
|
|
3087
|
+
return { vals, st: cur, empty };
|
|
3088
|
+
}
|
|
2753
3089
|
function isDataSymbol(env, name) {
|
|
2754
|
-
return !
|
|
3090
|
+
return !dataDeny().has(name) && !env.ruleIndex.has(name) && !env.gt.has(name);
|
|
2755
3091
|
}
|
|
2756
3092
|
function compileImpStaticAtom(env, a, scope) {
|
|
2757
3093
|
if (a.kind === "var") {
|
|
@@ -2771,21 +3107,7 @@ function compileImpStaticAtom(env, a, scope) {
|
|
|
2771
3107
|
if (head.kind === "sym" && !isDataSymbol(env, head.name)) return void 0;
|
|
2772
3108
|
const items = a.items.map((it) => compileImpStaticAtom(env, it, scope));
|
|
2773
3109
|
if (items.some((it) => it === void 0)) return void 0;
|
|
2774
|
-
|
|
2775
|
-
return {
|
|
2776
|
-
node: (slots, st, ops) => {
|
|
2777
|
-
const out = [];
|
|
2778
|
-
let cur = st;
|
|
2779
|
-
for (const part of parts) {
|
|
2780
|
-
const r = part.node(slots, cur, ops);
|
|
2781
|
-
if (r === BAIL) return BAIL;
|
|
2782
|
-
out.push(r.value);
|
|
2783
|
-
cur = r.st;
|
|
2784
|
-
}
|
|
2785
|
-
return { value: expr(out), st: cur };
|
|
2786
|
-
},
|
|
2787
|
-
...impMeta(parts)
|
|
2788
|
-
};
|
|
3110
|
+
return impAssembleExpr(items);
|
|
2789
3111
|
}
|
|
2790
3112
|
function compileImpGrounded(env, op, args, scope, holders) {
|
|
2791
3113
|
if (env.ruleIndex.has(op)) return void 0;
|
|
@@ -2794,22 +3116,73 @@ function compileImpGrounded(env, op, args, scope, holders) {
|
|
|
2794
3116
|
const compiled = parts;
|
|
2795
3117
|
return {
|
|
2796
3118
|
node: (slots, st, ops) => {
|
|
2797
|
-
const
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
vals.push(r.value);
|
|
2803
|
-
cur = r.st;
|
|
2804
|
-
}
|
|
2805
|
-
const gr = callGrounded(env.gt, op, vals);
|
|
2806
|
-
return gr.tag === "ok" && gr.results.length === 1 ? { value: gr.results[0], st: cur } : BAIL;
|
|
3119
|
+
const r = impEvalArgs(compiled, slots, st, ops);
|
|
3120
|
+
if (r === BAIL) return BAIL;
|
|
3121
|
+
if (r.empty) return { value: EMPTY_VALUE, st: r.st };
|
|
3122
|
+
const gr = callGrounded(env.gt, op, r.vals);
|
|
3123
|
+
return gr.tag === "ok" && gr.results.length === 1 ? { value: gr.results[0], st: r.st } : BAIL;
|
|
2807
3124
|
},
|
|
2808
3125
|
...impMeta(compiled)
|
|
2809
3126
|
};
|
|
2810
3127
|
}
|
|
3128
|
+
function impMatchInsideOnce(a) {
|
|
3129
|
+
if (a.kind !== "expr" || a.items.length !== 2) return void 0;
|
|
3130
|
+
const h = a.items[0];
|
|
3131
|
+
if (h.kind !== "sym" || h.name !== "once") return void 0;
|
|
3132
|
+
const inner = a.items[1];
|
|
3133
|
+
if (inner.kind !== "expr" || inner.items.length !== 4) return void 0;
|
|
3134
|
+
const ih = inner.items[0];
|
|
3135
|
+
return ih.kind === "sym" && ih.name === "match" ? inner : void 0;
|
|
3136
|
+
}
|
|
3137
|
+
function impEmptyCollapseMatch(a) {
|
|
3138
|
+
if (a.kind !== "expr" || a.items.length !== 3) return void 0;
|
|
3139
|
+
const h = a.items[0];
|
|
3140
|
+
if (h.kind !== "sym" || h.name !== "==") return void 0;
|
|
3141
|
+
const fromCollapse = (x) => {
|
|
3142
|
+
if (x.kind !== "expr" || x.items.length !== 2) return void 0;
|
|
3143
|
+
const ch = x.items[0];
|
|
3144
|
+
return ch.kind === "sym" && ch.name === "collapse" ? impMatchInsideOnce(x.items[1]) : void 0;
|
|
3145
|
+
};
|
|
3146
|
+
if (atomEq(a.items[1], emptyExpr)) return fromCollapse(a.items[2]);
|
|
3147
|
+
if (atomEq(a.items[2], emptyExpr)) return fromCollapse(a.items[1]);
|
|
3148
|
+
return void 0;
|
|
3149
|
+
}
|
|
3150
|
+
function compileImpAddIfAbsent(env, args, scope) {
|
|
3151
|
+
const match = impEmptyCollapseMatch(args[0]);
|
|
3152
|
+
if (match === void 0) return void 0;
|
|
3153
|
+
const add = args[1];
|
|
3154
|
+
const otherwise = args[2];
|
|
3155
|
+
if (add.kind !== "expr" || add.items.length !== 3) return void 0;
|
|
3156
|
+
const addHead = add.items[0];
|
|
3157
|
+
if (addHead.kind !== "sym" || addHead.name !== "add-atom") return void 0;
|
|
3158
|
+
if (otherwise.kind !== "expr" || otherwise.items.length !== 1) return void 0;
|
|
3159
|
+
const oh = otherwise.items[0];
|
|
3160
|
+
if (oh.kind !== "sym" || oh.name !== "empty") return void 0;
|
|
3161
|
+
if (!atomEq(match.items[1], add.items[1]) || !atomEq(match.items[2], match.items[3]) || !atomEq(match.items[2], add.items[2]))
|
|
3162
|
+
return void 0;
|
|
3163
|
+
const space = compileImpStaticAtom(env, add.items[1], scope);
|
|
3164
|
+
const atom = compileImpStaticAtom(env, add.items[2], scope);
|
|
3165
|
+
if (space === void 0 || atom === void 0) return void 0;
|
|
3166
|
+
return {
|
|
3167
|
+
node: (slots, st, ops) => {
|
|
3168
|
+
const addIfAbsent = ops.addIfAbsent;
|
|
3169
|
+
if (addIfAbsent === void 0) return BAIL;
|
|
3170
|
+
const s = space.node(slots, st, ops);
|
|
3171
|
+
if (s === BAIL) return BAIL;
|
|
3172
|
+
const a = atom.node(slots, s.st, ops);
|
|
3173
|
+
if (a === BAIL) return BAIL;
|
|
3174
|
+
const r = addIfAbsent(env, a.st, s.value, a.value);
|
|
3175
|
+
if (r === void 0) return BAIL;
|
|
3176
|
+
return { value: r.added ? emptyExpr : EMPTY_VALUE, st: r.state };
|
|
3177
|
+
},
|
|
3178
|
+
directEffect: true,
|
|
3179
|
+
callees: /* @__PURE__ */ new Set()
|
|
3180
|
+
};
|
|
3181
|
+
}
|
|
2811
3182
|
function compileImpIf(env, args, scope, holders) {
|
|
2812
3183
|
if (args.length !== 3 || (env.ruleIndex.get("if")?.length ?? 0) !== 2) return void 0;
|
|
3184
|
+
const addIfAbsent = compileImpAddIfAbsent(env, args, scope);
|
|
3185
|
+
if (addIfAbsent !== void 0) return addIfAbsent;
|
|
2813
3186
|
const cond = compileImpAtom(env, args[0], scope, holders);
|
|
2814
3187
|
const then_ = compileImpAtom(env, args[1], scope, holders);
|
|
2815
3188
|
const els = compileImpAtom(env, args[2], scope, holders);
|
|
@@ -2818,6 +3191,7 @@ function compileImpIf(env, args, scope, holders) {
|
|
|
2818
3191
|
node: (slots, st, ops, discard) => {
|
|
2819
3192
|
const c = cond.node(slots, st, ops);
|
|
2820
3193
|
if (c === BAIL) return BAIL;
|
|
3194
|
+
if (c.value === EMPTY_VALUE) return { value: EMPTY_VALUE, st: c.st };
|
|
2821
3195
|
const stIf = addCounter(c.st, 2);
|
|
2822
3196
|
if (c.value.kind !== "gnd" || c.value.value.g !== "bool") return BAIL;
|
|
2823
3197
|
return (c.value.value.b ? then_ : els).node(slots, stIf, ops, discard);
|
|
@@ -2841,6 +3215,7 @@ function compileImpLet(env, args, scope, holders) {
|
|
|
2841
3215
|
node: (slots, st, ops, discard) => {
|
|
2842
3216
|
const v = value.node(slots, st, ops);
|
|
2843
3217
|
if (v === BAIL) return BAIL;
|
|
3218
|
+
if (v.value === EMPTY_VALUE) return { value: EMPTY_VALUE, st: v.st };
|
|
2844
3219
|
const local = slots.slice();
|
|
2845
3220
|
local[slot] = v.value;
|
|
2846
3221
|
return body.node(local, addCounter(v.st, 1), ops, discard);
|
|
@@ -2875,6 +3250,7 @@ function compileImpLetStar(env, args, scope, holders) {
|
|
|
2875
3250
|
for (const binding of bindings) {
|
|
2876
3251
|
const v = binding.value.node(local, cur, ops);
|
|
2877
3252
|
if (v === BAIL) return BAIL;
|
|
3253
|
+
if (v.value === EMPTY_VALUE) return { value: EMPTY_VALUE, st: v.st };
|
|
2878
3254
|
local[binding.slot] = v.value;
|
|
2879
3255
|
cur = addCounter(addCounter(v.st, 1), 1);
|
|
2880
3256
|
}
|
|
@@ -2904,6 +3280,72 @@ function compileImpAddAtom(env, args, scope) {
|
|
|
2904
3280
|
callees: /* @__PURE__ */ new Set()
|
|
2905
3281
|
};
|
|
2906
3282
|
}
|
|
3283
|
+
function compileImpPatternAtom(a, scope) {
|
|
3284
|
+
if (a.kind === "var") {
|
|
3285
|
+
const slot = scope.vars.get(a.name);
|
|
3286
|
+
if (slot === void 0) return impConst(a);
|
|
3287
|
+
return {
|
|
3288
|
+
node: (slots, st) => ({ value: slots[slot], st }),
|
|
3289
|
+
directEffect: false,
|
|
3290
|
+
callees: /* @__PURE__ */ new Set()
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
if (a.kind !== "expr" || a.items.length === 0) return impConst(a);
|
|
3294
|
+
return impAssembleExpr(a.items.map((it) => compileImpPatternAtom(it, scope)));
|
|
3295
|
+
}
|
|
3296
|
+
function compileImpCaseMatch(env, args, scope, holders) {
|
|
3297
|
+
if (args.length !== 2 || (env.ruleIndex.get("case")?.length ?? 0) !== 1) return void 0;
|
|
3298
|
+
const scrut = args[0];
|
|
3299
|
+
if (scrut.kind !== "expr" || scrut.items.length !== 4) return void 0;
|
|
3300
|
+
const sh = scrut.items[0];
|
|
3301
|
+
if (sh.kind !== "sym" || sh.name !== "match") return void 0;
|
|
3302
|
+
const pairs = args[1];
|
|
3303
|
+
if (pairs.kind !== "expr" || pairs.items.length !== 1) return void 0;
|
|
3304
|
+
const branch = pairs.items[0];
|
|
3305
|
+
if (branch.kind !== "expr" || branch.items.length !== 2 || branch.items[0].kind !== "var")
|
|
3306
|
+
return void 0;
|
|
3307
|
+
const space = compileImpStaticAtom(env, scrut.items[1], scope);
|
|
3308
|
+
if (space === void 0) return void 0;
|
|
3309
|
+
const pattern = compileImpPatternAtom(scrut.items[2], scope);
|
|
3310
|
+
const template = compileImpPatternAtom(scrut.items[3], scope);
|
|
3311
|
+
const slot = scope.len;
|
|
3312
|
+
const branchScope = {
|
|
3313
|
+
vars: new Map(scope.vars).set(branch.items[0].name, slot),
|
|
3314
|
+
len: slot + 1
|
|
3315
|
+
};
|
|
3316
|
+
const body = compileImpAtom(env, branch.items[1], branchScope, holders);
|
|
3317
|
+
if (body === void 0) return void 0;
|
|
3318
|
+
return {
|
|
3319
|
+
node: (slots, st, ops, discard) => {
|
|
3320
|
+
const matchSolutions = ops.matchSolutions;
|
|
3321
|
+
if (matchSolutions === void 0) return BAIL;
|
|
3322
|
+
const s = space.node(slots, st, ops);
|
|
3323
|
+
if (s === BAIL) return BAIL;
|
|
3324
|
+
const p = pattern.node(slots, s.st, ops);
|
|
3325
|
+
if (p === BAIL) return BAIL;
|
|
3326
|
+
const t = template.node(slots, p.st, ops);
|
|
3327
|
+
if (t === BAIL) return BAIL;
|
|
3328
|
+
const m = matchSolutions(env, t.st, s.value, p.value, t.value);
|
|
3329
|
+
if (m === void 0) return BAIL;
|
|
3330
|
+
let cur = addCounter(t.st, m.counterDelta);
|
|
3331
|
+
const local = slots.slice();
|
|
3332
|
+
let survived;
|
|
3333
|
+
for (const [value] of m.pairs) {
|
|
3334
|
+
local[slot] = value;
|
|
3335
|
+
const r = body.node(local, cur, ops, discard);
|
|
3336
|
+
if (r === BAIL) return BAIL;
|
|
3337
|
+
cur = r.st;
|
|
3338
|
+
if (r.value !== EMPTY_VALUE) {
|
|
3339
|
+
if (survived !== void 0) return BAIL;
|
|
3340
|
+
survived = r.value;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
return { value: survived ?? EMPTY_VALUE, st: cur };
|
|
3344
|
+
},
|
|
3345
|
+
directEffect: true,
|
|
3346
|
+
callees: body.callees
|
|
3347
|
+
};
|
|
3348
|
+
}
|
|
2907
3349
|
function compileImpCall(env, op, args, scope, holders) {
|
|
2908
3350
|
const h = holders.get(op);
|
|
2909
3351
|
if (h === void 0 || args.length !== h.arity) return void 0;
|
|
@@ -2913,15 +3355,10 @@ function compileImpCall(env, op, args, scope, holders) {
|
|
|
2913
3355
|
const meta = impMeta(parts);
|
|
2914
3356
|
return {
|
|
2915
3357
|
node: (slots, st, ops, discard) => {
|
|
2916
|
-
const
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
if (r === BAIL) return BAIL;
|
|
2921
|
-
vals.push(r.value);
|
|
2922
|
-
cur = r.st;
|
|
2923
|
-
}
|
|
2924
|
-
return h.run(vals, cur, ops, discard);
|
|
3358
|
+
const r = impEvalArgs(parts, slots, st, ops);
|
|
3359
|
+
if (r === BAIL) return BAIL;
|
|
3360
|
+
if (r.empty) return { value: EMPTY_VALUE, st: r.st };
|
|
3361
|
+
return h.run(r.vals, r.st, ops, discard);
|
|
2925
3362
|
},
|
|
2926
3363
|
directEffect: meta.directEffect,
|
|
2927
3364
|
callees: /* @__PURE__ */ new Set([...meta.callees, op])
|
|
@@ -2943,12 +3380,15 @@ function compileImpTuple(env, items, scope, holders) {
|
|
|
2943
3380
|
return { value: emptyExpr, st: cur };
|
|
2944
3381
|
}
|
|
2945
3382
|
const out = [];
|
|
3383
|
+
let empty = false;
|
|
2946
3384
|
for (const part of compiled) {
|
|
2947
3385
|
const r = part.node(slots, cur, ops);
|
|
2948
3386
|
if (r === BAIL) return BAIL;
|
|
3387
|
+
if (r.value === EMPTY_VALUE) empty = true;
|
|
2949
3388
|
out.push(r.value);
|
|
2950
3389
|
cur = r.st;
|
|
2951
3390
|
}
|
|
3391
|
+
if (empty) return { value: EMPTY_VALUE, st: cur };
|
|
2952
3392
|
return { value: expr(out), st: cur };
|
|
2953
3393
|
},
|
|
2954
3394
|
...impMeta(compiled)
|
|
@@ -2967,6 +3407,7 @@ function compileImpAtom(env, a, scope, holders) {
|
|
|
2967
3407
|
if (op === "let") return compileImpLet(env, args, scope, holders);
|
|
2968
3408
|
if (op === "let*") return compileImpLetStar(env, args, scope, holders);
|
|
2969
3409
|
if (op === "add-atom") return compileImpAddAtom(env, args, scope);
|
|
3410
|
+
if (op === "case") return compileImpCaseMatch(env, args, scope, holders);
|
|
2970
3411
|
if (IMP_GROUNDED.has(op)) return compileImpGrounded(env, op, args, scope, holders);
|
|
2971
3412
|
const call = compileImpCall(env, op, args, scope, holders);
|
|
2972
3413
|
if (call !== void 0) return call;
|
|
@@ -3112,6 +3553,11 @@ function compileEnv(env) {
|
|
|
3112
3553
|
if (symbolic !== void 0) compiled.set(f, symbolic);
|
|
3113
3554
|
}
|
|
3114
3555
|
compileImperative(env, compiled);
|
|
3556
|
+
for (const f of env.ruleIndex.keys()) {
|
|
3557
|
+
if (compiled.has(f)) continue;
|
|
3558
|
+
const nondet = compileNondet(env, f);
|
|
3559
|
+
if (nondet !== void 0) compiled.set(f, nondet);
|
|
3560
|
+
}
|
|
3115
3561
|
return compiled;
|
|
3116
3562
|
}
|
|
3117
3563
|
}
|
|
@@ -3121,10 +3567,16 @@ function runCompiled(env, op, partAtoms, st, ops, discard) {
|
|
|
3121
3567
|
if (h === void 0 || partAtoms.length !== h.arity) return void 0;
|
|
3122
3568
|
if (h.kind === "rewrite") return h.run(partAtoms);
|
|
3123
3569
|
if (h.kind === "symbolic") return h.run(partAtoms, st.counter);
|
|
3570
|
+
if (h.kind === "nondet") {
|
|
3571
|
+
if (ops === void 0) return void 0;
|
|
3572
|
+
return h.run(env, partAtoms, st, ops);
|
|
3573
|
+
}
|
|
3124
3574
|
if (h.kind === "imperative") {
|
|
3125
3575
|
if (ops === void 0) return void 0;
|
|
3126
3576
|
const r = h.run(partAtoms, st, ops, discard);
|
|
3127
|
-
|
|
3577
|
+
if (r === BAIL) return void 0;
|
|
3578
|
+
if (r.value === EMPTY_VALUE) return { results: [], counterDelta: 0, state: r.st };
|
|
3579
|
+
return { results: [{ atom: r.value, bnd: emptyBindings }], counterDelta: 0, state: r.st };
|
|
3128
3580
|
}
|
|
3129
3581
|
const vals = [];
|
|
3130
3582
|
for (const a of partAtoms) {
|
|
@@ -4093,7 +4545,7 @@ function* matchCandidates(env, w, pInst) {
|
|
|
4093
4545
|
}
|
|
4094
4546
|
cands.push(...env.varHeadedFacts);
|
|
4095
4547
|
if (pInst.ground && logNonGround(w.selfExtra) === 0 && (w.flatSelfExtra?.nonGroundCount ?? 0) === 0 && w.store.size === 0) {
|
|
4096
|
-
const c = idxCount(logGroundIdx(w.selfExtra), pInst);
|
|
4548
|
+
const c = w.selfExtra === null ? 0 : idxCount(logGroundIdx(w.selfExtra), pInst);
|
|
4097
4549
|
for (const atom of cands) yield atom;
|
|
4098
4550
|
const flatCount = w.flatSelfExtra?.exactCount(pInst) ?? 0;
|
|
4099
4551
|
for (let i = 0; i < c + flatCount; i++) yield pInst;
|
|
@@ -4730,8 +5182,9 @@ function appendSpace(env, w0, name, atoms) {
|
|
|
4730
5182
|
if (env.useFlatAtomspace === true) {
|
|
4731
5183
|
if (flatSelfExtra !== void 0 || logSize(selfExtra) === 0) {
|
|
4732
5184
|
const base = flatSelfExtra ?? FlatAtomSpace.empty();
|
|
4733
|
-
|
|
4734
|
-
|
|
5185
|
+
const appended = base.appendAll(atoms);
|
|
5186
|
+
if (appended !== void 0) {
|
|
5187
|
+
flatSelfExtra = appended;
|
|
4735
5188
|
} else {
|
|
4736
5189
|
selfExtra = logFromArray([...base.toArray(), ...logToArray(selfExtra), ...atoms]);
|
|
4737
5190
|
flatSelfExtra = void 0;
|
|
@@ -4788,7 +5241,52 @@ function compiledAddAtom(env, st, space, added) {
|
|
|
4788
5241
|
if (name === void 0) return void 0;
|
|
4789
5242
|
return { counter: st.counter, world: appendSpace(env, st.world, name, [added]) };
|
|
4790
5243
|
}
|
|
4791
|
-
|
|
5244
|
+
function compiledMatchSolutions(env, st, space, pattern, template) {
|
|
5245
|
+
const { getCandidates, patterns } = matchSetup(env, st, space, pattern, emptyBindings);
|
|
5246
|
+
if (patterns.length !== 1) return void 0;
|
|
5247
|
+
const pat = patterns[0];
|
|
5248
|
+
const { endState } = matchSingleEndState(env, getCandidates, pat, template, st, emptyBindings);
|
|
5249
|
+
const pairs = [];
|
|
5250
|
+
for (const m of matchSingleSolutions(env, getCandidates, pat, st, emptyBindings))
|
|
5251
|
+
pairs.push([inst(env, m, template), m]);
|
|
5252
|
+
return { pairs, counterDelta: endState.counter - st.counter };
|
|
5253
|
+
}
|
|
5254
|
+
function compiledAddIfAbsent(env, st, space, atom) {
|
|
5255
|
+
if (!atom.ground || opOf(atom) === "=") return void 0;
|
|
5256
|
+
const w = st.world;
|
|
5257
|
+
if (w.store.size !== 0) return void 0;
|
|
5258
|
+
const name = spaceName(w, space);
|
|
5259
|
+
if (name === void 0) return void 0;
|
|
5260
|
+
if (name === "&self") {
|
|
5261
|
+
const k = headKey(atom);
|
|
5262
|
+
if (k === void 0) return void 0;
|
|
5263
|
+
if (env.varHeadedFacts.length !== 0 || (env.factIndex.get(k)?.length ?? 0) !== 0)
|
|
5264
|
+
return void 0;
|
|
5265
|
+
if (logNonGround(w.selfExtra) !== 0 || (w.flatSelfExtra?.nonGroundCount ?? 0) !== 0)
|
|
5266
|
+
return void 0;
|
|
5267
|
+
const size2 = logSize(w.selfExtra) + (w.flatSelfExtra?.size ?? 0);
|
|
5268
|
+
const checked2 = { counter: st.counter + size2, world: w };
|
|
5269
|
+
const present = idxCount(logGroundIdx(w.selfExtra), atom) + (w.flatSelfExtra?.exactCount(atom) ?? 0);
|
|
5270
|
+
if (present !== 0) return { added: false, state: checked2 };
|
|
5271
|
+
return {
|
|
5272
|
+
added: true,
|
|
5273
|
+
state: { counter: checked2.counter, world: appendSpace(env, w, "&self", [atom]) }
|
|
5274
|
+
};
|
|
5275
|
+
}
|
|
5276
|
+
const log = w.spaces.get(name) ?? emptyLog;
|
|
5277
|
+
if (logNonGround(log) !== 0) return void 0;
|
|
5278
|
+
const checked = { counter: st.counter + logSize(log), world: w };
|
|
5279
|
+
if (idxCount(logGroundIdx(log), atom) !== 0) return { added: false, state: checked };
|
|
5280
|
+
return {
|
|
5281
|
+
added: true,
|
|
5282
|
+
state: { counter: checked.counter, world: appendSpace(env, w, name, [atom]) }
|
|
5283
|
+
};
|
|
5284
|
+
}
|
|
5285
|
+
var COMPILED_IMPURE_OPS = {
|
|
5286
|
+
addAtom: compiledAddAtom,
|
|
5287
|
+
matchSolutions: compiledMatchSolutions,
|
|
5288
|
+
addIfAbsent: compiledAddIfAbsent
|
|
5289
|
+
};
|
|
4792
5290
|
function* getTypeOpG(env, fuel, st, prev, xi, b) {
|
|
4793
5291
|
const emit = function* (st0) {
|
|
4794
5292
|
let acc = [];
|
|
@@ -5535,7 +6033,7 @@ function tryCountAggregate(env, st, bnd, match) {
|
|
|
5535
6033
|
const unifies = (a) => a.kind === "var" || a.kind === "expr" && a.items.length === arity && (headKey(a) === k || a.items[0].kind === "var");
|
|
5536
6034
|
const w = st.world;
|
|
5537
6035
|
const sn = spaceName(w, inst(env, bnd, match.items[1]));
|
|
5538
|
-
if ((sn === void 0 || sn === "&self") && w.store.size === 0 &&
|
|
6036
|
+
if ((sn === void 0 || sn === "&self") && w.store.size === 0 && env.varHeadedFacts.length === 0 && (env.factIndex.get(k)?.length ?? 0) === 0) {
|
|
5539
6037
|
let count2 = 0;
|
|
5540
6038
|
let iterated2 = 0;
|
|
5541
6039
|
for (let p = w.selfExtra; p !== null; p = p.prev) {
|
|
@@ -5545,6 +6043,11 @@ function tryCountAggregate(env, st, bnd, match) {
|
|
|
5545
6043
|
if (unifies(p.atom)) count2 += 1;
|
|
5546
6044
|
}
|
|
5547
6045
|
}
|
|
6046
|
+
if (w.flatSelfExtra !== void 0) {
|
|
6047
|
+
const flat = w.flatSelfExtra.countHeadArity(k, arity);
|
|
6048
|
+
count2 += flat.count;
|
|
6049
|
+
iterated2 += flat.iterated;
|
|
6050
|
+
}
|
|
5548
6051
|
return { count: count2, iterated: iterated2 };
|
|
5549
6052
|
}
|
|
5550
6053
|
const source = getCandidates(pat);
|
|
@@ -5822,7 +6325,7 @@ function* mettaEvalG(env, fuel, st, bnd, a) {
|
|
|
5822
6325
|
out.push([errFound, partB]);
|
|
5823
6326
|
continue;
|
|
5824
6327
|
}
|
|
5825
|
-
const wApp = makeExpr(env, [sym(op), ...partAtoms]);
|
|
6328
|
+
const wApp = partAtoms.every((p, i) => p === args[i]) ? lw : makeExpr(env, [sym(op), ...partAtoms]);
|
|
5826
6329
|
if (env.curry && partAtoms.length >= 1) {
|
|
5827
6330
|
const ar = functionArity(env, cur2.world, op);
|
|
5828
6331
|
if (ar !== void 0 && partAtoms.length < ar) {
|