@metta-ts/core 1.0.0
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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/index.d.ts +632 -0
- package/dist/index.js +4777 -0
- package/package.json +51 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4777 @@
|
|
|
1
|
+
// src/number.ts
|
|
2
|
+
var MAX = BigInt(Number.MAX_SAFE_INTEGER);
|
|
3
|
+
var MIN = BigInt(Number.MIN_SAFE_INTEGER);
|
|
4
|
+
function canonInt(n) {
|
|
5
|
+
if (typeof n === "bigint") return n >= MIN && n <= MAX ? Number(n) : n;
|
|
6
|
+
return n;
|
|
7
|
+
}
|
|
8
|
+
function addInt(x, y) {
|
|
9
|
+
if (typeof x === "number" && typeof y === "number") {
|
|
10
|
+
const r = x + y;
|
|
11
|
+
return Number.isSafeInteger(r) ? r : canonInt(BigInt(x) + BigInt(y));
|
|
12
|
+
}
|
|
13
|
+
return canonInt(BigInt(x) + BigInt(y));
|
|
14
|
+
}
|
|
15
|
+
function subInt(x, y) {
|
|
16
|
+
if (typeof x === "number" && typeof y === "number") {
|
|
17
|
+
const r = x - y;
|
|
18
|
+
return Number.isSafeInteger(r) ? r : canonInt(BigInt(x) - BigInt(y));
|
|
19
|
+
}
|
|
20
|
+
return canonInt(BigInt(x) - BigInt(y));
|
|
21
|
+
}
|
|
22
|
+
function mulInt(x, y) {
|
|
23
|
+
if (typeof x === "number" && typeof y === "number") {
|
|
24
|
+
const r = x * y;
|
|
25
|
+
return Number.isSafeInteger(r) ? r : canonInt(BigInt(x) * BigInt(y));
|
|
26
|
+
}
|
|
27
|
+
return canonInt(BigInt(x) * BigInt(y));
|
|
28
|
+
}
|
|
29
|
+
function intDiv(x, y) {
|
|
30
|
+
if (typeof x === "number" && typeof y === "number") return Math.trunc(x / y);
|
|
31
|
+
return canonInt(BigInt(x) / BigInt(y));
|
|
32
|
+
}
|
|
33
|
+
function intMod(x, y) {
|
|
34
|
+
if (typeof x === "number" && typeof y === "number") return x % y;
|
|
35
|
+
return canonInt(BigInt(x) % BigInt(y));
|
|
36
|
+
}
|
|
37
|
+
function intAbs(n) {
|
|
38
|
+
if (typeof n === "bigint") return n < 0n ? -n : n;
|
|
39
|
+
return Math.abs(n);
|
|
40
|
+
}
|
|
41
|
+
function isZero(n) {
|
|
42
|
+
return typeof n === "bigint" ? n === 0n : n === 0;
|
|
43
|
+
}
|
|
44
|
+
function toF64(n) {
|
|
45
|
+
return typeof n === "bigint" ? Number(n) : n;
|
|
46
|
+
}
|
|
47
|
+
function cmpIntVal(a, b) {
|
|
48
|
+
if (typeof a === "bigint" || typeof b === "bigint") {
|
|
49
|
+
const x = BigInt(a);
|
|
50
|
+
const y = BigInt(b);
|
|
51
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
52
|
+
}
|
|
53
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/atom.ts
|
|
57
|
+
function groundEq(a, b) {
|
|
58
|
+
if (a.g !== b.g) return false;
|
|
59
|
+
switch (a.g) {
|
|
60
|
+
case "int":
|
|
61
|
+
case "float":
|
|
62
|
+
return a.n === b.n;
|
|
63
|
+
case "str":
|
|
64
|
+
return a.s === b.s;
|
|
65
|
+
case "bool":
|
|
66
|
+
return a.b === b.b;
|
|
67
|
+
case "unit":
|
|
68
|
+
return true;
|
|
69
|
+
case "error":
|
|
70
|
+
return a.msg === b.msg;
|
|
71
|
+
case "ext": {
|
|
72
|
+
const e = b;
|
|
73
|
+
return a.kind === e.kind && a.id === e.id;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
var SYM_INTERN = /* @__PURE__ */ new Map();
|
|
78
|
+
function sym(name) {
|
|
79
|
+
let s = SYM_INTERN.get(name);
|
|
80
|
+
if (s === void 0) {
|
|
81
|
+
s = {
|
|
82
|
+
kind: "sym",
|
|
83
|
+
name,
|
|
84
|
+
items: void 0,
|
|
85
|
+
value: void 0,
|
|
86
|
+
typ: void 0,
|
|
87
|
+
exec: void 0,
|
|
88
|
+
match: void 0,
|
|
89
|
+
ground: true
|
|
90
|
+
};
|
|
91
|
+
SYM_INTERN.set(name, s);
|
|
92
|
+
}
|
|
93
|
+
return s;
|
|
94
|
+
}
|
|
95
|
+
function variable(name) {
|
|
96
|
+
return {
|
|
97
|
+
kind: "var",
|
|
98
|
+
name,
|
|
99
|
+
items: void 0,
|
|
100
|
+
value: void 0,
|
|
101
|
+
typ: void 0,
|
|
102
|
+
exec: void 0,
|
|
103
|
+
match: void 0,
|
|
104
|
+
ground: false
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function expr(items) {
|
|
108
|
+
let ground = true;
|
|
109
|
+
for (const it of items)
|
|
110
|
+
if (!it.ground) {
|
|
111
|
+
ground = false;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
kind: "expr",
|
|
116
|
+
name: void 0,
|
|
117
|
+
items,
|
|
118
|
+
value: void 0,
|
|
119
|
+
typ: void 0,
|
|
120
|
+
exec: void 0,
|
|
121
|
+
match: void 0,
|
|
122
|
+
ground
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function groundType(v) {
|
|
126
|
+
switch (v.g) {
|
|
127
|
+
case "int":
|
|
128
|
+
case "float":
|
|
129
|
+
return sym("Number");
|
|
130
|
+
case "str":
|
|
131
|
+
return sym("String");
|
|
132
|
+
case "bool":
|
|
133
|
+
return sym("Bool");
|
|
134
|
+
default:
|
|
135
|
+
return sym("Grounded");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function gnd(value, typ = groundType(value), exec, match) {
|
|
139
|
+
return { kind: "gnd", name: void 0, items: void 0, value, typ, exec, match, ground: true };
|
|
140
|
+
}
|
|
141
|
+
var gint = (n) => gnd({ g: "int", n: canonInt(n) });
|
|
142
|
+
var gfloat = (n) => gnd({ g: "float", n });
|
|
143
|
+
var gstr = (s) => gnd({ g: "str", s });
|
|
144
|
+
var gbool = (b) => gnd({ g: "bool", b });
|
|
145
|
+
var gunit = gnd({ g: "unit" });
|
|
146
|
+
function metaType(a) {
|
|
147
|
+
switch (a.kind) {
|
|
148
|
+
case "sym":
|
|
149
|
+
return "Symbol";
|
|
150
|
+
case "var":
|
|
151
|
+
return "Variable";
|
|
152
|
+
case "expr":
|
|
153
|
+
return "Expression";
|
|
154
|
+
case "gnd":
|
|
155
|
+
return "Grounded";
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
var exprHashCache = /* @__PURE__ */ new WeakMap();
|
|
159
|
+
var mixHash = (h, x) => {
|
|
160
|
+
h = Math.imul(h ^ x, 2654435761);
|
|
161
|
+
return (h ^ h >>> 15) >>> 0;
|
|
162
|
+
};
|
|
163
|
+
var strHash = (s) => {
|
|
164
|
+
let h = 2166136261;
|
|
165
|
+
for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 16777619);
|
|
166
|
+
return h >>> 0;
|
|
167
|
+
};
|
|
168
|
+
function groundHash(g) {
|
|
169
|
+
switch (g.g) {
|
|
170
|
+
case "int":
|
|
171
|
+
return strHash("i" + g.n.toString());
|
|
172
|
+
case "float":
|
|
173
|
+
return strHash("f" + g.n.toString());
|
|
174
|
+
case "str":
|
|
175
|
+
return strHash("s" + g.s);
|
|
176
|
+
case "bool":
|
|
177
|
+
return g.b ? 1 : 2;
|
|
178
|
+
case "unit":
|
|
179
|
+
return 3;
|
|
180
|
+
case "error":
|
|
181
|
+
return strHash("e" + g.msg);
|
|
182
|
+
case "ext":
|
|
183
|
+
return strHash("x" + g.kind + "\0" + g.id);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function hashOf(a) {
|
|
187
|
+
switch (a.kind) {
|
|
188
|
+
case "sym":
|
|
189
|
+
return mixHash(1398361410, strHash(a.name));
|
|
190
|
+
// tag "SYMB"
|
|
191
|
+
case "var":
|
|
192
|
+
return mixHash(1447121474, strHash(a.name));
|
|
193
|
+
// tag "VARB"
|
|
194
|
+
case "gnd":
|
|
195
|
+
return mixHash(1196311620, groundHash(a.value));
|
|
196
|
+
// tag "GNDD"
|
|
197
|
+
case "expr": {
|
|
198
|
+
const cached = exprHashCache.get(a);
|
|
199
|
+
if (cached !== void 0) return cached;
|
|
200
|
+
let acc = 1163415634;
|
|
201
|
+
acc = mixHash(acc, a.items.length);
|
|
202
|
+
for (const it of a.items) acc = mixHash(acc, hashOf(it));
|
|
203
|
+
exprHashCache.set(a, acc);
|
|
204
|
+
return acc;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function atomSize(a) {
|
|
209
|
+
if (a.kind === "expr") {
|
|
210
|
+
let n = 1;
|
|
211
|
+
for (const it of a.items) n += atomSize(it);
|
|
212
|
+
return n;
|
|
213
|
+
}
|
|
214
|
+
return 1;
|
|
215
|
+
}
|
|
216
|
+
function atomVars(a, out = []) {
|
|
217
|
+
collectVars(a, out, new Set(out));
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
function collectVars(a, out, seen) {
|
|
221
|
+
if (a.ground) return;
|
|
222
|
+
switch (a.kind) {
|
|
223
|
+
case "var":
|
|
224
|
+
if (!seen.has(a.name)) {
|
|
225
|
+
seen.add(a.name);
|
|
226
|
+
out.push(a.name);
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
case "expr":
|
|
230
|
+
for (const it of a.items) collectVars(it, out, seen);
|
|
231
|
+
break;
|
|
232
|
+
default:
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
var emptyExpr = expr([]);
|
|
237
|
+
function isErrorAtom(a) {
|
|
238
|
+
return a.kind === "expr" && a.items.length >= 1 && a.items[0].kind === "sym" && a.items[0].name === "Error";
|
|
239
|
+
}
|
|
240
|
+
var isExpr = (a) => a.kind === "expr";
|
|
241
|
+
var isVar = (a) => a.kind === "var";
|
|
242
|
+
var isSym = (a) => a.kind === "sym";
|
|
243
|
+
var isGnd = (a) => a.kind === "gnd";
|
|
244
|
+
function atomEq(a, b) {
|
|
245
|
+
if (a === b) return true;
|
|
246
|
+
if (a.kind !== b.kind) return false;
|
|
247
|
+
switch (a.kind) {
|
|
248
|
+
case "sym":
|
|
249
|
+
return false;
|
|
250
|
+
// interned: a !== b means different symbols
|
|
251
|
+
case "var":
|
|
252
|
+
return a.name === b.name;
|
|
253
|
+
case "gnd":
|
|
254
|
+
return groundEq(a.value, b.value);
|
|
255
|
+
case "expr": {
|
|
256
|
+
const bi = b.items;
|
|
257
|
+
if (a.items.length !== bi.length) return false;
|
|
258
|
+
for (let i = 0; i < a.items.length; i++) {
|
|
259
|
+
const ai = a.items[i];
|
|
260
|
+
const bii = bi[i];
|
|
261
|
+
if (!atomEq(ai, bii)) return false;
|
|
262
|
+
}
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/tokenizer.ts
|
|
269
|
+
var Tokenizer = class {
|
|
270
|
+
entries = [];
|
|
271
|
+
/** Register a (regex, constructor). Order matters: the first matching pattern wins. */
|
|
272
|
+
register(re, make) {
|
|
273
|
+
this.entries.push({ re, make });
|
|
274
|
+
}
|
|
275
|
+
/** A grounded atom for `token`, or undefined if no pattern matches (caller falls back to Symbol). */
|
|
276
|
+
tokenize(token) {
|
|
277
|
+
for (const e of this.entries) if (e.re.test(token)) return e.make(token);
|
|
278
|
+
return void 0;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// src/parser.ts
|
|
283
|
+
var isWs = (c) => /\s/.test(c);
|
|
284
|
+
var isDelim = (c) => c === "(" || c === ")" || c === '"' || c === ";" || isWs(c);
|
|
285
|
+
var Cursor = class {
|
|
286
|
+
constructor(s, tk) {
|
|
287
|
+
this.s = s;
|
|
288
|
+
this.tk = tk;
|
|
289
|
+
}
|
|
290
|
+
s;
|
|
291
|
+
tk;
|
|
292
|
+
pos = 0;
|
|
293
|
+
done() {
|
|
294
|
+
return this.pos >= this.s.length;
|
|
295
|
+
}
|
|
296
|
+
peek() {
|
|
297
|
+
return this.s[this.pos];
|
|
298
|
+
}
|
|
299
|
+
skipTrivia() {
|
|
300
|
+
while (!this.done()) {
|
|
301
|
+
const c = this.peek();
|
|
302
|
+
if (isWs(c)) {
|
|
303
|
+
this.pos++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (c === ";") {
|
|
307
|
+
while (!this.done() && this.peek() !== "\n") this.pos++;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
function readString(c) {
|
|
315
|
+
c.pos++;
|
|
316
|
+
let out = "";
|
|
317
|
+
while (!c.done() && c.peek() !== '"') {
|
|
318
|
+
if (c.peek() === "\\" && c.pos + 1 < c.s.length) {
|
|
319
|
+
const next = c.s[c.pos + 1];
|
|
320
|
+
if (next === "u" && c.pos + 6 <= c.s.length) {
|
|
321
|
+
const hex = c.s.slice(c.pos + 2, c.pos + 6);
|
|
322
|
+
if (/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
323
|
+
out += String.fromCharCode(parseInt(hex, 16));
|
|
324
|
+
c.pos += 6;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
out += next === "n" ? "\n" : next === "t" ? " " : next === "r" ? "\r" : next === "b" ? "\b" : next === "f" ? "\f" : next;
|
|
329
|
+
c.pos += 2;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
out += c.peek();
|
|
333
|
+
c.pos++;
|
|
334
|
+
}
|
|
335
|
+
if (c.done()) throw new Error("unterminated string literal in MeTTa source");
|
|
336
|
+
c.pos++;
|
|
337
|
+
return gstr(out);
|
|
338
|
+
}
|
|
339
|
+
var MAX_DEPTH = 4096;
|
|
340
|
+
function readWord(c) {
|
|
341
|
+
let out = "";
|
|
342
|
+
while (!c.done() && !isDelim(c.peek())) {
|
|
343
|
+
out += c.peek();
|
|
344
|
+
c.pos++;
|
|
345
|
+
}
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
function readAtom(c, depth = 0) {
|
|
349
|
+
c.skipTrivia();
|
|
350
|
+
const ch = c.peek();
|
|
351
|
+
if (ch === "(") {
|
|
352
|
+
if (depth >= MAX_DEPTH) throw new Error("MeTTa expression nesting too deep");
|
|
353
|
+
c.pos++;
|
|
354
|
+
const items = [];
|
|
355
|
+
for (; ; ) {
|
|
356
|
+
c.skipTrivia();
|
|
357
|
+
if (c.done()) throw new Error("unbalanced '(' in MeTTa source");
|
|
358
|
+
if (c.peek() === ")") {
|
|
359
|
+
c.pos++;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
items.push(readAtom(c, depth + 1));
|
|
363
|
+
}
|
|
364
|
+
return expr(items);
|
|
365
|
+
}
|
|
366
|
+
if (ch === '"') return readString(c);
|
|
367
|
+
const word = readWord(c);
|
|
368
|
+
if (word.startsWith("$")) return variable(word.slice(1));
|
|
369
|
+
return c.tk.tokenize(word) ?? sym(word);
|
|
370
|
+
}
|
|
371
|
+
function readTop(c) {
|
|
372
|
+
let bang = false;
|
|
373
|
+
if (c.peek() === "!") {
|
|
374
|
+
bang = true;
|
|
375
|
+
c.pos++;
|
|
376
|
+
c.skipTrivia();
|
|
377
|
+
}
|
|
378
|
+
return { atom: readAtom(c), bang };
|
|
379
|
+
}
|
|
380
|
+
function parseTop(src, tk) {
|
|
381
|
+
const c = new Cursor(src, tk);
|
|
382
|
+
c.skipTrivia();
|
|
383
|
+
return c.done() ? void 0 : readTop(c);
|
|
384
|
+
}
|
|
385
|
+
function parse(src, tk) {
|
|
386
|
+
return parseTop(src, tk)?.atom;
|
|
387
|
+
}
|
|
388
|
+
function parseAll(src, tk) {
|
|
389
|
+
const c = new Cursor(src, tk);
|
|
390
|
+
const out = [];
|
|
391
|
+
for (; ; ) {
|
|
392
|
+
c.skipTrivia();
|
|
393
|
+
if (c.done()) break;
|
|
394
|
+
out.push(readTop(c));
|
|
395
|
+
}
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
398
|
+
function format(a) {
|
|
399
|
+
if (isExpr(a)) return "(" + a.items.map(format).join(" ") + ")";
|
|
400
|
+
if (isVar(a)) return "$" + a.name;
|
|
401
|
+
if (isSym(a)) return a.name;
|
|
402
|
+
if (isGnd(a)) {
|
|
403
|
+
const v = a.value;
|
|
404
|
+
switch (v.g) {
|
|
405
|
+
case "int":
|
|
406
|
+
return String(v.n);
|
|
407
|
+
case "float":
|
|
408
|
+
return Number.isInteger(v.n) ? v.n.toFixed(1) : String(v.n);
|
|
409
|
+
case "str":
|
|
410
|
+
return JSON.stringify(v.s);
|
|
411
|
+
case "bool":
|
|
412
|
+
return v.b ? "True" : "False";
|
|
413
|
+
case "unit":
|
|
414
|
+
return "()";
|
|
415
|
+
case "error":
|
|
416
|
+
return v.msg;
|
|
417
|
+
case "ext":
|
|
418
|
+
return v.id;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return "?";
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/bindings.ts
|
|
425
|
+
var emptyBindings = [];
|
|
426
|
+
var valRel = (x, a) => ({ tag: "val", x, a, y: void 0 });
|
|
427
|
+
var eqRel = (x, y) => ({ tag: "eq", x, a: void 0, y });
|
|
428
|
+
function lookupVal(b, x) {
|
|
429
|
+
for (const r of b) if (r.tag === "val" && r.x === x) return r.a;
|
|
430
|
+
return void 0;
|
|
431
|
+
}
|
|
432
|
+
function removeVal(b, x) {
|
|
433
|
+
return b.filter((r) => !(r.tag === "val" && r.x === x));
|
|
434
|
+
}
|
|
435
|
+
function hasLoop(b) {
|
|
436
|
+
for (const r of b) {
|
|
437
|
+
if (r.tag === "val" && r.a.kind === "var" && r.a.name === r.x) return true;
|
|
438
|
+
if (r.tag === "eq" && r.x === r.y) return true;
|
|
439
|
+
}
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
function addValRaw(b, x, a) {
|
|
443
|
+
return [valRel(x, a), ...removeVal(b, x)];
|
|
444
|
+
}
|
|
445
|
+
function addEqRaw(b, x, y) {
|
|
446
|
+
return x === y ? b : [eqRel(x, y), ...b];
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/match.ts
|
|
450
|
+
function suffixVars(a, suffix) {
|
|
451
|
+
if (a.ground) return a;
|
|
452
|
+
if (a.kind === "var") return variable(a.name + suffix);
|
|
453
|
+
if (a.kind === "expr") {
|
|
454
|
+
const its = a.items;
|
|
455
|
+
let items = null;
|
|
456
|
+
for (let i = 0; i < its.length; i++) {
|
|
457
|
+
const r = suffixVars(its[i], suffix);
|
|
458
|
+
if (items !== null) items.push(r);
|
|
459
|
+
else if (r !== its[i]) {
|
|
460
|
+
items = its.slice(0, i);
|
|
461
|
+
items.push(r);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return items === null ? a : { ...a, items };
|
|
465
|
+
}
|
|
466
|
+
return a;
|
|
467
|
+
}
|
|
468
|
+
function occursThrough(target, a, rels, b, seen) {
|
|
469
|
+
if (a.ground) return false;
|
|
470
|
+
if (a.kind === "var") {
|
|
471
|
+
if (a.name === target) return true;
|
|
472
|
+
if (seen.has(a.name)) return false;
|
|
473
|
+
seen.add(a.name);
|
|
474
|
+
const nv = lookupVal(rels, a.name) ?? lookupVal(b, a.name);
|
|
475
|
+
return nv !== void 0 && occursThrough(target, nv, rels, b, seen);
|
|
476
|
+
}
|
|
477
|
+
if (a.kind === "expr") return a.items.some((it) => occursThrough(target, it, rels, b, seen));
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
function reconcile(b, l, r) {
|
|
481
|
+
const out = [];
|
|
482
|
+
for (const mb of matchAtoms(l, r)) {
|
|
483
|
+
if (mb.some((rel) => rel.tag === "val" && occursThrough(rel.x, rel.a, mb, b, /* @__PURE__ */ new Set())))
|
|
484
|
+
continue;
|
|
485
|
+
for (const m of merge(b, mb)) out.push(m);
|
|
486
|
+
}
|
|
487
|
+
return out;
|
|
488
|
+
}
|
|
489
|
+
function addVarBinding(b, x, v) {
|
|
490
|
+
const prev = lookupVal(b, x);
|
|
491
|
+
if (prev === void 0) return [addValRaw(b, x, v)];
|
|
492
|
+
if (atomEq(prev, v)) return [b];
|
|
493
|
+
return reconcile(b, prev, v);
|
|
494
|
+
}
|
|
495
|
+
function addVarEquality(b, x, y) {
|
|
496
|
+
const vx = lookupVal(b, x);
|
|
497
|
+
const vy = lookupVal(b, y);
|
|
498
|
+
if (vx === void 0 || vy === void 0 || atomEq(vx, vy)) return [addEqRaw(b, x, y)];
|
|
499
|
+
return reconcile(b, vx, vy);
|
|
500
|
+
}
|
|
501
|
+
function mergeOne(bs, r) {
|
|
502
|
+
const out = [];
|
|
503
|
+
for (const b of bs) {
|
|
504
|
+
const ext = r.tag === "val" ? addVarBinding(b, r.x, r.a) : addVarEquality(b, r.x, r.y);
|
|
505
|
+
for (const e of ext) out.push(e);
|
|
506
|
+
}
|
|
507
|
+
return out;
|
|
508
|
+
}
|
|
509
|
+
function merge(a, b) {
|
|
510
|
+
let acc = [a];
|
|
511
|
+
for (const r of b) acc = mergeOne(acc, r);
|
|
512
|
+
return acc;
|
|
513
|
+
}
|
|
514
|
+
function matchAtomsWith(custom, l, r, leftSuffix = "") {
|
|
515
|
+
if (l.kind === "sym" && r.kind === "sym") return l.name === r.name ? [[]] : [];
|
|
516
|
+
if (l.kind === "var" && r.kind === "var") {
|
|
517
|
+
const lx = l.name + leftSuffix;
|
|
518
|
+
return lx === r.name ? [[]] : [[{ tag: "val", x: lx, a: r, y: void 0 }]];
|
|
519
|
+
}
|
|
520
|
+
if (l.kind === "var") return [[{ tag: "val", x: l.name + leftSuffix, a: r, y: void 0 }]];
|
|
521
|
+
if (r.kind === "var")
|
|
522
|
+
return [
|
|
523
|
+
[
|
|
524
|
+
{
|
|
525
|
+
tag: "val",
|
|
526
|
+
x: r.name,
|
|
527
|
+
a: leftSuffix === "" ? l : suffixVars(l, leftSuffix),
|
|
528
|
+
y: void 0
|
|
529
|
+
}
|
|
530
|
+
]
|
|
531
|
+
];
|
|
532
|
+
if (l.kind === "expr" && r.kind === "expr")
|
|
533
|
+
return matchAll(custom, [[]], l.items, r.items, leftSuffix);
|
|
534
|
+
if (l.kind === "gnd") return matchGrounded(custom, l, r);
|
|
535
|
+
if (r.kind === "gnd") return matchGrounded(custom, r, l);
|
|
536
|
+
return atomEq(l, r) ? [[]] : [];
|
|
537
|
+
}
|
|
538
|
+
function matchGrounded(custom, g, other) {
|
|
539
|
+
if (g.kind === "gnd" && g.match !== void 0) return g.match(other);
|
|
540
|
+
if (custom !== void 0) return custom(g, other);
|
|
541
|
+
return atomEq(g, other) ? [[]] : [];
|
|
542
|
+
}
|
|
543
|
+
function matchAll(custom, acc, xs, ys, leftSuffix = "") {
|
|
544
|
+
if (xs.length !== ys.length) return [];
|
|
545
|
+
let cur = acc;
|
|
546
|
+
for (let i = 0; i < xs.length; i++) {
|
|
547
|
+
const subs = matchAtomsWith(custom, xs[i], ys[i], leftSuffix);
|
|
548
|
+
const next = [];
|
|
549
|
+
for (const a of cur) for (const b of subs) for (const m of merge(a, b)) next.push(m);
|
|
550
|
+
cur = next;
|
|
551
|
+
if (cur.length === 0) break;
|
|
552
|
+
}
|
|
553
|
+
return cur;
|
|
554
|
+
}
|
|
555
|
+
function matchAtoms(l, r) {
|
|
556
|
+
return matchAtomsWith(void 0, l, r);
|
|
557
|
+
}
|
|
558
|
+
function matchAtomsScoped(l, r, suffix) {
|
|
559
|
+
return matchAtomsWith(void 0, l, r, suffix);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/substitution.ts
|
|
563
|
+
var emptySubst = [];
|
|
564
|
+
function lookupSubst(s, x) {
|
|
565
|
+
for (const [k, v] of s) if (k === x) return v;
|
|
566
|
+
return void 0;
|
|
567
|
+
}
|
|
568
|
+
function eraseSubst(s, x) {
|
|
569
|
+
return s.filter((p) => p[0] !== x);
|
|
570
|
+
}
|
|
571
|
+
function extendSubst(s, x, a) {
|
|
572
|
+
return [[x, a], ...eraseSubst(s, x)];
|
|
573
|
+
}
|
|
574
|
+
function applySubst(s, a) {
|
|
575
|
+
if (a.ground) return a;
|
|
576
|
+
if (s.length === 0) return a;
|
|
577
|
+
switch (a.kind) {
|
|
578
|
+
case "var":
|
|
579
|
+
return lookupSubst(s, a.name) ?? a;
|
|
580
|
+
case "expr": {
|
|
581
|
+
const its = a.items;
|
|
582
|
+
let items = null;
|
|
583
|
+
for (let i = 0; i < its.length; i++) {
|
|
584
|
+
const it = its[i];
|
|
585
|
+
const r = applySubst(s, it);
|
|
586
|
+
if (items !== null) items.push(r);
|
|
587
|
+
else if (r !== it) {
|
|
588
|
+
items = its.slice(0, i);
|
|
589
|
+
items.push(r);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return items === null ? a : { ...a, items };
|
|
593
|
+
}
|
|
594
|
+
default:
|
|
595
|
+
return a;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function occurs(x, a) {
|
|
599
|
+
if (a.ground) return false;
|
|
600
|
+
switch (a.kind) {
|
|
601
|
+
case "var":
|
|
602
|
+
return x === a.name;
|
|
603
|
+
case "expr":
|
|
604
|
+
return a.items.some((it) => occurs(x, it));
|
|
605
|
+
default:
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/instantiate.ts
|
|
611
|
+
function bindingsToSubst(b) {
|
|
612
|
+
const out = [];
|
|
613
|
+
for (const r of b) if (r.tag === "val") out.push([r.x, r.a]);
|
|
614
|
+
return out;
|
|
615
|
+
}
|
|
616
|
+
function instantiate(b, a, suffix = "") {
|
|
617
|
+
if (a.kind === "var") {
|
|
618
|
+
if (suffix === "") return b.length === 0 ? a : lookupVal(b, a.name) ?? a;
|
|
619
|
+
const name = a.name + suffix;
|
|
620
|
+
return lookupVal(b, name) ?? variable(name);
|
|
621
|
+
}
|
|
622
|
+
if (a.ground || a.kind !== "expr") return a;
|
|
623
|
+
if (b.length === 0 && suffix === "") return a;
|
|
624
|
+
const its = a.items;
|
|
625
|
+
let items = null;
|
|
626
|
+
for (let i = 0; i < its.length; i++) {
|
|
627
|
+
const it = its[i];
|
|
628
|
+
const r = instantiate(b, it, suffix);
|
|
629
|
+
if (items !== null) items.push(r);
|
|
630
|
+
else if (r !== it) {
|
|
631
|
+
items = its.slice(0, i);
|
|
632
|
+
items.push(r);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
return items === null ? a : { ...a, items };
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/pmap.ts
|
|
639
|
+
var BITS = 5;
|
|
640
|
+
var WIDTH = 1 << BITS;
|
|
641
|
+
var MASK = WIDTH - 1;
|
|
642
|
+
var DEPTH = 7;
|
|
643
|
+
var emptyPMap = null;
|
|
644
|
+
function keyHash(s) {
|
|
645
|
+
let h = 2166136261;
|
|
646
|
+
for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 16777619);
|
|
647
|
+
return h >>> 0;
|
|
648
|
+
}
|
|
649
|
+
var isBranch = (n) => Array.isArray(n);
|
|
650
|
+
function pmGet(map, key) {
|
|
651
|
+
let node = map;
|
|
652
|
+
let h = keyHash(key);
|
|
653
|
+
for (let level = 0; level < DEPTH && isBranch(node); level++) {
|
|
654
|
+
node = node[h & MASK] ?? null;
|
|
655
|
+
h >>>= BITS;
|
|
656
|
+
}
|
|
657
|
+
if (node === null || isBranch(node)) return void 0;
|
|
658
|
+
if (node.kind === "leaf") return node.key === key ? node.val : void 0;
|
|
659
|
+
for (const e of node.entries) if (e.key === key) return e.val;
|
|
660
|
+
return void 0;
|
|
661
|
+
}
|
|
662
|
+
var newBranch = () => new Array(WIDTH).fill(null);
|
|
663
|
+
function setLeaf(node, key, val) {
|
|
664
|
+
if (node === null) return val === void 0 ? null : { kind: "leaf", key, val };
|
|
665
|
+
if (isBranch(node)) return node;
|
|
666
|
+
if (node.kind === "leaf") {
|
|
667
|
+
if (node.key === key) return val === void 0 ? null : { kind: "leaf", key, val };
|
|
668
|
+
if (val === void 0) return node;
|
|
669
|
+
return { kind: "collision", entries: [node, { kind: "leaf", key, val }] };
|
|
670
|
+
}
|
|
671
|
+
const kept = node.entries.filter((e) => e.key !== key);
|
|
672
|
+
if (val !== void 0) kept.push({ kind: "leaf", key, val });
|
|
673
|
+
if (kept.length === 0) return null;
|
|
674
|
+
if (kept.length === 1) return kept[0];
|
|
675
|
+
return { kind: "collision", entries: kept };
|
|
676
|
+
}
|
|
677
|
+
function pmSet(map, key, val) {
|
|
678
|
+
const h = keyHash(key);
|
|
679
|
+
const go = (node, level) => {
|
|
680
|
+
if (level >= DEPTH) return setLeaf(node, key, val);
|
|
681
|
+
const idx = h >>> level * BITS & MASK;
|
|
682
|
+
if (node === null) {
|
|
683
|
+
if (val === void 0) return null;
|
|
684
|
+
const b = newBranch();
|
|
685
|
+
b[idx] = go(null, level + 1);
|
|
686
|
+
return b;
|
|
687
|
+
}
|
|
688
|
+
if (!isBranch(node)) return setLeaf(node, key, val);
|
|
689
|
+
const child = go(node[idx] ?? null, level + 1);
|
|
690
|
+
if (child === (node[idx] ?? null)) return node;
|
|
691
|
+
const copy = node.slice();
|
|
692
|
+
copy[idx] = child;
|
|
693
|
+
return copy;
|
|
694
|
+
};
|
|
695
|
+
return go(map, 0);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// src/atomlog.ts
|
|
699
|
+
var idxAdd = (idx, atom) => {
|
|
700
|
+
const key = String(hashOf(atom));
|
|
701
|
+
const bucket = pmGet(idx, key) ?? [];
|
|
702
|
+
const i = bucket.findIndex((e) => atomEq(e.atom, atom));
|
|
703
|
+
const next = i < 0 ? [...bucket, { atom, count: 1 }] : bucket.map((e, j) => j === i ? { atom: e.atom, count: e.count + 1 } : e);
|
|
704
|
+
return pmSet(idx, key, next);
|
|
705
|
+
};
|
|
706
|
+
var idxCount = (idx, atom) => {
|
|
707
|
+
const bucket = pmGet(idx, String(hashOf(atom)));
|
|
708
|
+
if (bucket === void 0) return 0;
|
|
709
|
+
for (const e of bucket) if (atomEq(e.atom, atom)) return e.count;
|
|
710
|
+
return 0;
|
|
711
|
+
};
|
|
712
|
+
var emptyLog = null;
|
|
713
|
+
var logSize = (log) => log === null ? 0 : log.size;
|
|
714
|
+
var logGroundIdx = (log) => log === null ? emptyPMap : log.groundIdx;
|
|
715
|
+
var logNonGround = (log) => log === null ? 0 : log.nonGround;
|
|
716
|
+
var logAppend = (log, atom) => ({
|
|
717
|
+
atom,
|
|
718
|
+
prev: log,
|
|
719
|
+
size: (log === null ? 0 : log.size) + 1,
|
|
720
|
+
groundIdx: atom.ground ? idxAdd(logGroundIdx(log), atom) : logGroundIdx(log),
|
|
721
|
+
nonGround: (log === null ? 0 : log.nonGround) + (atom.ground ? 0 : 1)
|
|
722
|
+
});
|
|
723
|
+
function logAppendAll(log, atoms) {
|
|
724
|
+
let out = log;
|
|
725
|
+
for (const a of atoms) out = logAppend(out, a);
|
|
726
|
+
return out;
|
|
727
|
+
}
|
|
728
|
+
function logToArray(log) {
|
|
729
|
+
const n = logSize(log);
|
|
730
|
+
const out = new Array(n);
|
|
731
|
+
let i = n - 1;
|
|
732
|
+
for (let p = log; p !== null; p = p.prev) out[i--] = p.atom;
|
|
733
|
+
return out;
|
|
734
|
+
}
|
|
735
|
+
var logFromArray = (atoms) => logAppendAll(emptyLog, atoms);
|
|
736
|
+
|
|
737
|
+
// src/wcojoin.ts
|
|
738
|
+
function allVars(rels) {
|
|
739
|
+
const seen = /* @__PURE__ */ new Set();
|
|
740
|
+
const out = [];
|
|
741
|
+
for (const r of rels)
|
|
742
|
+
for (const v of r.vars)
|
|
743
|
+
if (!seen.has(v)) {
|
|
744
|
+
seen.add(v);
|
|
745
|
+
out.push(v);
|
|
746
|
+
}
|
|
747
|
+
return out;
|
|
748
|
+
}
|
|
749
|
+
function wcoJoin(rels, key, varOrder) {
|
|
750
|
+
const order = varOrder ?? allVars(rels);
|
|
751
|
+
const relInfos = rels.map((r) => {
|
|
752
|
+
const relVars = order.filter((v) => r.vars.includes(v));
|
|
753
|
+
const root = /* @__PURE__ */ new Map();
|
|
754
|
+
tuple: for (const t of r.tuples) {
|
|
755
|
+
let node = root;
|
|
756
|
+
for (const v of relVars) {
|
|
757
|
+
const val = t.get(v);
|
|
758
|
+
if (val === void 0) continue tuple;
|
|
759
|
+
const k = key(val);
|
|
760
|
+
let e = node.get(k);
|
|
761
|
+
if (e === void 0) {
|
|
762
|
+
e = { val, child: /* @__PURE__ */ new Map() };
|
|
763
|
+
node.set(k, e);
|
|
764
|
+
}
|
|
765
|
+
node = e.child;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return { relVars, root };
|
|
769
|
+
});
|
|
770
|
+
const participants = order.map(
|
|
771
|
+
(v) => relInfos.map((ri, r) => ri.relVars.includes(v) ? r : -1).filter((r) => r >= 0)
|
|
772
|
+
);
|
|
773
|
+
const out = [];
|
|
774
|
+
const partial = /* @__PURE__ */ new Map();
|
|
775
|
+
const cursors = relInfos.map((ri) => ri.root);
|
|
776
|
+
const recurse = (i) => {
|
|
777
|
+
if (i === order.length) {
|
|
778
|
+
out.push(new Map(partial));
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const parts = participants[i];
|
|
782
|
+
if (parts.length === 0) return;
|
|
783
|
+
let smallest = parts[0];
|
|
784
|
+
for (const r of parts) if (cursors[r].size < cursors[smallest].size) smallest = r;
|
|
785
|
+
const v = order[i];
|
|
786
|
+
for (const [k, entry] of cursors[smallest]) {
|
|
787
|
+
const advanced = [];
|
|
788
|
+
let ok2 = true;
|
|
789
|
+
for (const r of parts) {
|
|
790
|
+
const e = cursors[r].get(k);
|
|
791
|
+
if (e === void 0) {
|
|
792
|
+
ok2 = false;
|
|
793
|
+
break;
|
|
794
|
+
}
|
|
795
|
+
advanced.push([r, e.child]);
|
|
796
|
+
}
|
|
797
|
+
if (!ok2) continue;
|
|
798
|
+
const saved = advanced.map(([r]) => [r, cursors[r]]);
|
|
799
|
+
for (const [r, child] of advanced) cursors[r] = child;
|
|
800
|
+
partial.set(v, entry.val);
|
|
801
|
+
recurse(i + 1);
|
|
802
|
+
for (const [r, c] of saved) cursors[r] = c;
|
|
803
|
+
}
|
|
804
|
+
partial.delete(v);
|
|
805
|
+
};
|
|
806
|
+
recurse(0);
|
|
807
|
+
return out;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// src/alpha.ts
|
|
811
|
+
function canonicalize(a, map) {
|
|
812
|
+
switch (a.kind) {
|
|
813
|
+
case "var": {
|
|
814
|
+
let c = map.get(a.name);
|
|
815
|
+
if (c === void 0) {
|
|
816
|
+
c = "%" + String(map.size);
|
|
817
|
+
map.set(a.name, c);
|
|
818
|
+
}
|
|
819
|
+
return variable(c);
|
|
820
|
+
}
|
|
821
|
+
case "expr":
|
|
822
|
+
return expr(a.items.map((x) => canonicalize(x, map)));
|
|
823
|
+
default:
|
|
824
|
+
return a;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
function alphaEq(a, b) {
|
|
828
|
+
return atomEq(canonicalize(a, /* @__PURE__ */ new Map()), canonicalize(b, /* @__PURE__ */ new Map()));
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// src/builtins.ts
|
|
832
|
+
var parseTokenizer;
|
|
833
|
+
function makeTokenizer() {
|
|
834
|
+
if (parseTokenizer === void 0) {
|
|
835
|
+
const t = new Tokenizer();
|
|
836
|
+
t.register(/^-?\d+$/, (s) => gint(BigInt(s)));
|
|
837
|
+
t.register(/^-?\d+\.\d+$/, (s) => gfloat(Number(s)));
|
|
838
|
+
t.register(/^True$/, () => gbool(true));
|
|
839
|
+
t.register(/^False$/, () => gbool(false));
|
|
840
|
+
parseTokenizer = t;
|
|
841
|
+
}
|
|
842
|
+
return parseTokenizer;
|
|
843
|
+
}
|
|
844
|
+
var sealCounter = 0;
|
|
845
|
+
var ok = (...results) => ({ tag: "ok", results });
|
|
846
|
+
var rerr = (msg) => ({ tag: "runtimeError", msg });
|
|
847
|
+
var ierr = (msg) => ({ tag: "incorrectArgument", msg });
|
|
848
|
+
var outputSink = (line) => {
|
|
849
|
+
console.log(line);
|
|
850
|
+
};
|
|
851
|
+
function setOutputSink(fn) {
|
|
852
|
+
const prev = outputSink;
|
|
853
|
+
outputSink = fn;
|
|
854
|
+
return prev;
|
|
855
|
+
}
|
|
856
|
+
var rawSink = typeof process !== "undefined" && process.stdout && typeof process.stdout.write === "function" ? (text) => void process.stdout.write(text) : (text) => console.log(text);
|
|
857
|
+
function setRawSink(fn) {
|
|
858
|
+
const prev = rawSink;
|
|
859
|
+
rawSink = fn;
|
|
860
|
+
return prev;
|
|
861
|
+
}
|
|
862
|
+
function display(a) {
|
|
863
|
+
if (a.kind === "gnd" && a.value.g === "str") return a.value.s;
|
|
864
|
+
return format(a);
|
|
865
|
+
}
|
|
866
|
+
function asIntVal(a) {
|
|
867
|
+
return a.kind === "gnd" && a.value.g === "int" ? a.value.n : void 0;
|
|
868
|
+
}
|
|
869
|
+
function asBool(a) {
|
|
870
|
+
if (a.kind === "gnd" && a.value.g === "bool") return a.value.b;
|
|
871
|
+
return void 0;
|
|
872
|
+
}
|
|
873
|
+
function asStr(a) {
|
|
874
|
+
return a.kind === "gnd" && a.value.g === "str" ? a.value.s : void 0;
|
|
875
|
+
}
|
|
876
|
+
function asFloat(a) {
|
|
877
|
+
if (a.kind !== "gnd") return void 0;
|
|
878
|
+
const v = a.value;
|
|
879
|
+
if (v.g === "int") return toF64(v.n);
|
|
880
|
+
if (v.g === "float") return v.n;
|
|
881
|
+
return void 0;
|
|
882
|
+
}
|
|
883
|
+
function arithBin(intF, floatF) {
|
|
884
|
+
return (args) => {
|
|
885
|
+
if (args.length !== 2) return ierr("expected exactly two arguments");
|
|
886
|
+
const ax = asIntVal(args[0]);
|
|
887
|
+
const ay = asIntVal(args[1]);
|
|
888
|
+
if (ax !== void 0 && ay !== void 0) return ok(gint(intF(ax, ay)));
|
|
889
|
+
const fx = asFloat(args[0]);
|
|
890
|
+
const fy = asFloat(args[1]);
|
|
891
|
+
if (fx === void 0 || fy === void 0) return ierr("expected two Numbers");
|
|
892
|
+
return ok(gfloat(floatF(fx, fy)));
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
function compareNumbers(a, b) {
|
|
896
|
+
const ai = asIntVal(a);
|
|
897
|
+
const bi = asIntVal(b);
|
|
898
|
+
if (ai !== void 0 && bi !== void 0) {
|
|
899
|
+
if (typeof ai === "bigint" || typeof bi === "bigint") {
|
|
900
|
+
const x = BigInt(ai);
|
|
901
|
+
const y = BigInt(bi);
|
|
902
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
903
|
+
}
|
|
904
|
+
return ai < bi ? -1 : ai > bi ? 1 : 0;
|
|
905
|
+
}
|
|
906
|
+
const af = asFloat(a);
|
|
907
|
+
const bf = asFloat(b);
|
|
908
|
+
if (af === void 0 || bf === void 0) return void 0;
|
|
909
|
+
return af < bf ? -1 : af > bf ? 1 : 0;
|
|
910
|
+
}
|
|
911
|
+
function numCmp(f) {
|
|
912
|
+
return (args) => {
|
|
913
|
+
if (args.length !== 2) return ierr("expected exactly two arguments");
|
|
914
|
+
const c = compareNumbers(args[0], args[1]);
|
|
915
|
+
if (c === void 0) return ierr("expected two Numbers");
|
|
916
|
+
return ok(gbool(f(c)));
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
function boolBin(f) {
|
|
920
|
+
return (args) => {
|
|
921
|
+
if (args.length !== 2) return ierr("expected exactly two arguments");
|
|
922
|
+
const x = asBool(args[0]);
|
|
923
|
+
const y = asBool(args[1]);
|
|
924
|
+
if (x === void 0 || y === void 0) return ierr("expected two Bool atoms");
|
|
925
|
+
return ok(gbool(f(x, y)));
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
var eqAtom = (args) => {
|
|
929
|
+
if (args.length !== 2) return ierr("expected exactly two arguments");
|
|
930
|
+
const a = args[0];
|
|
931
|
+
const b = args[1];
|
|
932
|
+
if (isErrorAtom(a)) return ok(a);
|
|
933
|
+
if (isErrorAtom(b)) return ok(b);
|
|
934
|
+
return ok(gbool(atomEq(a, b)));
|
|
935
|
+
};
|
|
936
|
+
var consAtom = (args) => {
|
|
937
|
+
if (args.length !== 2) return ierr("expected head and tail");
|
|
938
|
+
const [h, t] = args;
|
|
939
|
+
if (t.kind !== "expr") return ierr("cons-atom: expected an expression tail");
|
|
940
|
+
return ok(expr([h, ...t.items]));
|
|
941
|
+
};
|
|
942
|
+
var deconsAtom = (args) => {
|
|
943
|
+
if (args.length !== 1) return ierr("expected non-empty expression");
|
|
944
|
+
const e = args[0];
|
|
945
|
+
if (e.kind !== "expr") return ierr("expected non-empty expression");
|
|
946
|
+
if (e.items.length === 0) return ok(emptyExpr);
|
|
947
|
+
const [h, ...t] = e.items;
|
|
948
|
+
return ok(expr([h, expr(t)]));
|
|
949
|
+
};
|
|
950
|
+
var carAtom = (args) => {
|
|
951
|
+
const e = args[0];
|
|
952
|
+
if (args.length !== 1 || e?.kind !== "expr" || e.items.length === 0)
|
|
953
|
+
return ierr("expected non-empty expression");
|
|
954
|
+
return ok(e.items[0]);
|
|
955
|
+
};
|
|
956
|
+
var cdrAtom = (args) => {
|
|
957
|
+
const e = args[0];
|
|
958
|
+
if (args.length !== 1 || e?.kind !== "expr" || e.items.length === 0)
|
|
959
|
+
return ierr("expected non-empty expression");
|
|
960
|
+
return ok(expr(e.items.slice(1)));
|
|
961
|
+
};
|
|
962
|
+
var sizeAtom = (args) => {
|
|
963
|
+
if (args.length !== 1) return ierr("expected one atom");
|
|
964
|
+
const a = args[0];
|
|
965
|
+
return ok(gint(a.kind === "expr" ? a.items.length : atomSize(a)));
|
|
966
|
+
};
|
|
967
|
+
var minMaxAtom = (isMin, name) => (args) => {
|
|
968
|
+
const e = args[0];
|
|
969
|
+
if (args.length !== 1 || e?.kind !== "expr")
|
|
970
|
+
return ierr(name + " expects one argument: expression");
|
|
971
|
+
const nums = [];
|
|
972
|
+
for (const c of e.items) {
|
|
973
|
+
const f = asFloat(c);
|
|
974
|
+
if (f === void 0) return rerr("Only numbers are allowed in expression");
|
|
975
|
+
nums.push(f);
|
|
976
|
+
}
|
|
977
|
+
if (nums.length === 0) return rerr("Empty expression");
|
|
978
|
+
let acc = nums[0];
|
|
979
|
+
for (const z of nums.slice(1)) acc = isMin ? z < acc ? z : acc : z > acc ? z : acc;
|
|
980
|
+
return ok(gfloat(acc));
|
|
981
|
+
};
|
|
982
|
+
var indexAtom = (args) => {
|
|
983
|
+
const e = args[0];
|
|
984
|
+
if (args.length !== 2 || e?.kind !== "expr")
|
|
985
|
+
return ierr("index-atom expects two arguments: expression and atom");
|
|
986
|
+
const iv = asIntVal(args[1]);
|
|
987
|
+
if (iv === void 0) return ierr("index-atom expects two arguments: expression and atom");
|
|
988
|
+
const i = Number(iv);
|
|
989
|
+
if (i < 0 || i >= e.items.length) return rerr("Index is out of bounds");
|
|
990
|
+
return ok(e.items[i]);
|
|
991
|
+
};
|
|
992
|
+
var floatUn = (ff) => (args) => {
|
|
993
|
+
if (args.length !== 1) return ierr("expected exactly one argument");
|
|
994
|
+
const x = asFloat(args[0]);
|
|
995
|
+
return x === void 0 ? ierr("expected a Number") : ok(gfloat(ff(x)));
|
|
996
|
+
};
|
|
997
|
+
var floatBin = (ff) => (args) => {
|
|
998
|
+
if (args.length !== 2) return ierr("expected exactly two arguments");
|
|
999
|
+
const x = asFloat(args[0]);
|
|
1000
|
+
const y = asFloat(args[1]);
|
|
1001
|
+
return x === void 0 || y === void 0 ? ierr("expected two Numbers") : ok(gfloat(ff(x, y)));
|
|
1002
|
+
};
|
|
1003
|
+
var numRound = (fi, ff) => (args) => {
|
|
1004
|
+
if (args.length !== 1) return ierr("expected exactly one argument");
|
|
1005
|
+
const a = args[0];
|
|
1006
|
+
if (a.kind === "gnd" && a.value.g === "int") return ok(gint(fi(a.value.n)));
|
|
1007
|
+
if (a.kind === "gnd" && a.value.g === "float") return ok(gfloat(ff(a.value.n)));
|
|
1008
|
+
return ierr("expected a Number");
|
|
1009
|
+
};
|
|
1010
|
+
var floatPred = (fb) => (args) => {
|
|
1011
|
+
if (args.length !== 1) return ierr("expected exactly one argument");
|
|
1012
|
+
const a = args[0];
|
|
1013
|
+
if (a.kind === "gnd" && a.value.g === "int") return ok(gbool(false));
|
|
1014
|
+
if (a.kind === "gnd" && a.value.g === "float") return ok(gbool(fb(a.value.n)));
|
|
1015
|
+
return ierr("expected a Number");
|
|
1016
|
+
};
|
|
1017
|
+
var mathEntries = [
|
|
1018
|
+
["sqrt-math", floatUn(Math.sqrt)],
|
|
1019
|
+
["sin-math", floatUn(Math.sin)],
|
|
1020
|
+
["cos-math", floatUn(Math.cos)],
|
|
1021
|
+
["tan-math", floatUn(Math.tan)],
|
|
1022
|
+
["asin-math", floatUn(Math.asin)],
|
|
1023
|
+
["acos-math", floatUn(Math.acos)],
|
|
1024
|
+
["atan-math", floatUn(Math.atan)],
|
|
1025
|
+
["pow-math", floatBin(Math.pow)],
|
|
1026
|
+
["log-math", floatBin((base, input) => Math.log(input) / Math.log(base))],
|
|
1027
|
+
["abs-math", numRound(intAbs, Math.abs)],
|
|
1028
|
+
["trunc-math", numRound((n) => n, Math.trunc)],
|
|
1029
|
+
["ceil-math", numRound((n) => n, Math.ceil)],
|
|
1030
|
+
["floor-math", numRound((n) => n, Math.floor)],
|
|
1031
|
+
["round-math", numRound((n) => n, Math.round)],
|
|
1032
|
+
["isnan-math", floatPred(Number.isNaN)],
|
|
1033
|
+
["isinf-math", floatPred((x) => !Number.isFinite(x) && !Number.isNaN(x))]
|
|
1034
|
+
];
|
|
1035
|
+
var coreEntries = [
|
|
1036
|
+
["+", arithBin(addInt, (a, b) => a + b)],
|
|
1037
|
+
["-", arithBin(subInt, (a, b) => a - b)],
|
|
1038
|
+
["*", arithBin(mulInt, (a, b) => a * b)],
|
|
1039
|
+
["<", numCmp((c) => c < 0)],
|
|
1040
|
+
["<=", numCmp((c) => c <= 0)],
|
|
1041
|
+
[">", numCmp((c) => c > 0)],
|
|
1042
|
+
[">=", numCmp((c) => c >= 0)],
|
|
1043
|
+
["==", eqAtom],
|
|
1044
|
+
["and", boolBin((a, b) => a && b)],
|
|
1045
|
+
["or", boolBin((a, b) => a || b)],
|
|
1046
|
+
["cons-atom", consAtom],
|
|
1047
|
+
["decons-atom", deconsAtom],
|
|
1048
|
+
["car-atom", carAtom],
|
|
1049
|
+
["cdr-atom", cdrAtom],
|
|
1050
|
+
["size-atom", sizeAtom],
|
|
1051
|
+
["min-atom", minMaxAtom(true, "min-atom")],
|
|
1052
|
+
["max-atom", minMaxAtom(false, "max-atom")],
|
|
1053
|
+
["index-atom", indexAtom]
|
|
1054
|
+
];
|
|
1055
|
+
var removeFirst = (a, xs) => {
|
|
1056
|
+
const i = xs.findIndex((x) => atomEq(x, a));
|
|
1057
|
+
return i < 0 ? [...xs] : [...xs.slice(0, i), ...xs.slice(i + 1)];
|
|
1058
|
+
};
|
|
1059
|
+
var dedupAlpha = (xs) => {
|
|
1060
|
+
const out = [];
|
|
1061
|
+
for (const x of xs) if (!out.some((s) => alphaEq(s, x))) out.push(x);
|
|
1062
|
+
return out;
|
|
1063
|
+
};
|
|
1064
|
+
var msIntersect = (lhs, rhs) => {
|
|
1065
|
+
let pool = [...rhs];
|
|
1066
|
+
const out = [];
|
|
1067
|
+
for (const x of lhs)
|
|
1068
|
+
if (pool.some((y) => atomEq(y, x))) {
|
|
1069
|
+
out.push(x);
|
|
1070
|
+
pool = removeFirst(x, pool);
|
|
1071
|
+
}
|
|
1072
|
+
return out;
|
|
1073
|
+
};
|
|
1074
|
+
var msSubtract = (lhs, rhs) => {
|
|
1075
|
+
let pool = [...rhs];
|
|
1076
|
+
const out = [];
|
|
1077
|
+
for (const x of lhs) {
|
|
1078
|
+
if (pool.some((y) => atomEq(y, x))) pool = removeFirst(x, pool);
|
|
1079
|
+
else out.push(x);
|
|
1080
|
+
}
|
|
1081
|
+
return out;
|
|
1082
|
+
};
|
|
1083
|
+
var resultItems = (xs) => xs.length > 0 && xs[0].kind === "sym" && xs[0].name === "," ? xs.slice(1) : [...xs];
|
|
1084
|
+
var removeFirstBy = (eq, a, xs) => {
|
|
1085
|
+
const i = xs.findIndex((x) => eq(a, x));
|
|
1086
|
+
return i < 0 ? void 0 : [...xs.slice(0, i), ...xs.slice(i + 1)];
|
|
1087
|
+
};
|
|
1088
|
+
var bagEqBy = (eq, as, bs) => {
|
|
1089
|
+
let pool = [...bs];
|
|
1090
|
+
for (const a of as) {
|
|
1091
|
+
const r = removeFirstBy(eq, a, pool);
|
|
1092
|
+
if (r === void 0) return false;
|
|
1093
|
+
pool = r;
|
|
1094
|
+
}
|
|
1095
|
+
return pool.length === 0;
|
|
1096
|
+
};
|
|
1097
|
+
var exprArgs = (args) => {
|
|
1098
|
+
const out = [];
|
|
1099
|
+
for (const a of args) {
|
|
1100
|
+
if (a.kind !== "expr") return void 0;
|
|
1101
|
+
out.push([...a.items]);
|
|
1102
|
+
}
|
|
1103
|
+
return out;
|
|
1104
|
+
};
|
|
1105
|
+
var getMetatypeOp = (args) => {
|
|
1106
|
+
const a = args[0];
|
|
1107
|
+
if (args.length !== 1 || a === void 0) return ierr("get-metatype expects 1 argument");
|
|
1108
|
+
const k = a.kind === "sym" ? "Symbol" : a.kind === "var" ? "Variable" : a.kind === "expr" ? "Expression" : "Grounded";
|
|
1109
|
+
return ok(sym(k));
|
|
1110
|
+
};
|
|
1111
|
+
var assertEqOp = (eq) => (args) => {
|
|
1112
|
+
if (args.length !== 3 && args.length !== 4) return ierr("_assert-results-are-equal arity");
|
|
1113
|
+
const a0 = args[0];
|
|
1114
|
+
const e0 = args[1];
|
|
1115
|
+
if (a0?.kind !== "expr" || e0?.kind !== "expr") return ierr("expected two expressions");
|
|
1116
|
+
const okEq = bagEqBy(eq, resultItems(a0.items), resultItems(e0.items));
|
|
1117
|
+
if (okEq) return ok(emptyExpr);
|
|
1118
|
+
const msg = args.length === 4 ? args[3] : sym("results-are-not-equal");
|
|
1119
|
+
return ok(expr([sym("Error"), args[2], msg]));
|
|
1120
|
+
};
|
|
1121
|
+
var sortByFormat = (xs) => [...xs].sort((a, b) => format(a) < format(b) ? -1 : format(a) > format(b) ? 1 : 0);
|
|
1122
|
+
var stdEntries = [
|
|
1123
|
+
[
|
|
1124
|
+
"println!",
|
|
1125
|
+
(args) => {
|
|
1126
|
+
if (args.length !== 1) return ierr("println! expects 1 argument");
|
|
1127
|
+
outputSink(display(args[0]));
|
|
1128
|
+
return ok(emptyExpr);
|
|
1129
|
+
}
|
|
1130
|
+
],
|
|
1131
|
+
[
|
|
1132
|
+
// print! writes without a trailing newline (Hyperon semantics), via the raw sink, unlike println!.
|
|
1133
|
+
"print!",
|
|
1134
|
+
(args) => {
|
|
1135
|
+
if (args.length !== 1) return ierr("print! expects 1 argument");
|
|
1136
|
+
rawSink(display(args[0]));
|
|
1137
|
+
return ok(emptyExpr);
|
|
1138
|
+
}
|
|
1139
|
+
],
|
|
1140
|
+
[
|
|
1141
|
+
"format-args",
|
|
1142
|
+
(args) => {
|
|
1143
|
+
if (args.length !== 2) return ierr("format-args expects 2 arguments");
|
|
1144
|
+
const tmpl = args[0];
|
|
1145
|
+
const items = args[1];
|
|
1146
|
+
if (tmpl.kind !== "gnd" || tmpl.value.g !== "str")
|
|
1147
|
+
return ierr("format-args: first argument must be a String");
|
|
1148
|
+
if (items.kind !== "expr") return ierr("format-args: second argument must be an Expression");
|
|
1149
|
+
let i = 0;
|
|
1150
|
+
const out = tmpl.value.s.replace(/\{\}/g, () => {
|
|
1151
|
+
const it = items.items[i++];
|
|
1152
|
+
return it === void 0 ? "{}" : display(it);
|
|
1153
|
+
});
|
|
1154
|
+
return ok(gstr(out));
|
|
1155
|
+
}
|
|
1156
|
+
],
|
|
1157
|
+
[
|
|
1158
|
+
"repr",
|
|
1159
|
+
(args) => args.length === 1 ? ok(gstr(format(args[0]))) : ierr("repr expects 1 argument")
|
|
1160
|
+
],
|
|
1161
|
+
[
|
|
1162
|
+
"if-equal",
|
|
1163
|
+
(args) => args.length === 4 ? ok(alphaEq(args[0], args[1]) ? args[2] : args[3]) : ierr("if-equal expects 4 arguments")
|
|
1164
|
+
],
|
|
1165
|
+
[
|
|
1166
|
+
"=alpha",
|
|
1167
|
+
(args) => args.length === 2 ? ok(gbool(alphaEq(args[0], args[1]))) : ierr("=alpha expects 2 arguments")
|
|
1168
|
+
],
|
|
1169
|
+
["get-metatype", getMetatypeOp],
|
|
1170
|
+
[
|
|
1171
|
+
"not",
|
|
1172
|
+
(args) => {
|
|
1173
|
+
const b = asBool(args[0]);
|
|
1174
|
+
return args.length === 1 && b !== void 0 ? ok(gbool(!b)) : ierr("not expects one Bool");
|
|
1175
|
+
}
|
|
1176
|
+
],
|
|
1177
|
+
[
|
|
1178
|
+
"xor",
|
|
1179
|
+
(args) => {
|
|
1180
|
+
const x = asBool(args[0]);
|
|
1181
|
+
const y = asBool(args[1]);
|
|
1182
|
+
return args.length === 2 && x !== void 0 && y !== void 0 ? ok(gbool(x !== y)) : ierr("xor expects two Bool");
|
|
1183
|
+
}
|
|
1184
|
+
],
|
|
1185
|
+
[
|
|
1186
|
+
"/",
|
|
1187
|
+
(args) => {
|
|
1188
|
+
if (args.length === 2) {
|
|
1189
|
+
const a = asIntVal(args[0]);
|
|
1190
|
+
const b = asIntVal(args[1]);
|
|
1191
|
+
if (a !== void 0 && b !== void 0)
|
|
1192
|
+
return isZero(b) ? rerr("DivisionByZero") : ok(gint(intDiv(a, b)));
|
|
1193
|
+
}
|
|
1194
|
+
return arithBin(intDiv, (x, y) => x / y)(args);
|
|
1195
|
+
}
|
|
1196
|
+
],
|
|
1197
|
+
[
|
|
1198
|
+
"%",
|
|
1199
|
+
(args) => {
|
|
1200
|
+
const a = asIntVal(args[0]);
|
|
1201
|
+
const b = asIntVal(args[1]);
|
|
1202
|
+
if (args.length === 2 && a !== void 0 && b !== void 0)
|
|
1203
|
+
return isZero(b) ? rerr("DivisionByZero") : ok(gint(intMod(a, b)));
|
|
1204
|
+
return ierr("% expects two Int atoms");
|
|
1205
|
+
}
|
|
1206
|
+
],
|
|
1207
|
+
[
|
|
1208
|
+
"unique-atom",
|
|
1209
|
+
(args) => {
|
|
1210
|
+
const e = exprArgs(args);
|
|
1211
|
+
return e && e.length === 1 ? ok(expr(dedupAlpha(e[0]))) : ierr("unique-atom expects one expression");
|
|
1212
|
+
}
|
|
1213
|
+
],
|
|
1214
|
+
[
|
|
1215
|
+
"union-atom",
|
|
1216
|
+
(args) => {
|
|
1217
|
+
const e = exprArgs(args);
|
|
1218
|
+
return e && e.length === 2 ? ok(expr([...e[0], ...e[1]])) : ierr("union-atom expects two expressions");
|
|
1219
|
+
}
|
|
1220
|
+
],
|
|
1221
|
+
[
|
|
1222
|
+
"intersection-atom",
|
|
1223
|
+
(args) => {
|
|
1224
|
+
const e = exprArgs(args);
|
|
1225
|
+
return e && e.length === 2 ? ok(expr(msIntersect(e[0], e[1]))) : ierr("intersection-atom expects two expressions");
|
|
1226
|
+
}
|
|
1227
|
+
],
|
|
1228
|
+
[
|
|
1229
|
+
"subtraction-atom",
|
|
1230
|
+
(args) => {
|
|
1231
|
+
const e = exprArgs(args);
|
|
1232
|
+
return e && e.length === 2 ? ok(expr(msSubtract(e[0], e[1]))) : ierr("subtraction-atom expects two expressions");
|
|
1233
|
+
}
|
|
1234
|
+
],
|
|
1235
|
+
[
|
|
1236
|
+
"superpose",
|
|
1237
|
+
(args) => {
|
|
1238
|
+
const e = exprArgs(args);
|
|
1239
|
+
return e && e.length === 1 ? ok(...resultItems(e[0])) : ierr("superpose expects one expression");
|
|
1240
|
+
}
|
|
1241
|
+
],
|
|
1242
|
+
[
|
|
1243
|
+
"hyperpose",
|
|
1244
|
+
(args) => {
|
|
1245
|
+
const e = exprArgs(args);
|
|
1246
|
+
return e && e.length === 1 ? ok(...resultItems(e[0])) : ierr("hyperpose expects one expression");
|
|
1247
|
+
}
|
|
1248
|
+
],
|
|
1249
|
+
[
|
|
1250
|
+
"collapse-extract",
|
|
1251
|
+
(args) => {
|
|
1252
|
+
const e = exprArgs(args);
|
|
1253
|
+
if (!e || e.length !== 1) return ierr("collapse-extract expects one expression");
|
|
1254
|
+
return ok(
|
|
1255
|
+
expr(e[0].map((p) => p.kind === "expr" && p.items.length > 0 ? p.items[0] : p))
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1258
|
+
],
|
|
1259
|
+
[
|
|
1260
|
+
"sealed",
|
|
1261
|
+
// Alpha-rename every variable in the atom (second argument) to a fresh, unique variable, except those in
|
|
1262
|
+
// the ignore list (first argument). The operation is Hyperon's `sealed`; it gives a higher-order template
|
|
1263
|
+
// (map-atom/filter-atom's body, an applied lambda) a private copy of its variables each time, so repeated
|
|
1264
|
+
// applications do not capture one another. (Previously a no-op, which silently broke that hygiene.)
|
|
1265
|
+
(args) => {
|
|
1266
|
+
if (args.length !== 2) return ierr("sealed expects (sealed <vars> <atom>)");
|
|
1267
|
+
const ignore = new Set(
|
|
1268
|
+
(args[0].kind === "expr" ? args[0].items : []).flatMap(
|
|
1269
|
+
(v) => v.kind === "var" ? [v.name] : []
|
|
1270
|
+
)
|
|
1271
|
+
);
|
|
1272
|
+
const fresh = atomVars(args[1]).filter((v) => !ignore.has(v));
|
|
1273
|
+
if (fresh.length === 0) return ok(args[1]);
|
|
1274
|
+
const sub = fresh.map((v) => [v, variable(v + "#" + String(sealCounter++))]);
|
|
1275
|
+
return ok(applySubst(sub, args[1]));
|
|
1276
|
+
}
|
|
1277
|
+
],
|
|
1278
|
+
["nop", () => ok(emptyExpr)],
|
|
1279
|
+
// `pragma!` is handled as a stateful embedded op in eval.ts (it writes interpreter settings), not here.
|
|
1280
|
+
["register-module!", () => ok(emptyExpr)],
|
|
1281
|
+
["help!", () => ok(emptyExpr)],
|
|
1282
|
+
["empty", () => ok()],
|
|
1283
|
+
[
|
|
1284
|
+
// `(test actual expected)` checks alpha-equivalence (exactly, no convention-forgiving), prints
|
|
1285
|
+
// "is X, should Y. ✅/❌", and reduces to `()` on pass. The MeTTa-TS corpus is written in MeTTa-TS
|
|
1286
|
+
// conventions, so this stays strict. MeTTa-TS is not bent to match PeTTa's rendering.
|
|
1287
|
+
"test",
|
|
1288
|
+
(args) => {
|
|
1289
|
+
if (args.length !== 2) return ierr("test expects 2 arguments");
|
|
1290
|
+
const passed = alphaEq(args[0], args[1]);
|
|
1291
|
+
outputSink(`is ${format(args[0])}, should ${format(args[1])}. ${passed ? "\u2705" : "\u274C"}`);
|
|
1292
|
+
return passed ? ok(emptyExpr) : ok(expr([sym("Error"), expr([sym("test"), args[0], args[1]]), sym("test-failed")]));
|
|
1293
|
+
}
|
|
1294
|
+
],
|
|
1295
|
+
["_assert-results-are-equal", assertEqOp(atomEq)],
|
|
1296
|
+
["_assert-results-are-equal-msg", assertEqOp(atomEq)],
|
|
1297
|
+
["_assert-results-are-alpha-equal", assertEqOp(alphaEq)],
|
|
1298
|
+
["_assert-results-are-alpha-equal-msg", assertEqOp(alphaEq)],
|
|
1299
|
+
[
|
|
1300
|
+
"sort-atom",
|
|
1301
|
+
(args) => {
|
|
1302
|
+
const e = exprArgs(args);
|
|
1303
|
+
return e && e.length === 1 ? ok(expr(sortByFormat(e[0]))) : ierr("sort-atom expects one expression");
|
|
1304
|
+
}
|
|
1305
|
+
],
|
|
1306
|
+
[
|
|
1307
|
+
"sort-strings",
|
|
1308
|
+
(args) => {
|
|
1309
|
+
const e = exprArgs(args);
|
|
1310
|
+
return e && e.length === 1 ? ok(expr(sortByFormat(e[0]))) : ierr("sort-strings expects one expression");
|
|
1311
|
+
}
|
|
1312
|
+
]
|
|
1313
|
+
];
|
|
1314
|
+
var exprItems = (a) => a?.kind === "expr" ? a.items : void 0;
|
|
1315
|
+
var numVal = (a) => a.kind === "gnd" && (a.value.g === "int" || a.value.g === "float") ? Number(a.value.n) : void 0;
|
|
1316
|
+
var termRank = (a) => numVal(a) !== void 0 ? 0 : a.kind === "var" ? 1 : a.kind === "sym" ? 2 : a.kind === "gnd" ? 3 : 4;
|
|
1317
|
+
var atomCmp = (a, b) => {
|
|
1318
|
+
const ra = termRank(a);
|
|
1319
|
+
const rb = termRank(b);
|
|
1320
|
+
if (ra !== rb) return ra - rb;
|
|
1321
|
+
if (ra === 0) return numVal(a) - numVal(b);
|
|
1322
|
+
if (a.kind === "expr" && b.kind === "expr") {
|
|
1323
|
+
if (a.items.length !== b.items.length) return a.items.length - b.items.length;
|
|
1324
|
+
for (let i = 0; i < a.items.length; i++) {
|
|
1325
|
+
const c = atomCmp(a.items[i], b.items[i]);
|
|
1326
|
+
if (c !== 0) return c;
|
|
1327
|
+
}
|
|
1328
|
+
return 0;
|
|
1329
|
+
}
|
|
1330
|
+
const fa = format(a);
|
|
1331
|
+
const fb = format(b);
|
|
1332
|
+
return fa < fb ? -1 : fa > fb ? 1 : 0;
|
|
1333
|
+
};
|
|
1334
|
+
var sortStd = (xs) => [...xs].sort(atomCmp);
|
|
1335
|
+
var dedup = (xs) => {
|
|
1336
|
+
const out = [];
|
|
1337
|
+
for (const x of xs) if (!out.some((y) => atomEq(y, x))) out.push(x);
|
|
1338
|
+
return out;
|
|
1339
|
+
};
|
|
1340
|
+
var metatypeOf = (a) => a.kind === "var" ? "Variable" : a.kind === "gnd" ? "Grounded" : a.kind === "expr" ? "Expression" : "Symbol";
|
|
1341
|
+
var oneExpr = (name, args, f) => {
|
|
1342
|
+
const it = exprItems(args[0]);
|
|
1343
|
+
return args.length === 1 && it ? f(it) : ierr(`${name} expects one expression`);
|
|
1344
|
+
};
|
|
1345
|
+
var pettaEntries = [
|
|
1346
|
+
["length", (a) => oneExpr("length", a, (it) => ok(gint(it.length)))],
|
|
1347
|
+
["first", (a) => oneExpr("first", a, (it) => it.length ? ok(it[0]) : ierr("first: empty"))],
|
|
1348
|
+
[
|
|
1349
|
+
"last",
|
|
1350
|
+
(a) => oneExpr("last", a, (it) => it.length ? ok(it[it.length - 1]) : ierr("last: empty"))
|
|
1351
|
+
],
|
|
1352
|
+
["reverse", (a) => oneExpr("reverse", a, (it) => ok(expr([...it].reverse())))],
|
|
1353
|
+
["msort", (a) => oneExpr("msort", a, (it) => ok(expr(sortStd(it))))],
|
|
1354
|
+
["sort", (a) => oneExpr("sort", a, (it) => ok(expr(dedup(sortStd(it)))))],
|
|
1355
|
+
["list_to_set", (a) => oneExpr("list_to_set", a, (it) => ok(expr(dedup(it))))],
|
|
1356
|
+
// PeTTa metta.pl: dedupe a tuple modulo alpha-equivalence (two atoms equal up to a consistent
|
|
1357
|
+
// renaming of variables count as one). Hyperon has no such op; this is the alpha-aware sibling of
|
|
1358
|
+
// unique-atom, used by lib functions that work over patterns with variables.
|
|
1359
|
+
["alpha-unique-atom", (a) => oneExpr("alpha-unique-atom", a, (it) => ok(expr(dedupAlpha(it))))],
|
|
1360
|
+
[
|
|
1361
|
+
"second-from-pair",
|
|
1362
|
+
(a) => oneExpr("second-from-pair", a, (it) => it.length >= 2 ? ok(it[1]) : ierr("not a pair"))
|
|
1363
|
+
],
|
|
1364
|
+
[
|
|
1365
|
+
"append",
|
|
1366
|
+
(a) => {
|
|
1367
|
+
const x = exprItems(a[0]);
|
|
1368
|
+
const y = exprItems(a[1]);
|
|
1369
|
+
return a.length === 2 && x && y ? ok(expr([...x, ...y])) : ierr("append expects two expressions");
|
|
1370
|
+
}
|
|
1371
|
+
],
|
|
1372
|
+
[
|
|
1373
|
+
"is-var",
|
|
1374
|
+
(a) => a.length === 1 ? ok(gbool(a[0].kind === "var")) : ierr("is-var expects one atom")
|
|
1375
|
+
],
|
|
1376
|
+
[
|
|
1377
|
+
"is-ground",
|
|
1378
|
+
(a) => a.length === 1 ? ok(gbool(atomVars(a[0]).length === 0)) : ierr("is-ground expects one atom")
|
|
1379
|
+
],
|
|
1380
|
+
[
|
|
1381
|
+
"is-expr",
|
|
1382
|
+
(a) => a.length === 1 ? ok(gbool(a[0].kind === "expr")) : ierr("is-expr expects one atom")
|
|
1383
|
+
],
|
|
1384
|
+
[
|
|
1385
|
+
"is-space",
|
|
1386
|
+
(a) => a.length === 1 ? ok(gbool(a[0].kind === "sym" && a[0].name.startsWith("&"))) : ierr("is-space expects one atom")
|
|
1387
|
+
],
|
|
1388
|
+
[
|
|
1389
|
+
"get-mettatype",
|
|
1390
|
+
(a) => a.length === 1 ? ok(sym(metatypeOf(a[0]))) : ierr("get-mettatype expects one atom")
|
|
1391
|
+
],
|
|
1392
|
+
// Membership: `is-member`/`is-alpha-member` give a Bool; bare `member` succeeds (True) or yields nothing,
|
|
1393
|
+
// as in metta.pl's `member(X,L,true) :- member(X,L)`.
|
|
1394
|
+
[
|
|
1395
|
+
"is-member",
|
|
1396
|
+
(a) => {
|
|
1397
|
+
const l = exprItems(a[1]);
|
|
1398
|
+
return a.length === 2 && l ? ok(gbool(l.some((x) => atomEq(x, a[0])))) : ierr("is-member expects (x expr)");
|
|
1399
|
+
}
|
|
1400
|
+
],
|
|
1401
|
+
[
|
|
1402
|
+
"is-alpha-member",
|
|
1403
|
+
(a) => {
|
|
1404
|
+
const l = exprItems(a[1]);
|
|
1405
|
+
return a.length === 2 && l ? ok(gbool(l.some((x) => alphaEq(x, a[0])))) : ierr("is-alpha-member expects (x expr)");
|
|
1406
|
+
}
|
|
1407
|
+
],
|
|
1408
|
+
[
|
|
1409
|
+
"member",
|
|
1410
|
+
(a) => {
|
|
1411
|
+
const l = exprItems(a[1]);
|
|
1412
|
+
if (!(a.length === 2 && l)) return ierr("member expects (x expr)");
|
|
1413
|
+
return l.some((x) => atomEq(x, a[0])) ? ok(gbool(true)) : ok();
|
|
1414
|
+
}
|
|
1415
|
+
],
|
|
1416
|
+
[
|
|
1417
|
+
"exclude-item",
|
|
1418
|
+
(a) => {
|
|
1419
|
+
const l = exprItems(a[1]);
|
|
1420
|
+
return a.length === 2 && l ? ok(expr(l.filter((x) => !atomEq(x, a[0])))) : ierr("exclude-item expects (item expr)");
|
|
1421
|
+
}
|
|
1422
|
+
],
|
|
1423
|
+
// numeric min/max of two numbers (Hyperon has only the list min-atom/max-atom). Int vs float preserved.
|
|
1424
|
+
[
|
|
1425
|
+
"min",
|
|
1426
|
+
(a) => {
|
|
1427
|
+
const x = asFloat(a[0]);
|
|
1428
|
+
const y = asFloat(a[1]);
|
|
1429
|
+
return a.length === 2 && x !== void 0 && y !== void 0 ? ok(x <= y ? a[0] : a[1]) : ierr("min expects two Numbers");
|
|
1430
|
+
}
|
|
1431
|
+
],
|
|
1432
|
+
[
|
|
1433
|
+
"max",
|
|
1434
|
+
(a) => {
|
|
1435
|
+
const x = asFloat(a[0]);
|
|
1436
|
+
const y = asFloat(a[1]);
|
|
1437
|
+
return a.length === 2 && x !== void 0 && y !== void 0 ? ok(x >= y ? a[0] : a[1]) : ierr("max expects two Numbers");
|
|
1438
|
+
}
|
|
1439
|
+
],
|
|
1440
|
+
// bare math names PeTTa registers alongside the *-math forms. log is (base value).
|
|
1441
|
+
["sqrt", floatUn(Math.sqrt)],
|
|
1442
|
+
["sin", floatUn(Math.sin)],
|
|
1443
|
+
["cos", floatUn(Math.cos)],
|
|
1444
|
+
["exp", floatUn(Math.exp)],
|
|
1445
|
+
["log", floatBin((b, x) => Math.log(x) / Math.log(b))],
|
|
1446
|
+
// implies a b == (not a) or b
|
|
1447
|
+
[
|
|
1448
|
+
"implies",
|
|
1449
|
+
(a) => {
|
|
1450
|
+
const x = asBool(a[0]);
|
|
1451
|
+
const y = asBool(a[1]);
|
|
1452
|
+
return a.length === 2 && x !== void 0 && y !== void 0 ? ok(gbool(!x || y)) : ierr("implies expects two Bools");
|
|
1453
|
+
}
|
|
1454
|
+
],
|
|
1455
|
+
// string / atom construction
|
|
1456
|
+
[
|
|
1457
|
+
"concat",
|
|
1458
|
+
(a) => {
|
|
1459
|
+
const parts = a.map((x) => asStr(x) ?? format(x));
|
|
1460
|
+
return ok(gstr(parts.join("")));
|
|
1461
|
+
}
|
|
1462
|
+
],
|
|
1463
|
+
[
|
|
1464
|
+
"atom_concat",
|
|
1465
|
+
(a) => ok(sym(a.map((x) => x.kind === "sym" ? x.name : asStr(x) ?? format(x)).join("")))
|
|
1466
|
+
],
|
|
1467
|
+
// parse a string of MeTTa source into its (first) atom; sread is PeTTa's alias.
|
|
1468
|
+
[
|
|
1469
|
+
"parse",
|
|
1470
|
+
(a) => {
|
|
1471
|
+
const s = asStr(a[0]);
|
|
1472
|
+
if (a.length !== 1 || s === void 0) return ierr("parse expects a String");
|
|
1473
|
+
const tops = parseAll(s, makeTokenizer());
|
|
1474
|
+
return tops.length > 0 ? ok(tops[0].atom) : ok(emptyExpr);
|
|
1475
|
+
}
|
|
1476
|
+
],
|
|
1477
|
+
[
|
|
1478
|
+
"sread",
|
|
1479
|
+
(a) => {
|
|
1480
|
+
const s = asStr(a[0]);
|
|
1481
|
+
if (a.length !== 1 || s === void 0) return ierr("sread expects a String");
|
|
1482
|
+
const tops = parseAll(s, makeTokenizer());
|
|
1483
|
+
return tops.length > 0 ? ok(tops[0].atom) : ok(emptyExpr);
|
|
1484
|
+
}
|
|
1485
|
+
],
|
|
1486
|
+
// Effectful PeTTa ops: a random integer in [lo, hi), a random float in [lo, hi), and the wall-clock time.
|
|
1487
|
+
[
|
|
1488
|
+
"random-int",
|
|
1489
|
+
(a) => {
|
|
1490
|
+
const lo = asIntVal(a[0]);
|
|
1491
|
+
const hi = asIntVal(a[1]);
|
|
1492
|
+
if (a.length !== 2 || lo === void 0 || hi === void 0)
|
|
1493
|
+
return ierr("random-int expects two Ints");
|
|
1494
|
+
const l = Number(lo);
|
|
1495
|
+
const h = Number(hi);
|
|
1496
|
+
return ok(gint(BigInt(l + Math.floor(Math.random() * Math.max(0, h - l)))));
|
|
1497
|
+
}
|
|
1498
|
+
],
|
|
1499
|
+
[
|
|
1500
|
+
"random-float",
|
|
1501
|
+
(a) => {
|
|
1502
|
+
const lo = asFloat(a[0]);
|
|
1503
|
+
const hi = asFloat(a[1]);
|
|
1504
|
+
return a.length === 2 && lo !== void 0 && hi !== void 0 ? ok(gfloat(lo + Math.random() * (hi - lo))) : ierr("random-float expects two Numbers");
|
|
1505
|
+
}
|
|
1506
|
+
],
|
|
1507
|
+
["current-time", () => ok(gfloat(Date.now() / 1e3))]
|
|
1508
|
+
];
|
|
1509
|
+
var pettaOpNames = new Set(pettaEntries.map(([n]) => n));
|
|
1510
|
+
function baseTable() {
|
|
1511
|
+
return new Map([...mathEntries, ...coreEntries]);
|
|
1512
|
+
}
|
|
1513
|
+
function stdTable() {
|
|
1514
|
+
const t = new Map([...mathEntries, ...coreEntries, ...stdEntries]);
|
|
1515
|
+
for (const [name, fn] of pettaEntries) if (!t.has(name)) t.set(name, fn);
|
|
1516
|
+
return t;
|
|
1517
|
+
}
|
|
1518
|
+
function callGrounded(gt, op, args) {
|
|
1519
|
+
const fn = gt.get(op);
|
|
1520
|
+
return fn ? fn(args) : { tag: "noReduce" };
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
// src/compile.ts
|
|
1524
|
+
var BAIL = /* @__PURE__ */ Symbol("bail");
|
|
1525
|
+
var Tup = class {
|
|
1526
|
+
constructor(v) {
|
|
1527
|
+
this.v = v;
|
|
1528
|
+
}
|
|
1529
|
+
v;
|
|
1530
|
+
};
|
|
1531
|
+
var ARITH = {
|
|
1532
|
+
"+": addInt,
|
|
1533
|
+
"-": subInt,
|
|
1534
|
+
"*": mulInt
|
|
1535
|
+
};
|
|
1536
|
+
var KNOWN_OPS = /* @__PURE__ */ new Set([
|
|
1537
|
+
"+",
|
|
1538
|
+
"-",
|
|
1539
|
+
"*",
|
|
1540
|
+
"/",
|
|
1541
|
+
"%",
|
|
1542
|
+
"<",
|
|
1543
|
+
"<=",
|
|
1544
|
+
">",
|
|
1545
|
+
">=",
|
|
1546
|
+
"==",
|
|
1547
|
+
"if",
|
|
1548
|
+
"unify",
|
|
1549
|
+
"let"
|
|
1550
|
+
]);
|
|
1551
|
+
var asIntNode = (c) => c.node;
|
|
1552
|
+
function binIntArgs(args, scope, holders) {
|
|
1553
|
+
if (args.length !== 2) return void 0;
|
|
1554
|
+
const x = compileBody(args[0], scope, holders);
|
|
1555
|
+
const y = compileBody(args[1], scope, holders);
|
|
1556
|
+
if (!x || !y || x.type !== "int" || y.type !== "int") return void 0;
|
|
1557
|
+
return [asIntNode(x), asIntNode(y)];
|
|
1558
|
+
}
|
|
1559
|
+
function compileIf(cond, then_, els, scope, holders, branch) {
|
|
1560
|
+
const c = compileBody(cond, scope, holders);
|
|
1561
|
+
const t = branch(then_);
|
|
1562
|
+
const e = branch(els);
|
|
1563
|
+
if (!c || !t || !e || c.type !== "bool" || t.type !== e.type) return void 0;
|
|
1564
|
+
const cn = c.node;
|
|
1565
|
+
const tn = t.node;
|
|
1566
|
+
const en = e.node;
|
|
1567
|
+
return { node: (f) => cn(f) ? tn(f) : en(f), type: t.type };
|
|
1568
|
+
}
|
|
1569
|
+
function compileBody(a, scope, holders) {
|
|
1570
|
+
if (a.kind === "var") {
|
|
1571
|
+
const v = scope.vars.get(a.name);
|
|
1572
|
+
if (v === void 0) return void 0;
|
|
1573
|
+
return { node: v.acc, type: v.type };
|
|
1574
|
+
}
|
|
1575
|
+
if (a.kind === "gnd") {
|
|
1576
|
+
const v = a.value;
|
|
1577
|
+
if (v.g === "int") {
|
|
1578
|
+
const k = v.n;
|
|
1579
|
+
return { node: () => k, type: "int" };
|
|
1580
|
+
}
|
|
1581
|
+
if (v.g === "bool") {
|
|
1582
|
+
const b = v.b;
|
|
1583
|
+
return { node: () => b, type: "bool" };
|
|
1584
|
+
}
|
|
1585
|
+
return void 0;
|
|
1586
|
+
}
|
|
1587
|
+
if (a.kind !== "expr" || a.items.length === 0) return void 0;
|
|
1588
|
+
const head = a.items[0];
|
|
1589
|
+
const isCall = head.kind === "sym" && (KNOWN_OPS.has(head.name) || holders.has(head.name));
|
|
1590
|
+
if (!isCall) {
|
|
1591
|
+
const elems = a.items.map((e) => compileBody(e, scope, holders));
|
|
1592
|
+
if (elems.some((c) => !c || c.type !== "int")) return void 0;
|
|
1593
|
+
const ns = elems.map((c) => asIntNode(c));
|
|
1594
|
+
return { node: (f) => new Tup(ns.map((n) => n(f))), type: `tuple${a.items.length}` };
|
|
1595
|
+
}
|
|
1596
|
+
const op = head.name;
|
|
1597
|
+
const args = a.items.slice(1);
|
|
1598
|
+
if (op === "+" || op === "-" || op === "*") {
|
|
1599
|
+
const xy = binIntArgs(args, scope, holders);
|
|
1600
|
+
if (!xy) return void 0;
|
|
1601
|
+
const [xn, yn] = xy;
|
|
1602
|
+
const f = ARITH[op];
|
|
1603
|
+
return { node: (fr) => f(xn(fr), yn(fr)), type: "int" };
|
|
1604
|
+
}
|
|
1605
|
+
if (op === "/" || op === "%") {
|
|
1606
|
+
const xy = binIntArgs(args, scope, holders);
|
|
1607
|
+
if (!xy) return void 0;
|
|
1608
|
+
const [xn, yn] = xy;
|
|
1609
|
+
const div = op === "/" ? intDiv : intMod;
|
|
1610
|
+
return {
|
|
1611
|
+
node: (fr) => {
|
|
1612
|
+
const d = yn(fr);
|
|
1613
|
+
if (isZero(d)) throw BAIL;
|
|
1614
|
+
return div(xn(fr), d);
|
|
1615
|
+
},
|
|
1616
|
+
type: "int"
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
if (op === "<" || op === "<=" || op === ">" || op === ">=" || op === "==") {
|
|
1620
|
+
const xy = binIntArgs(args, scope, holders);
|
|
1621
|
+
if (!xy) return void 0;
|
|
1622
|
+
const [xn, yn] = xy;
|
|
1623
|
+
const test = op === "<" ? (c) => c < 0 : op === "<=" ? (c) => c <= 0 : op === ">" ? (c) => c > 0 : op === ">=" ? (c) => c >= 0 : (c) => c === 0;
|
|
1624
|
+
return { node: (fr) => test(cmpIntVal(xn(fr), yn(fr))), type: "bool" };
|
|
1625
|
+
}
|
|
1626
|
+
if (op === "if") {
|
|
1627
|
+
if (args.length !== 3) return void 0;
|
|
1628
|
+
return compileIf(
|
|
1629
|
+
args[0],
|
|
1630
|
+
args[1],
|
|
1631
|
+
args[2],
|
|
1632
|
+
scope,
|
|
1633
|
+
holders,
|
|
1634
|
+
(x) => compileBody(x, scope, holders)
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
if (op === "unify") {
|
|
1638
|
+
if (args.length !== 4) return void 0;
|
|
1639
|
+
const pat = args[1];
|
|
1640
|
+
if (!(pat.kind === "gnd" && pat.value.g === "int")) return void 0;
|
|
1641
|
+
const patVal = pat.value.n;
|
|
1642
|
+
const x = compileBody(args[0], scope, holders);
|
|
1643
|
+
const t = compileBody(args[2], scope, holders);
|
|
1644
|
+
const e = compileBody(args[3], scope, holders);
|
|
1645
|
+
if (!x || !t || !e || x.type !== "int" || t.type !== e.type) return void 0;
|
|
1646
|
+
const xn = asIntNode(x);
|
|
1647
|
+
const tn = t.node;
|
|
1648
|
+
const en = e.node;
|
|
1649
|
+
return { node: (fr) => cmpIntVal(xn(fr), patVal) === 0 ? tn(fr) : en(fr), type: t.type };
|
|
1650
|
+
}
|
|
1651
|
+
if (op === "let") {
|
|
1652
|
+
if (args.length !== 3 || args[0].kind !== "var") return void 0;
|
|
1653
|
+
const val = compileBody(args[1], scope, holders);
|
|
1654
|
+
if (!val || val.type !== "int") return void 0;
|
|
1655
|
+
const idx = scope.len;
|
|
1656
|
+
const np = {
|
|
1657
|
+
vars: new Map(scope.vars).set(args[0].name, {
|
|
1658
|
+
acc: (f) => f[idx],
|
|
1659
|
+
type: "int"
|
|
1660
|
+
}),
|
|
1661
|
+
len: scope.len + 1
|
|
1662
|
+
};
|
|
1663
|
+
const body = compileBody(args[2], np, holders);
|
|
1664
|
+
if (!body) return void 0;
|
|
1665
|
+
const vn = asIntNode(val);
|
|
1666
|
+
const bn = body.node;
|
|
1667
|
+
return { node: (fr) => bn([...fr, vn(fr)]), type: body.type };
|
|
1668
|
+
}
|
|
1669
|
+
const h = holders.get(op);
|
|
1670
|
+
if (h !== void 0) {
|
|
1671
|
+
if (args.length !== h.arity) return void 0;
|
|
1672
|
+
const cs = args.map((ar) => compileBody(ar, scope, holders));
|
|
1673
|
+
if (cs.some((c, i) => !c || c.type !== h.paramTypes[i])) return void 0;
|
|
1674
|
+
const ns = cs.map((c) => c.node);
|
|
1675
|
+
return { node: (fr) => h.run(ns.map((n) => n(fr))), type: h.retType };
|
|
1676
|
+
}
|
|
1677
|
+
return void 0;
|
|
1678
|
+
}
|
|
1679
|
+
function compileTail(a, scope, holders, self) {
|
|
1680
|
+
if (a.kind === "expr" && a.items.length > 0 && a.items[0].kind === "sym") {
|
|
1681
|
+
const op = a.items[0].name;
|
|
1682
|
+
if (op === "if" && a.items.length === 4) {
|
|
1683
|
+
return compileIf(
|
|
1684
|
+
a.items[1],
|
|
1685
|
+
a.items[2],
|
|
1686
|
+
a.items[3],
|
|
1687
|
+
scope,
|
|
1688
|
+
holders,
|
|
1689
|
+
(x) => compileTail(x, scope, holders, self)
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
if (op === self) {
|
|
1693
|
+
const h = holders.get(self);
|
|
1694
|
+
if (h !== void 0 && a.items.length - 1 === h.arity) {
|
|
1695
|
+
const cs = a.items.slice(1).map((x) => compileBody(x, scope, holders));
|
|
1696
|
+
if (!cs.some((c, i) => !c || c.type !== h.paramTypes[i])) {
|
|
1697
|
+
const ns = cs.map((c) => c.node);
|
|
1698
|
+
return { node: (f) => ns.map((n) => n(f)), type: h.retType };
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
return compileBody(a, scope, holders);
|
|
1704
|
+
}
|
|
1705
|
+
var bailRun = () => {
|
|
1706
|
+
throw BAIL;
|
|
1707
|
+
};
|
|
1708
|
+
function selfCallCount(a, functor) {
|
|
1709
|
+
if (a.kind !== "expr" || a.items.length === 0) return 0;
|
|
1710
|
+
let n = a.items[0].kind === "sym" && a.items[0].name === functor ? 1 : 0;
|
|
1711
|
+
for (const it of a.items) n += selfCallCount(it, functor);
|
|
1712
|
+
return n;
|
|
1713
|
+
}
|
|
1714
|
+
function makeRun(arity, node, memoize) {
|
|
1715
|
+
const loop = (vals) => {
|
|
1716
|
+
let frame2 = vals;
|
|
1717
|
+
for (; ; ) {
|
|
1718
|
+
const r = node(frame2);
|
|
1719
|
+
if (Array.isArray(r)) {
|
|
1720
|
+
frame2 = r;
|
|
1721
|
+
continue;
|
|
1722
|
+
}
|
|
1723
|
+
return r;
|
|
1724
|
+
}
|
|
1725
|
+
};
|
|
1726
|
+
if (!memoize) return loop;
|
|
1727
|
+
const memo = /* @__PURE__ */ new Map();
|
|
1728
|
+
const keyOf = (v) => v instanceof Tup ? "(" + v.v.map(keyOf).join(" ") + ")" : String(v);
|
|
1729
|
+
return (vals) => {
|
|
1730
|
+
const key = arity === 1 ? keyOf(vals[0]) : vals.map(keyOf).join(",");
|
|
1731
|
+
const hit = memo.get(key);
|
|
1732
|
+
if (hit !== void 0) return hit;
|
|
1733
|
+
const v = loop(vals);
|
|
1734
|
+
memo.set(key, v);
|
|
1735
|
+
return v;
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
function singleClauseHead(env, functor) {
|
|
1739
|
+
const eqs = env.ruleIndex.get(functor);
|
|
1740
|
+
if (eqs === void 0 || eqs.length !== 1) return void 0;
|
|
1741
|
+
const [lhs, body] = eqs[0];
|
|
1742
|
+
if (lhs.kind !== "expr" || lhs.items.length === 0 || lhs.items[0].kind !== "sym")
|
|
1743
|
+
return void 0;
|
|
1744
|
+
const params = [];
|
|
1745
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1746
|
+
const take = (name) => seen.has(name) ? false : (seen.add(name), true);
|
|
1747
|
+
for (let i = 1; i < lhs.items.length; i++) {
|
|
1748
|
+
const it = lhs.items[i];
|
|
1749
|
+
if (it.kind === "var") {
|
|
1750
|
+
if (!take(it.name)) return void 0;
|
|
1751
|
+
params.push(it.name);
|
|
1752
|
+
} else if (it.kind === "expr" && it.items.length > 0 && it.items.every((e) => e.kind === "var")) {
|
|
1753
|
+
const elems = it.items.map((e) => e.name);
|
|
1754
|
+
if (!elems.every(take)) return void 0;
|
|
1755
|
+
params.push(elems);
|
|
1756
|
+
} else return void 0;
|
|
1757
|
+
}
|
|
1758
|
+
return { params, body };
|
|
1759
|
+
}
|
|
1760
|
+
function buildScope(params, paramTypes) {
|
|
1761
|
+
const vars = /* @__PURE__ */ new Map();
|
|
1762
|
+
params.forEach((p, i) => {
|
|
1763
|
+
if (typeof p === "string") vars.set(p, { acc: (f) => f[i], type: paramTypes[i] });
|
|
1764
|
+
else p.forEach((e, j) => vars.set(e, { acc: (f) => f[i].v[j], type: "int" }));
|
|
1765
|
+
});
|
|
1766
|
+
return { vars, len: params.length };
|
|
1767
|
+
}
|
|
1768
|
+
function varTypesOf(params, paramTypes) {
|
|
1769
|
+
const m = /* @__PURE__ */ new Map();
|
|
1770
|
+
params.forEach((p, i) => {
|
|
1771
|
+
if (typeof p === "string") m.set(p, paramTypes[i]);
|
|
1772
|
+
else p.forEach((e) => m.set(e, "int"));
|
|
1773
|
+
});
|
|
1774
|
+
return m;
|
|
1775
|
+
}
|
|
1776
|
+
var paramTypesOf = (params) => params.map((p) => typeof p === "string" ? "int" : `tuple${p.length}`);
|
|
1777
|
+
function inferVarType(body, name, holders) {
|
|
1778
|
+
let found;
|
|
1779
|
+
const walk = (a) => {
|
|
1780
|
+
if (found !== void 0 || a.kind !== "expr" || a.items.length === 0) return;
|
|
1781
|
+
if (a.items[0].kind === "sym") {
|
|
1782
|
+
const h = holders.get(a.items[0].name);
|
|
1783
|
+
if (h !== void 0)
|
|
1784
|
+
for (let i = 0; i + 1 < a.items.length && found === void 0; i++) {
|
|
1785
|
+
const arg = a.items[i + 1];
|
|
1786
|
+
if (arg.kind === "var" && arg.name === name && h.paramTypes[i] !== "int")
|
|
1787
|
+
found = h.paramTypes[i];
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
for (const it of a.items) walk(it);
|
|
1791
|
+
};
|
|
1792
|
+
walk(body);
|
|
1793
|
+
return found;
|
|
1794
|
+
}
|
|
1795
|
+
function inferType(a, varTypes, holders) {
|
|
1796
|
+
if (a.kind === "var") return varTypes.get(a.name);
|
|
1797
|
+
if (a.kind === "gnd")
|
|
1798
|
+
return a.value.g === "int" ? "int" : a.value.g === "bool" ? "bool" : void 0;
|
|
1799
|
+
if (a.kind !== "expr" || a.items.length === 0) return void 0;
|
|
1800
|
+
const hd = a.items[0];
|
|
1801
|
+
if (!(hd.kind === "sym" && (KNOWN_OPS.has(hd.name) || holders.has(hd.name))))
|
|
1802
|
+
return a.items.every((e) => inferType(e, varTypes, holders) === "int") ? `tuple${a.items.length}` : void 0;
|
|
1803
|
+
const op = hd.name;
|
|
1804
|
+
if (op === "+" || op === "-" || op === "*" || op === "/" || op === "%") return "int";
|
|
1805
|
+
if (op === "<" || op === "<=" || op === ">" || op === ">=" || op === "==") return "bool";
|
|
1806
|
+
if (op === "if" && a.items.length === 4) {
|
|
1807
|
+
const tt = inferType(a.items[2], varTypes, holders);
|
|
1808
|
+
const te = inferType(a.items[3], varTypes, holders);
|
|
1809
|
+
if (tt !== void 0 && te !== void 0) return tt === te ? tt : void 0;
|
|
1810
|
+
return tt ?? te;
|
|
1811
|
+
}
|
|
1812
|
+
if (op === "unify" && a.items.length === 5) {
|
|
1813
|
+
const tt = inferType(a.items[3], varTypes, holders);
|
|
1814
|
+
const te = inferType(a.items[4], varTypes, holders);
|
|
1815
|
+
if (tt !== void 0 && te !== void 0) return tt === te ? tt : void 0;
|
|
1816
|
+
return tt ?? te;
|
|
1817
|
+
}
|
|
1818
|
+
if (op === "let" && a.items.length === 4) return inferType(a.items[3], varTypes, holders);
|
|
1819
|
+
return holders.get(op)?.retType;
|
|
1820
|
+
}
|
|
1821
|
+
function compileEnv(env) {
|
|
1822
|
+
const pure = env.pureFunctors ?? /* @__PURE__ */ new Set();
|
|
1823
|
+
const cand = /* @__PURE__ */ new Map();
|
|
1824
|
+
for (const f of pure) {
|
|
1825
|
+
const h = singleClauseHead(env, f);
|
|
1826
|
+
if (h !== void 0) cand.set(f, h);
|
|
1827
|
+
}
|
|
1828
|
+
const holders = /* @__PURE__ */ new Map();
|
|
1829
|
+
for (const [f, { params }] of cand)
|
|
1830
|
+
holders.set(f, {
|
|
1831
|
+
arity: params.length,
|
|
1832
|
+
retType: void 0,
|
|
1833
|
+
paramTypes: paramTypesOf(params),
|
|
1834
|
+
run: bailRun
|
|
1835
|
+
});
|
|
1836
|
+
for (let changed = true; changed; ) {
|
|
1837
|
+
changed = false;
|
|
1838
|
+
for (const [f, { params, body }] of cand) {
|
|
1839
|
+
const h = holders.get(f);
|
|
1840
|
+
params.forEach((p, i) => {
|
|
1841
|
+
if (typeof p === "string" && h.paramTypes[i] === "int") {
|
|
1842
|
+
const t = inferVarType(body, p, holders);
|
|
1843
|
+
if (t !== void 0 && t !== "int") {
|
|
1844
|
+
h.paramTypes[i] = t;
|
|
1845
|
+
changed = true;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
});
|
|
1849
|
+
if (h.retType === void 0) {
|
|
1850
|
+
const rt = inferType(body, varTypesOf(params, h.paramTypes), holders);
|
|
1851
|
+
if (rt !== void 0) {
|
|
1852
|
+
h.retType = rt;
|
|
1853
|
+
changed = true;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
for (const [f, h] of [...holders])
|
|
1859
|
+
if (h.retType === void 0) holders.delete(f);
|
|
1860
|
+
for (; ; ) {
|
|
1861
|
+
let removed = false;
|
|
1862
|
+
const result = /* @__PURE__ */ new Map();
|
|
1863
|
+
for (const [f] of [...holders]) {
|
|
1864
|
+
const cd = cand.get(f);
|
|
1865
|
+
const c = compileTail(cd.body, buildScope(cd.params, holders.get(f).paramTypes), holders, f);
|
|
1866
|
+
if (c === void 0) {
|
|
1867
|
+
holders.delete(f);
|
|
1868
|
+
removed = true;
|
|
1869
|
+
} else {
|
|
1870
|
+
result.set(f, { node: c.node, arity: cd.params.length });
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
if (!removed) {
|
|
1874
|
+
for (const [f, { node, arity }] of result)
|
|
1875
|
+
holders.get(f).run = makeRun(arity, node, selfCallCount(cand.get(f).body, f) >= 2);
|
|
1876
|
+
return holders;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
function runCompiled(env, op, partAtoms) {
|
|
1881
|
+
const h = env.compiled?.get(op);
|
|
1882
|
+
if (h === void 0 || partAtoms.length !== h.arity) return void 0;
|
|
1883
|
+
const vals = [];
|
|
1884
|
+
for (const a of partAtoms) {
|
|
1885
|
+
if (a.kind === "gnd" && a.value.g === "int") vals.push(a.value.n);
|
|
1886
|
+
else if (a.kind === "expr" && a.items.length > 0 && a.items.every((x) => x.kind === "gnd" && x.value.g === "int"))
|
|
1887
|
+
vals.push(new Tup(a.items.map((x) => x.value.n)));
|
|
1888
|
+
else return void 0;
|
|
1889
|
+
}
|
|
1890
|
+
try {
|
|
1891
|
+
const r = h.run(vals);
|
|
1892
|
+
if (typeof r === "boolean") return gbool(r);
|
|
1893
|
+
if (r instanceof Tup) return expr(r.v.map((n) => gint(n)));
|
|
1894
|
+
return gint(r);
|
|
1895
|
+
} catch (e) {
|
|
1896
|
+
if (e === BAIL || e instanceof RangeError) return void 0;
|
|
1897
|
+
throw e;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// src/eval.ts
|
|
1902
|
+
var LAZY_ARGS_OPS = /* @__PURE__ */ new Set(["par", "race", "once", "with-mutex"]);
|
|
1903
|
+
var AsyncInSyncError = class extends Error {
|
|
1904
|
+
constructor(op) {
|
|
1905
|
+
super(
|
|
1906
|
+
`async grounded operation '${op}' reached in synchronous evaluation; use the async runner`
|
|
1907
|
+
);
|
|
1908
|
+
this.name = "AsyncInSyncError";
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
var pendingAsyncOp = "?";
|
|
1912
|
+
function runGenSync(gen) {
|
|
1913
|
+
const r = gen.next();
|
|
1914
|
+
if (!r.done) throw new AsyncInSyncError(pendingAsyncOp);
|
|
1915
|
+
return r.value;
|
|
1916
|
+
}
|
|
1917
|
+
async function runGenAsync(gen, signal) {
|
|
1918
|
+
let r = gen.next();
|
|
1919
|
+
while (!r.done) {
|
|
1920
|
+
signal?.throwIfAborted();
|
|
1921
|
+
const v = await r.value;
|
|
1922
|
+
signal?.throwIfAborted();
|
|
1923
|
+
r = gen.next(v);
|
|
1924
|
+
}
|
|
1925
|
+
return r.value;
|
|
1926
|
+
}
|
|
1927
|
+
function* callGroundedG(env, op, args) {
|
|
1928
|
+
const af = env.agt.get(op);
|
|
1929
|
+
if (af !== void 0) {
|
|
1930
|
+
pendingAsyncOp = op;
|
|
1931
|
+
return yield af(args);
|
|
1932
|
+
}
|
|
1933
|
+
return callGrounded(env.gt, op, args);
|
|
1934
|
+
}
|
|
1935
|
+
var cons = (head, tail) => ({ head, tail });
|
|
1936
|
+
var frame = (atom, ret = "none", vars = [], fin = false) => ({
|
|
1937
|
+
atom,
|
|
1938
|
+
ret,
|
|
1939
|
+
vars,
|
|
1940
|
+
fin
|
|
1941
|
+
});
|
|
1942
|
+
var notReducibleA = sym("NotReducible");
|
|
1943
|
+
var emptyA = sym("Empty");
|
|
1944
|
+
var unitA = emptyExpr;
|
|
1945
|
+
var errAtom = (a, msg) => expr([sym("Error"), a, sym(msg)]);
|
|
1946
|
+
function opOf(a) {
|
|
1947
|
+
return a.kind === "expr" && a.items.length > 0 && a.items[0].kind === "sym" ? a.items[0].name : void 0;
|
|
1948
|
+
}
|
|
1949
|
+
function tryParHyperpose(env, world, bnd, arg, firstOnly) {
|
|
1950
|
+
if (env.parEval === void 0) return void 0;
|
|
1951
|
+
if (world.selfRules.size > 0) return void 0;
|
|
1952
|
+
const a = instantiate(bnd, arg);
|
|
1953
|
+
if (a.kind !== "expr" || opOf(a) !== "hyperpose" || a.items.length !== 2) return void 0;
|
|
1954
|
+
const tup = a.items[1];
|
|
1955
|
+
if (tup.kind !== "expr" || tup.items.length === 0) return void 0;
|
|
1956
|
+
const branches = tup.items;
|
|
1957
|
+
for (const b of branches) {
|
|
1958
|
+
const h = opOf(b);
|
|
1959
|
+
if (!b.ground || h === void 0 || env.pureFunctors?.has(h) !== true) return void 0;
|
|
1960
|
+
}
|
|
1961
|
+
const perBranch = env.parEval(branches.map(format), firstOnly);
|
|
1962
|
+
const out = [];
|
|
1963
|
+
for (const r of perBranch) if (r !== null) for (const at of r) out.push(at);
|
|
1964
|
+
return out;
|
|
1965
|
+
}
|
|
1966
|
+
var EMBEDDED = /* @__PURE__ */ new Set([
|
|
1967
|
+
"eval",
|
|
1968
|
+
"evalc",
|
|
1969
|
+
"chain",
|
|
1970
|
+
"unify",
|
|
1971
|
+
"cons-atom",
|
|
1972
|
+
"decons-atom",
|
|
1973
|
+
"function",
|
|
1974
|
+
"collapse-bind",
|
|
1975
|
+
"superpose-bind",
|
|
1976
|
+
"metta",
|
|
1977
|
+
"metta-thread",
|
|
1978
|
+
"capture",
|
|
1979
|
+
"context-space",
|
|
1980
|
+
"match",
|
|
1981
|
+
"get-type",
|
|
1982
|
+
"get-type-space",
|
|
1983
|
+
"get-doc",
|
|
1984
|
+
"new-state",
|
|
1985
|
+
"get-state",
|
|
1986
|
+
"change-state!",
|
|
1987
|
+
"new-space",
|
|
1988
|
+
"new-mork-space",
|
|
1989
|
+
"fork-space",
|
|
1990
|
+
"add-atom",
|
|
1991
|
+
"remove-atom",
|
|
1992
|
+
"get-atoms",
|
|
1993
|
+
"bind!",
|
|
1994
|
+
"import!",
|
|
1995
|
+
// Sets interpreter settings in-language (Hyperon `pragma!`); stateful, so handled here not as a pure op.
|
|
1996
|
+
"pragma!",
|
|
1997
|
+
// TS-native extension (not upstream MeTTa): atomic space mutation with rollback.
|
|
1998
|
+
"transaction",
|
|
1999
|
+
// TS-native concurrency primitives (async-only); see docs/.../concurrency-primitives.md.
|
|
2000
|
+
"par",
|
|
2001
|
+
"race",
|
|
2002
|
+
"once",
|
|
2003
|
+
"with-mutex"
|
|
2004
|
+
]);
|
|
2005
|
+
function isEmbeddedOp(a) {
|
|
2006
|
+
const op = opOf(a);
|
|
2007
|
+
return op !== void 0 && EMBEDDED.has(op);
|
|
2008
|
+
}
|
|
2009
|
+
var varsCopy = (prev) => prev !== null ? prev.head.vars : [];
|
|
2010
|
+
function isVariableHeaded(a) {
|
|
2011
|
+
if (a.kind === "var") return true;
|
|
2012
|
+
if (a.kind === "expr" && a.items.length > 0) return isVariableHeaded(a.items[0]);
|
|
2013
|
+
return false;
|
|
2014
|
+
}
|
|
2015
|
+
function headKey(a) {
|
|
2016
|
+
if (a.kind === "sym") return a.name;
|
|
2017
|
+
if (a.kind === "expr" && a.items.length > 0 && a.items[0].kind === "sym")
|
|
2018
|
+
return a.items[0].name;
|
|
2019
|
+
return void 0;
|
|
2020
|
+
}
|
|
2021
|
+
function atomToStack(a, prev) {
|
|
2022
|
+
if (a.kind === "expr") {
|
|
2023
|
+
const op = opOf(a);
|
|
2024
|
+
const it = a.items;
|
|
2025
|
+
if (op === "chain" && it.length === 4 && it[2].kind === "var") {
|
|
2026
|
+
return atomToStack(it[1], cons(frame(a, "chain", varsCopy(prev)), prev));
|
|
2027
|
+
}
|
|
2028
|
+
if (op === "function" && it.length === 2 && it[1].kind === "expr") {
|
|
2029
|
+
return atomToStack(it[1], cons(frame(a, "function", varsCopy(prev)), prev));
|
|
2030
|
+
}
|
|
2031
|
+
if (op === "unify" && it.length === 5) {
|
|
2032
|
+
return cons(frame(a, "none"), prev);
|
|
2033
|
+
}
|
|
2034
|
+
if (op === "chain") return cons(frame(errAtom(a, "chain: malformed"), "none", [], true), prev);
|
|
2035
|
+
if (op === "function")
|
|
2036
|
+
return cons(frame(errAtom(a, "function: malformed"), "none", [], true), prev);
|
|
2037
|
+
if (op === "unify") return cons(frame(errAtom(a, "unify: malformed"), "none", [], true), prev);
|
|
2038
|
+
}
|
|
2039
|
+
return cons(frame(a, "none", varsCopy(prev)), prev);
|
|
2040
|
+
}
|
|
2041
|
+
function finItem(st, a, b) {
|
|
2042
|
+
return { stack: cons(frame(a, "none", [], true), st), bnd: b };
|
|
2043
|
+
}
|
|
2044
|
+
function evalResult(prev, r, b) {
|
|
2045
|
+
if (opOf(r) === "function") return { stack: atomToStack(r, prev), bnd: b };
|
|
2046
|
+
return finItem(prev, r, b);
|
|
2047
|
+
}
|
|
2048
|
+
var KEY_SEP = "";
|
|
2049
|
+
var ARG_SEP = "\0";
|
|
2050
|
+
function argKey(a) {
|
|
2051
|
+
if (a.kind === "sym") return "s" + ARG_SEP + a.name;
|
|
2052
|
+
if (a.kind === "gnd") {
|
|
2053
|
+
const v = a.value;
|
|
2054
|
+
switch (v.g) {
|
|
2055
|
+
case "int":
|
|
2056
|
+
return "i" + ARG_SEP + v.n;
|
|
2057
|
+
case "float":
|
|
2058
|
+
return "f" + ARG_SEP + v.n;
|
|
2059
|
+
case "str":
|
|
2060
|
+
return "S" + ARG_SEP + v.s;
|
|
2061
|
+
case "bool":
|
|
2062
|
+
return "b" + ARG_SEP + (v.b ? "1" : "0");
|
|
2063
|
+
default:
|
|
2064
|
+
return void 0;
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
return void 0;
|
|
2068
|
+
}
|
|
2069
|
+
function pushTo(m, k, x) {
|
|
2070
|
+
const cur = m.get(k);
|
|
2071
|
+
if (cur === void 0) m.set(k, [x]);
|
|
2072
|
+
else cur.push(x);
|
|
2073
|
+
}
|
|
2074
|
+
function emptyEnv(gt) {
|
|
2075
|
+
return {
|
|
2076
|
+
ruleIndex: /* @__PURE__ */ new Map(),
|
|
2077
|
+
varRules: [],
|
|
2078
|
+
sigs: /* @__PURE__ */ new Map(),
|
|
2079
|
+
gt,
|
|
2080
|
+
atoms: [],
|
|
2081
|
+
types: /* @__PURE__ */ new Map(),
|
|
2082
|
+
imports: /* @__PURE__ */ new Map(),
|
|
2083
|
+
exprTypes: [],
|
|
2084
|
+
agt: /* @__PURE__ */ new Map(),
|
|
2085
|
+
mutexes: /* @__PURE__ */ new Map(),
|
|
2086
|
+
factIndex: /* @__PURE__ */ new Map(),
|
|
2087
|
+
argIndex: /* @__PURE__ */ new Map(),
|
|
2088
|
+
nonGroundAtPos: /* @__PURE__ */ new Map(),
|
|
2089
|
+
varHeadedFacts: []
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
function invalidateTabling(env) {
|
|
2093
|
+
if (env.table !== void 0) {
|
|
2094
|
+
env.table.clear();
|
|
2095
|
+
env.pureFunctors = analyzePurity(env);
|
|
2096
|
+
env.compileDirty = true;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function usedAsHead(a, name) {
|
|
2100
|
+
if (a.kind !== "expr" || a.items.length === 0) return false;
|
|
2101
|
+
if (a.items[0].kind === "var" && a.items[0].name === name) return true;
|
|
2102
|
+
return a.items.some((it) => usedAsHead(it, name));
|
|
2103
|
+
}
|
|
2104
|
+
function hoFunctors(env) {
|
|
2105
|
+
const out = /* @__PURE__ */ new Map();
|
|
2106
|
+
for (const [g, eqs] of env.ruleIndex) {
|
|
2107
|
+
if (eqs.length !== 1) continue;
|
|
2108
|
+
const [lhs, rhs] = eqs[0];
|
|
2109
|
+
if (lhs.kind !== "expr") continue;
|
|
2110
|
+
const idxs = [];
|
|
2111
|
+
for (let k = 0; k < lhs.items.length - 1; k++) {
|
|
2112
|
+
const p = lhs.items[k + 1];
|
|
2113
|
+
if (p.kind === "var" && usedAsHead(rhs, p.name)) idxs.push(k);
|
|
2114
|
+
}
|
|
2115
|
+
if (idxs.length > 0) out.set(g, { arity: lhs.items.length - 1, idxs });
|
|
2116
|
+
}
|
|
2117
|
+
return out;
|
|
2118
|
+
}
|
|
2119
|
+
function specBody(a, pk, fsym, g, sName, k, gArity) {
|
|
2120
|
+
const rec = (x) => specBody(x, pk, fsym, g, sName, k, gArity);
|
|
2121
|
+
if (a.kind === "var") return a.name === pk ? sym(fsym) : a;
|
|
2122
|
+
if (a.kind !== "expr" || a.items.length === 0) return a;
|
|
2123
|
+
const h = a.items[0];
|
|
2124
|
+
if (h.kind === "var" && h.name === pk) return expr([sym(fsym), ...a.items.slice(1).map(rec)]);
|
|
2125
|
+
if (h.kind === "sym" && h.name === g && a.items.length - 1 === gArity) {
|
|
2126
|
+
const argK = a.items[k + 1];
|
|
2127
|
+
if (argK.kind === "var" && argK.name === pk)
|
|
2128
|
+
return expr([
|
|
2129
|
+
sym(sName),
|
|
2130
|
+
...a.items.slice(1).filter((_, i) => i !== k).map(rec)
|
|
2131
|
+
]);
|
|
2132
|
+
}
|
|
2133
|
+
return expr(a.items.map(rec));
|
|
2134
|
+
}
|
|
2135
|
+
function makeSpec(env, g, k, fsym) {
|
|
2136
|
+
const sName = g + "$" + fsym;
|
|
2137
|
+
if (env.ruleIndex.has(sName)) return sName;
|
|
2138
|
+
const eqs = env.ruleIndex.get(g);
|
|
2139
|
+
if (eqs === void 0 || eqs.length !== 1) return void 0;
|
|
2140
|
+
const [lhs, rhs] = eqs[0];
|
|
2141
|
+
if (lhs.kind !== "expr") return void 0;
|
|
2142
|
+
const params = lhs.items.slice(1);
|
|
2143
|
+
const pk = params[k];
|
|
2144
|
+
if (pk === void 0 || pk.kind !== "var") return void 0;
|
|
2145
|
+
const newLhs = expr([sym(sName), ...params.filter((_, i) => i !== k)]);
|
|
2146
|
+
const newRhs = specBody(rhs, pk.name, fsym, g, sName, k, params.length);
|
|
2147
|
+
addAtomToEnv(env, expr([sym("="), newLhs, newRhs]));
|
|
2148
|
+
return sName;
|
|
2149
|
+
}
|
|
2150
|
+
function rewriteHO(env, a, ho) {
|
|
2151
|
+
if (a.kind !== "expr" || a.items.length === 0) return a;
|
|
2152
|
+
const items = a.items.map((x) => rewriteHO(env, x, ho));
|
|
2153
|
+
const h = items[0];
|
|
2154
|
+
if (h.kind === "sym") {
|
|
2155
|
+
const info = ho.get(h.name);
|
|
2156
|
+
if (info !== void 0 && items.length - 1 === info.arity) {
|
|
2157
|
+
for (const k of info.idxs) {
|
|
2158
|
+
const argK = items[k + 1];
|
|
2159
|
+
if (argK !== void 0 && argK.kind === "sym" && env.ruleIndex.has(argK.name)) {
|
|
2160
|
+
const sName = makeSpec(env, h.name, k, argK.name);
|
|
2161
|
+
if (sName !== void 0)
|
|
2162
|
+
return expr([sym(sName), ...items.slice(1).filter((_, i) => i !== k)]);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
return items.every((it, i) => it === a.items[i]) ? a : expr(items);
|
|
2168
|
+
}
|
|
2169
|
+
function specializeHO(env) {
|
|
2170
|
+
const ho = hoFunctors(env);
|
|
2171
|
+
if (ho.size === 0) return;
|
|
2172
|
+
const rules = [];
|
|
2173
|
+
for (const [g, eqs] of env.ruleIndex) for (const [lhs, rhs] of eqs) rules.push([g, lhs, rhs]);
|
|
2174
|
+
for (const [g, lhs, rhs] of rules) {
|
|
2175
|
+
const newRhs = rewriteHO(env, rhs, ho);
|
|
2176
|
+
if (newRhs !== rhs) {
|
|
2177
|
+
const eqs = env.ruleIndex.get(g);
|
|
2178
|
+
if (eqs !== void 0) {
|
|
2179
|
+
for (let i = 0; i < eqs.length; i++)
|
|
2180
|
+
if (eqs[i][0] === lhs && eqs[i][1] === rhs) eqs[i] = [lhs, newRhs];
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
function ensureCompiled(env) {
|
|
2186
|
+
if (env.compiled !== void 0 && env.compileDirty) {
|
|
2187
|
+
specializeHO(env);
|
|
2188
|
+
env.compiled = compileEnv(env);
|
|
2189
|
+
env.compileDirty = false;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
function disableTabling(env) {
|
|
2193
|
+
if (env.table !== void 0) {
|
|
2194
|
+
env.table.clear();
|
|
2195
|
+
env.pureFunctors = /* @__PURE__ */ new Set();
|
|
2196
|
+
if (env.compiled !== void 0) {
|
|
2197
|
+
env.compiled = /* @__PURE__ */ new Map();
|
|
2198
|
+
env.compileDirty = false;
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
function addAtomToEnv(env, x) {
|
|
2203
|
+
env.atoms.push(x);
|
|
2204
|
+
const fk = headKey(x);
|
|
2205
|
+
if (fk === void 0) env.varHeadedFacts.push(x);
|
|
2206
|
+
else {
|
|
2207
|
+
pushTo(env.factIndex, fk, x);
|
|
2208
|
+
if (x.kind === "expr")
|
|
2209
|
+
for (let i = 1; i < x.items.length; i++) {
|
|
2210
|
+
const ak = argKey(x.items[i]);
|
|
2211
|
+
if (ak !== void 0) pushTo(env.argIndex, fk + KEY_SEP + i + KEY_SEP + ak, x);
|
|
2212
|
+
else pushTo(env.nonGroundAtPos, fk + KEY_SEP + i, x);
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
if (opOf(x) === "=" && x.kind === "expr" && x.items.length === 3) {
|
|
2216
|
+
const lhs = x.items[1];
|
|
2217
|
+
const rhs = x.items[2];
|
|
2218
|
+
const k = headKey(lhs);
|
|
2219
|
+
if (k === void 0) env.varRules.push([lhs, rhs]);
|
|
2220
|
+
else {
|
|
2221
|
+
const cur = env.ruleIndex.get(k);
|
|
2222
|
+
if (cur === void 0) env.ruleIndex.set(k, [[lhs, rhs]]);
|
|
2223
|
+
else cur.push([lhs, rhs]);
|
|
2224
|
+
}
|
|
2225
|
+
invalidateTabling(env);
|
|
2226
|
+
}
|
|
2227
|
+
if (x.kind === "expr" && opOf(x) === ":" && x.items.length === 3) {
|
|
2228
|
+
const subj = x.items[1];
|
|
2229
|
+
const t = x.items[2];
|
|
2230
|
+
if (subj.kind === "sym") {
|
|
2231
|
+
if (opOf(t) === "->" && t.kind === "expr") env.sigs.set(subj.name, t.items.slice(1));
|
|
2232
|
+
env.types.set(subj.name, [...env.types.get(subj.name) ?? [], t]);
|
|
2233
|
+
} else if (subj.kind === "expr") {
|
|
2234
|
+
env.exprTypes.push([subj, t]);
|
|
2235
|
+
}
|
|
2236
|
+
env.typeCache = void 0;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
function buildEnv(atoms, gt) {
|
|
2240
|
+
const env = emptyEnv(gt);
|
|
2241
|
+
for (const x of atoms) addAtomToEnv(env, x);
|
|
2242
|
+
return env;
|
|
2243
|
+
}
|
|
2244
|
+
function registerImportedTypes(env, atoms) {
|
|
2245
|
+
for (const x of atoms) {
|
|
2246
|
+
if (x.kind !== "expr" || opOf(x) !== ":" || x.items.length !== 3) continue;
|
|
2247
|
+
const subj = x.items[1];
|
|
2248
|
+
const t = x.items[2];
|
|
2249
|
+
if (subj.kind === "sym") {
|
|
2250
|
+
if (opOf(t) === "->" && t.kind === "expr" && !env.sigs.has(subj.name))
|
|
2251
|
+
env.sigs.set(subj.name, t.items.slice(1));
|
|
2252
|
+
const cur = env.types.get(subj.name) ?? [];
|
|
2253
|
+
if (!cur.some((e) => atomEq(e, t))) env.types.set(subj.name, [...cur, t]);
|
|
2254
|
+
} else if (subj.kind === "expr") {
|
|
2255
|
+
if (!env.exprTypes.some(([s, tt]) => atomEq(s, subj) && atomEq(tt, t)))
|
|
2256
|
+
env.exprTypes.push([subj, t]);
|
|
2257
|
+
}
|
|
2258
|
+
env.typeCache = void 0;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
function selfAtoms(env, w) {
|
|
2262
|
+
return logSize(w.selfExtra) === 0 ? env.atoms : [...env.atoms, ...logToArray(w.selfExtra)];
|
|
2263
|
+
}
|
|
2264
|
+
function candidates(env, toEval) {
|
|
2265
|
+
const k = headKey(toEval);
|
|
2266
|
+
const keyed = k !== void 0 ? env.ruleIndex.get(k) ?? [] : [];
|
|
2267
|
+
return [...keyed, ...env.varRules];
|
|
2268
|
+
}
|
|
2269
|
+
var initSt = () => ({
|
|
2270
|
+
counter: 0,
|
|
2271
|
+
world: {
|
|
2272
|
+
spaces: /* @__PURE__ */ new Map(),
|
|
2273
|
+
store: /* @__PURE__ */ new Map(),
|
|
2274
|
+
tokens: /* @__PURE__ */ new Map(),
|
|
2275
|
+
selfExtra: emptyLog,
|
|
2276
|
+
selfRules: /* @__PURE__ */ new Map(),
|
|
2277
|
+
selfVarRules: [],
|
|
2278
|
+
maxStackDepth: 0
|
|
2279
|
+
}
|
|
2280
|
+
});
|
|
2281
|
+
function cloneWorld(w) {
|
|
2282
|
+
return {
|
|
2283
|
+
spaces: new Map(w.spaces),
|
|
2284
|
+
store: new Map(w.store),
|
|
2285
|
+
tokens: new Map(w.tokens),
|
|
2286
|
+
selfExtra: w.selfExtra,
|
|
2287
|
+
selfRules: new Map(w.selfRules),
|
|
2288
|
+
selfVarRules: w.selfVarRules,
|
|
2289
|
+
maxStackDepth: w.maxStackDepth
|
|
2290
|
+
};
|
|
2291
|
+
}
|
|
2292
|
+
function multisetDelta(base, branch) {
|
|
2293
|
+
const remaining = base.slice();
|
|
2294
|
+
const added = [];
|
|
2295
|
+
for (const a of branch) {
|
|
2296
|
+
const i = remaining.findIndex((x) => atomEq(x, a));
|
|
2297
|
+
if (i >= 0) remaining.splice(i, 1);
|
|
2298
|
+
else added.push(a);
|
|
2299
|
+
}
|
|
2300
|
+
return { added, removed: remaining };
|
|
2301
|
+
}
|
|
2302
|
+
function applyAtomDelta(into, added, removed) {
|
|
2303
|
+
const out = into.slice();
|
|
2304
|
+
for (const r of removed) {
|
|
2305
|
+
const i = out.findIndex((x) => atomEq(x, r));
|
|
2306
|
+
if (i >= 0) out.splice(i, 1);
|
|
2307
|
+
}
|
|
2308
|
+
out.push(...added);
|
|
2309
|
+
return out;
|
|
2310
|
+
}
|
|
2311
|
+
function mergeWorlds(base, branches) {
|
|
2312
|
+
const baseSelf = logToArray(base.selfExtra);
|
|
2313
|
+
let selfExtra = baseSelf.slice();
|
|
2314
|
+
const spaces = new Map(base.spaces);
|
|
2315
|
+
const store = new Map(base.store);
|
|
2316
|
+
const tokens = new Map(base.tokens);
|
|
2317
|
+
for (const w of branches) {
|
|
2318
|
+
const d = multisetDelta(baseSelf, logToArray(w.selfExtra));
|
|
2319
|
+
selfExtra = applyAtomDelta(selfExtra, d.added, d.removed);
|
|
2320
|
+
for (const [k, v] of w.spaces) {
|
|
2321
|
+
const baseV = base.spaces.get(k) ?? [];
|
|
2322
|
+
const sd = multisetDelta(baseV, v);
|
|
2323
|
+
spaces.set(k, applyAtomDelta(spaces.get(k) ?? baseV.slice(), sd.added, sd.removed));
|
|
2324
|
+
}
|
|
2325
|
+
for (const [k, v] of w.store) if (!Object.is(base.store.get(k), v)) store.set(k, v);
|
|
2326
|
+
for (const [k, v] of w.tokens) if (!Object.is(base.tokens.get(k), v)) tokens.set(k, v);
|
|
2327
|
+
}
|
|
2328
|
+
const merged = {
|
|
2329
|
+
spaces,
|
|
2330
|
+
store,
|
|
2331
|
+
tokens,
|
|
2332
|
+
selfExtra: logFromArray(selfExtra),
|
|
2333
|
+
selfRules: /* @__PURE__ */ new Map(),
|
|
2334
|
+
selfVarRules: [],
|
|
2335
|
+
maxStackDepth: base.maxStackDepth
|
|
2336
|
+
};
|
|
2337
|
+
indexSelfRules(merged, selfExtra);
|
|
2338
|
+
return merged;
|
|
2339
|
+
}
|
|
2340
|
+
function mutexKey(a) {
|
|
2341
|
+
switch (a.kind) {
|
|
2342
|
+
case "sym":
|
|
2343
|
+
return "s:" + a.name;
|
|
2344
|
+
case "var":
|
|
2345
|
+
return "v:" + a.name;
|
|
2346
|
+
case "gnd": {
|
|
2347
|
+
const g = a.value;
|
|
2348
|
+
return g.g === "str" ? "S:" + g.s : g.g === "int" || g.g === "float" ? "n:" + g.n : "g:" + g.g;
|
|
2349
|
+
}
|
|
2350
|
+
case "expr":
|
|
2351
|
+
return "e:[" + a.items.map(mutexKey).join(",") + "]";
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
function resolveTok(w, a) {
|
|
2355
|
+
if (a.kind === "sym") return w.tokens.get(a.name) ?? a;
|
|
2356
|
+
return a;
|
|
2357
|
+
}
|
|
2358
|
+
var stateHandle = (id) => expr([sym("State"), gint(id)]);
|
|
2359
|
+
function stateId(w, a) {
|
|
2360
|
+
const r = resolveTok(w, a);
|
|
2361
|
+
if (opOf(r) === "State" && r.kind === "expr" && r.items.length === 2) {
|
|
2362
|
+
const g = r.items[1];
|
|
2363
|
+
if (g.kind === "gnd" && g.value.g === "int") return Number(g.value.n);
|
|
2364
|
+
}
|
|
2365
|
+
return void 0;
|
|
2366
|
+
}
|
|
2367
|
+
function spaceName(w, a) {
|
|
2368
|
+
const r = resolveTok(w, a);
|
|
2369
|
+
return r.kind === "sym" ? r.name : void 0;
|
|
2370
|
+
}
|
|
2371
|
+
function resolveStates(w, a) {
|
|
2372
|
+
if (w.store.size === 0) return a;
|
|
2373
|
+
if (a.kind === "expr") {
|
|
2374
|
+
if (opOf(a) === "State" && a.items.length === 2) {
|
|
2375
|
+
const g = a.items[1];
|
|
2376
|
+
if (g.kind === "gnd" && g.value.g === "int") return w.store.get(Number(g.value.n)) ?? a;
|
|
2377
|
+
}
|
|
2378
|
+
return expr(a.items.map((x) => resolveStates(w, x)));
|
|
2379
|
+
}
|
|
2380
|
+
return a;
|
|
2381
|
+
}
|
|
2382
|
+
function subTokens(w, a) {
|
|
2383
|
+
if (w.tokens.size === 0) return a;
|
|
2384
|
+
if (a.kind === "sym") return w.tokens.get(a.name) ?? a;
|
|
2385
|
+
if (a.kind === "expr") return expr(a.items.map((x) => subTokens(w, x)));
|
|
2386
|
+
return a;
|
|
2387
|
+
}
|
|
2388
|
+
function wrapStates(w, a) {
|
|
2389
|
+
if (w.store.size === 0) return a;
|
|
2390
|
+
if (a.kind === "expr") {
|
|
2391
|
+
if (opOf(a) === "State" && a.items.length === 2) {
|
|
2392
|
+
const g = a.items[1];
|
|
2393
|
+
if (g.kind === "gnd" && g.value.g === "int") {
|
|
2394
|
+
const v = w.store.get(Number(g.value.n));
|
|
2395
|
+
return v !== void 0 ? expr([sym("StateValue"), v]) : a;
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
return expr(a.items.map((x) => wrapStates(w, x)));
|
|
2399
|
+
}
|
|
2400
|
+
return a;
|
|
2401
|
+
}
|
|
2402
|
+
var typePrep = (w, a) => wrapStates(w, subTokens(w, a));
|
|
2403
|
+
function candidatesW(env, w, toEval) {
|
|
2404
|
+
const k2 = headKey(toEval);
|
|
2405
|
+
const headRules = k2 !== void 0 ? w.selfRules.get(k2) ?? [] : [];
|
|
2406
|
+
return [...candidates(env, toEval), ...headRules, ...w.selfVarRules];
|
|
2407
|
+
}
|
|
2408
|
+
var ruleVarsCache = /* @__PURE__ */ new WeakMap();
|
|
2409
|
+
function ruleVars(lhs, rhs) {
|
|
2410
|
+
let vs = ruleVarsCache.get(lhs);
|
|
2411
|
+
if (vs === void 0) {
|
|
2412
|
+
vs = atomVars(lhs);
|
|
2413
|
+
const seen = new Set(vs);
|
|
2414
|
+
for (const v of atomVars(rhs))
|
|
2415
|
+
if (!seen.has(v)) {
|
|
2416
|
+
seen.add(v);
|
|
2417
|
+
vs.push(v);
|
|
2418
|
+
}
|
|
2419
|
+
ruleVarsCache.set(lhs, vs);
|
|
2420
|
+
}
|
|
2421
|
+
return vs;
|
|
2422
|
+
}
|
|
2423
|
+
function freshenSub(counter, lhs, rhs) {
|
|
2424
|
+
const vs = ruleVars(lhs, rhs);
|
|
2425
|
+
return vs.length === 0 ? [] : vs.map((v) => [v, variable(v + "#" + String(counter))]);
|
|
2426
|
+
}
|
|
2427
|
+
function freshenRule(counter, lhs, rhs) {
|
|
2428
|
+
const sub = freshenSub(counter, lhs, rhs);
|
|
2429
|
+
if (sub.length === 0) return [lhs, rhs];
|
|
2430
|
+
return [applySubst(sub, lhs), applySubst(sub, rhs)];
|
|
2431
|
+
}
|
|
2432
|
+
function canMatchShallow(lhs, toEval) {
|
|
2433
|
+
if (lhs.kind === "var" || toEval.kind === "var") return true;
|
|
2434
|
+
if (lhs.kind === "sym") return toEval.kind === "sym" && toEval.name === lhs.name;
|
|
2435
|
+
if (lhs.kind === "gnd") return atomEq(lhs, toEval);
|
|
2436
|
+
return toEval.kind === "expr" && toEval.items.length === lhs.items.length && canMatchShallow(lhs.items[0], toEval.items[0]);
|
|
2437
|
+
}
|
|
2438
|
+
function queryOp(env, st, prev, toEval, b) {
|
|
2439
|
+
if (isVariableHeaded(toEval)) return [[finItem(prev, notReducibleA, b)], st];
|
|
2440
|
+
const cands = candidatesW(env, st.world, toEval);
|
|
2441
|
+
const out = [];
|
|
2442
|
+
let counter = st.counter;
|
|
2443
|
+
for (const [lhs0, rhs0] of cands) {
|
|
2444
|
+
if (!canMatchShallow(lhs0, toEval)) {
|
|
2445
|
+
counter += 1;
|
|
2446
|
+
continue;
|
|
2447
|
+
}
|
|
2448
|
+
const suffix = "#" + counter;
|
|
2449
|
+
counter += 1;
|
|
2450
|
+
for (const mb of matchAtomsScoped(lhs0, toEval, suffix)) {
|
|
2451
|
+
for (const m of merge(b, mb)) {
|
|
2452
|
+
if (!hasLoop(m)) out.push(evalResult(prev, instantiate(m, rhs0, suffix), m));
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
const st2 = { counter, world: st.world };
|
|
2457
|
+
if (out.length === 0) return [[finItem(prev, notReducibleA, b)], st2];
|
|
2458
|
+
return [out, st2];
|
|
2459
|
+
}
|
|
2460
|
+
function hasRuleFor(env, w, counter, a) {
|
|
2461
|
+
for (const [lhs, rhs] of candidatesW(env, w, a)) {
|
|
2462
|
+
const [fl] = freshenRule(counter, lhs, rhs);
|
|
2463
|
+
if (matchAtoms(fl, a).length > 0) return true;
|
|
2464
|
+
}
|
|
2465
|
+
return false;
|
|
2466
|
+
}
|
|
2467
|
+
function* evalOpG(env, st, prev, x, b) {
|
|
2468
|
+
const x2 = instantiate(b, x);
|
|
2469
|
+
const op = opOf(x2);
|
|
2470
|
+
const useGrounded = op !== void 0 && x2.kind === "expr" && !(pettaOpNames.has(op) && hasRuleFor(env, st.world, st.counter, x2));
|
|
2471
|
+
if (useGrounded) {
|
|
2472
|
+
const args = x2.items.slice(1).map((a) => resolveStates(st.world, subTokens(st.world, a)));
|
|
2473
|
+
const r = yield* callGroundedG(env, op, args);
|
|
2474
|
+
if (r.tag === "ok") return [r.results.map((res) => evalResult(prev, res, b)), st];
|
|
2475
|
+
if (r.tag === "runtimeError") return [[finItem(prev, errAtom(x2, r.msg), b)], st];
|
|
2476
|
+
if (r.tag === "incorrectArgument") return [[finItem(prev, notReducibleA, b)], st];
|
|
2477
|
+
}
|
|
2478
|
+
if (x2.kind === "expr" && x2.items.length > 0) {
|
|
2479
|
+
const head = x2.items[0];
|
|
2480
|
+
if (head.kind === "gnd" && head.exec !== void 0) {
|
|
2481
|
+
const args = x2.items.slice(1).map((a) => resolveStates(st.world, subTokens(st.world, a)));
|
|
2482
|
+
try {
|
|
2483
|
+
const results = head.exec(args);
|
|
2484
|
+
return [results.map((res) => evalResult(prev, res, b)), st];
|
|
2485
|
+
} catch (e) {
|
|
2486
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2487
|
+
return [[finItem(prev, errAtom(x2, msg), b)], st];
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
if (isEmbeddedOp(x2)) return [[{ stack: atomToStack(x2, prev), bnd: b }], st];
|
|
2492
|
+
return queryOp(env, st, prev, x2, b);
|
|
2493
|
+
}
|
|
2494
|
+
function unifyOp(prev, a, p, t, e, b) {
|
|
2495
|
+
const ms = [];
|
|
2496
|
+
for (const mb of matchAtoms(a, p))
|
|
2497
|
+
for (const m of merge(b, mb)) if (!hasLoop(m)) ms.push(finItem(prev, instantiate(m, t), m));
|
|
2498
|
+
return ms.length === 0 ? [finItem(prev, e, b)] : ms;
|
|
2499
|
+
}
|
|
2500
|
+
var isFinal = (it) => it.stack !== null && it.stack.tail === null && it.stack.head.fin;
|
|
2501
|
+
function finalPair(it) {
|
|
2502
|
+
const f = it.stack;
|
|
2503
|
+
return f === null ? [emptyA, []] : [instantiate(it.bnd, f.head.atom), it.bnd];
|
|
2504
|
+
}
|
|
2505
|
+
function exhaustedPair(it) {
|
|
2506
|
+
const f = it.stack;
|
|
2507
|
+
return f === null ? [emptyA, it.bnd] : [expr([sym("Error"), instantiate(it.bnd, f.head.atom), sym("StackOverflow")]), it.bnd];
|
|
2508
|
+
}
|
|
2509
|
+
function resolveAtomFix(b, n, a) {
|
|
2510
|
+
let cur = a;
|
|
2511
|
+
for (let i = 0; i < n; i++) {
|
|
2512
|
+
const next = instantiate(b, cur);
|
|
2513
|
+
if (atomEq(next, cur)) return cur;
|
|
2514
|
+
cur = next;
|
|
2515
|
+
}
|
|
2516
|
+
return cur;
|
|
2517
|
+
}
|
|
2518
|
+
function restrictBnd(vars, b) {
|
|
2519
|
+
const solved = [];
|
|
2520
|
+
for (const x of vars) {
|
|
2521
|
+
const v = resolveAtomFix(b, b.length + 1, variable(x));
|
|
2522
|
+
if (!(v.kind === "var" && v.name === x)) solved.push({ tag: "val", x, a: v, y: void 0 });
|
|
2523
|
+
}
|
|
2524
|
+
if (!b.some((r) => r.tag === "eq")) return solved;
|
|
2525
|
+
const vset = new Set(vars);
|
|
2526
|
+
const eqs = b.filter((r) => r.tag === "eq" && vset.has(r.x) && vset.has(r.y));
|
|
2527
|
+
return solved.length === 0 ? eqs : [...solved, ...eqs];
|
|
2528
|
+
}
|
|
2529
|
+
function mergeRestrict(vars, baseB, pb) {
|
|
2530
|
+
const merged = merge(baseB, pb);
|
|
2531
|
+
return restrictBnd(vars, merged.length > 0 ? merged[0] : pb);
|
|
2532
|
+
}
|
|
2533
|
+
function scopeVars(b, prev) {
|
|
2534
|
+
const out = [];
|
|
2535
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2536
|
+
for (let p = prev; p !== null; p = p.tail) collectVars(instantiate(b, p.head.atom), out, seen);
|
|
2537
|
+
return out;
|
|
2538
|
+
}
|
|
2539
|
+
function frameVars(prev) {
|
|
2540
|
+
const out = [];
|
|
2541
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2542
|
+
for (let p = prev; p !== null; p = p.tail) collectVars(p.head.atom, out, seen);
|
|
2543
|
+
return out;
|
|
2544
|
+
}
|
|
2545
|
+
function superposeItem(prev, b, pair) {
|
|
2546
|
+
if (pair.kind === "expr" && pair.items.length > 0) return finItem(prev, pair.items[0], b);
|
|
2547
|
+
return finItem(prev, pair, b);
|
|
2548
|
+
}
|
|
2549
|
+
function argMask(ts, arity) {
|
|
2550
|
+
const mask = new Array(arity);
|
|
2551
|
+
if (ts === void 0) {
|
|
2552
|
+
mask.fill(true);
|
|
2553
|
+
return mask;
|
|
2554
|
+
}
|
|
2555
|
+
for (let i = 0; i < arity; i++) {
|
|
2556
|
+
const t = ts[i];
|
|
2557
|
+
mask[i] = t === void 0 || !(t.kind === "sym" && (t.name === "Atom" || t.name === "Variable" || t.name === "Expression"));
|
|
2558
|
+
}
|
|
2559
|
+
return mask;
|
|
2560
|
+
}
|
|
2561
|
+
function returnsAtom(env, a) {
|
|
2562
|
+
const op = headKey(a);
|
|
2563
|
+
if (op === void 0) return false;
|
|
2564
|
+
const ts = env.sigs.get(op);
|
|
2565
|
+
const last = ts && ts.length > 0 ? ts[ts.length - 1] : void 0;
|
|
2566
|
+
return last !== void 0 && atomEq(last, sym("Atom"));
|
|
2567
|
+
}
|
|
2568
|
+
function functionArity(env, w, name) {
|
|
2569
|
+
const sig = env.sigs.get(name);
|
|
2570
|
+
if (sig !== void 0 && sig.length >= 1) return sig.length - 1;
|
|
2571
|
+
for (const [lhs] of [...env.ruleIndex.get(name) ?? [], ...w.selfRules.get(name) ?? []])
|
|
2572
|
+
if (lhs.kind === "expr" && lhs.items.length >= 2) return lhs.items.length - 1;
|
|
2573
|
+
return void 0;
|
|
2574
|
+
}
|
|
2575
|
+
var headOr = (xs, d) => xs.length > 0 ? xs[0] : d;
|
|
2576
|
+
var UNDEF = sym("%Undefined%");
|
|
2577
|
+
var NUMBER_T = [sym("Number")];
|
|
2578
|
+
var STRING_T = [sym("String")];
|
|
2579
|
+
var BOOL_T = [sym("Bool")];
|
|
2580
|
+
var GROUNDED_T = [sym("Grounded")];
|
|
2581
|
+
var UNDEF_T = [UNDEF];
|
|
2582
|
+
function getTypes(env, a) {
|
|
2583
|
+
if (a.ground) {
|
|
2584
|
+
const cache3 = env.typeCache ??= /* @__PURE__ */ new WeakMap();
|
|
2585
|
+
const hit = cache3.get(a);
|
|
2586
|
+
if (hit !== void 0) return hit;
|
|
2587
|
+
const r = getTypesUncached(env, a);
|
|
2588
|
+
cache3.set(a, r);
|
|
2589
|
+
return r;
|
|
2590
|
+
}
|
|
2591
|
+
return getTypesUncached(env, a);
|
|
2592
|
+
}
|
|
2593
|
+
function getTypesUncached(env, a) {
|
|
2594
|
+
if (a.kind === "gnd") {
|
|
2595
|
+
const g = a.value;
|
|
2596
|
+
if (g.g === "int" || g.g === "float") return NUMBER_T;
|
|
2597
|
+
if (g.g === "str") return STRING_T;
|
|
2598
|
+
if (g.g === "bool") return BOOL_T;
|
|
2599
|
+
return GROUNDED_T;
|
|
2600
|
+
}
|
|
2601
|
+
if (a.kind === "var") return UNDEF_T;
|
|
2602
|
+
if (a.kind === "sym") {
|
|
2603
|
+
const ts = env.types.get(a.name);
|
|
2604
|
+
return ts && ts.length > 0 ? ts : UNDEF_T;
|
|
2605
|
+
}
|
|
2606
|
+
if (a.items.length === 0) return UNDEF_T;
|
|
2607
|
+
if (opOf(a) === "StateValue" && a.items.length === 2)
|
|
2608
|
+
return [expr([sym("StateMonad"), headOr(getTypes(env, a.items[1]), UNDEF)])];
|
|
2609
|
+
const direct = env.exprTypes.filter((p) => atomEq(p[0], a));
|
|
2610
|
+
if (direct.length > 0) return direct.map((p) => p[1]);
|
|
2611
|
+
const f = a.items[0];
|
|
2612
|
+
const args = a.items.slice(1);
|
|
2613
|
+
const argTs = args.map((x) => headOr(getTypes(env, x), UNDEF));
|
|
2614
|
+
const fTypes = getTypes(env, f);
|
|
2615
|
+
const out = [];
|
|
2616
|
+
for (const t of fTypes) {
|
|
2617
|
+
if (opOf(t) === "->" && t.kind === "expr") {
|
|
2618
|
+
const ts = t.items.slice(1);
|
|
2619
|
+
const ret = ts.length > 0 ? ts[ts.length - 1] : UNDEF;
|
|
2620
|
+
const params = ts.slice(0, -1);
|
|
2621
|
+
let tb = [];
|
|
2622
|
+
for (let i = 0; i < params.length && i < argTs.length; i++) {
|
|
2623
|
+
const m = matchAtoms(instantiate(tb, params[i]), argTs[i]);
|
|
2624
|
+
if (m.length > 0) {
|
|
2625
|
+
const merged = merge(tb, m[0]);
|
|
2626
|
+
if (merged.length > 0) tb = merged[0];
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
out.push(instantiate(tb, ret));
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
return out.length > 0 ? out : UNDEF_T;
|
|
2633
|
+
}
|
|
2634
|
+
function getTypesForQuery(env, a) {
|
|
2635
|
+
const base = getTypes(env, a);
|
|
2636
|
+
if (a.kind !== "expr" || a.items.length === 0) return base;
|
|
2637
|
+
if (base.length > 0 && !base.every((t) => atomEq(t, UNDEF))) return base;
|
|
2638
|
+
const f = a.items[0];
|
|
2639
|
+
if (getTypes(env, f).some((t) => opOf(t) === "->")) return base;
|
|
2640
|
+
let combos = [[]];
|
|
2641
|
+
for (const x of a.items) {
|
|
2642
|
+
const ts = getTypesForQuery(env, x);
|
|
2643
|
+
const opts = ts.length > 0 ? ts : [UNDEF];
|
|
2644
|
+
const next = [];
|
|
2645
|
+
for (const combo of combos) for (const t of opts) next.push([...combo, t]);
|
|
2646
|
+
combos = next;
|
|
2647
|
+
}
|
|
2648
|
+
return combos.map((c) => expr(c));
|
|
2649
|
+
}
|
|
2650
|
+
function matchReduced(tb, expected, actual) {
|
|
2651
|
+
if (atomEq(expected, UNDEF) || atomEq(actual, UNDEF)) return tb;
|
|
2652
|
+
if (expected.kind === "expr" && actual.kind === "expr")
|
|
2653
|
+
return matchReducedList(tb, expected.items, actual.items);
|
|
2654
|
+
for (const mb of matchAtoms(expected, actual)) {
|
|
2655
|
+
const merged = merge(tb, mb);
|
|
2656
|
+
if (merged.length > 0) return merged[0];
|
|
2657
|
+
}
|
|
2658
|
+
return void 0;
|
|
2659
|
+
}
|
|
2660
|
+
function matchReducedList(tb, es, acts) {
|
|
2661
|
+
if (es.length !== acts.length) return void 0;
|
|
2662
|
+
let cur = tb;
|
|
2663
|
+
for (let i = 0; i < es.length; i++) {
|
|
2664
|
+
const r = matchReduced(cur, es[i], acts[i]);
|
|
2665
|
+
if (r === void 0) return void 0;
|
|
2666
|
+
cur = r;
|
|
2667
|
+
}
|
|
2668
|
+
return cur;
|
|
2669
|
+
}
|
|
2670
|
+
function matchType(tb, expected, actual) {
|
|
2671
|
+
if (atomEq(expected, UNDEF) || atomEq(actual, UNDEF) || atomEq(expected, sym("Atom")) || atomEq(actual, sym("Atom")))
|
|
2672
|
+
return tb;
|
|
2673
|
+
return matchReduced(tb, expected, actual);
|
|
2674
|
+
}
|
|
2675
|
+
function typeCheckArgs(env, w, argTypes, i, tb, argsLeft) {
|
|
2676
|
+
if (argsLeft.length === 0) return void 0;
|
|
2677
|
+
const ti0 = argTypes[i];
|
|
2678
|
+
if (ti0 === void 0) return void 0;
|
|
2679
|
+
const ti = instantiate(tb, ti0);
|
|
2680
|
+
if (ti.kind === "sym" && (ti.name === "Atom" || ti.name === "%Undefined%"))
|
|
2681
|
+
return typeCheckArgs(env, w, argTypes, i + 1, tb, argsLeft.slice(1));
|
|
2682
|
+
const ai = argsLeft[0];
|
|
2683
|
+
const prepped = typePrep(w, ai);
|
|
2684
|
+
if (ti.kind === "sym" && ti.name === metaType(prepped))
|
|
2685
|
+
return typeCheckArgs(env, w, argTypes, i + 1, tb, argsLeft.slice(1));
|
|
2686
|
+
const actuals = getTypes(env, prepped);
|
|
2687
|
+
for (const act of actuals) {
|
|
2688
|
+
const tb2 = matchType(tb, ti, act);
|
|
2689
|
+
if (tb2 !== void 0) return typeCheckArgs(env, w, argTypes, i + 1, tb2, argsLeft.slice(1));
|
|
2690
|
+
}
|
|
2691
|
+
return [i + 1, ti, headOr(actuals, UNDEF)];
|
|
2692
|
+
}
|
|
2693
|
+
function typeMismatch(env, w, op, args, ts = env.sigs.get(op)) {
|
|
2694
|
+
if (ts === void 0) return void 0;
|
|
2695
|
+
return typeCheckArgs(env, w, ts.slice(0, -1), 0, [], args);
|
|
2696
|
+
}
|
|
2697
|
+
function matchCandidates(env, w, pInst) {
|
|
2698
|
+
const k = headKey(pInst);
|
|
2699
|
+
if (k === void 0) {
|
|
2700
|
+
const extra2 = logToArray(w.selfExtra);
|
|
2701
|
+
const all = extra2.length === 0 ? env.atoms.slice() : [...env.atoms, ...extra2];
|
|
2702
|
+
return resolveAll(w, all);
|
|
2703
|
+
}
|
|
2704
|
+
let bestKey;
|
|
2705
|
+
let bestPosKey;
|
|
2706
|
+
let bestSize = Infinity;
|
|
2707
|
+
if (pInst.kind === "expr")
|
|
2708
|
+
for (let i = 1; i < pInst.items.length; i++) {
|
|
2709
|
+
const ak = argKey(pInst.items[i]);
|
|
2710
|
+
if (ak === void 0) continue;
|
|
2711
|
+
const ik = k + KEY_SEP + i + KEY_SEP + ak;
|
|
2712
|
+
const posKey = k + KEY_SEP + i;
|
|
2713
|
+
const size = (env.argIndex.get(ik)?.length ?? 0) + (env.nonGroundAtPos.get(posKey)?.length ?? 0);
|
|
2714
|
+
if (size < bestSize) {
|
|
2715
|
+
bestSize = size;
|
|
2716
|
+
bestKey = ik;
|
|
2717
|
+
bestPosKey = posKey;
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
let cands;
|
|
2721
|
+
if (bestKey !== void 0) {
|
|
2722
|
+
cands = [...env.argIndex.get(bestKey) ?? [], ...env.nonGroundAtPos.get(bestPosKey) ?? []];
|
|
2723
|
+
} else {
|
|
2724
|
+
cands = (env.factIndex.get(k) ?? []).slice();
|
|
2725
|
+
}
|
|
2726
|
+
cands.push(...env.varHeadedFacts);
|
|
2727
|
+
if (pInst.ground && logNonGround(w.selfExtra) === 0 && w.store.size === 0) {
|
|
2728
|
+
const c = idxCount(logGroundIdx(w.selfExtra), pInst);
|
|
2729
|
+
for (let i = 0; i < c; i++) cands.push(pInst);
|
|
2730
|
+
return cands;
|
|
2731
|
+
}
|
|
2732
|
+
const extra = logToArray(w.selfExtra);
|
|
2733
|
+
for (const a of extra) {
|
|
2734
|
+
const akk = headKey(a);
|
|
2735
|
+
if (akk === void 0 || akk === k) cands.push(a);
|
|
2736
|
+
}
|
|
2737
|
+
return resolveAll(w, cands);
|
|
2738
|
+
}
|
|
2739
|
+
function resolveAll(w, atoms) {
|
|
2740
|
+
return w.store.size === 0 ? atoms : atoms.map((x) => resolveStates(w, x));
|
|
2741
|
+
}
|
|
2742
|
+
function matchConj(getCandidates, patterns, st, sols) {
|
|
2743
|
+
let cur = sols;
|
|
2744
|
+
let counter = st.counter;
|
|
2745
|
+
for (const p of patterns) {
|
|
2746
|
+
const next = [];
|
|
2747
|
+
for (const b of cur) {
|
|
2748
|
+
const pInst = instantiate(b, p);
|
|
2749
|
+
for (const atom of getCandidates(pInst)) {
|
|
2750
|
+
const atom2 = freshenRule(counter, atom, atom)[0];
|
|
2751
|
+
counter += 1;
|
|
2752
|
+
for (const mb of matchAtoms(pInst, atom2))
|
|
2753
|
+
for (const m of merge(b, mb)) if (!hasLoop(m)) next.push(m);
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
cur = next;
|
|
2757
|
+
}
|
|
2758
|
+
return [cur, { counter, world: st.world }];
|
|
2759
|
+
}
|
|
2760
|
+
function matchConjJoin(getCandidates, patterns, st, b0) {
|
|
2761
|
+
let counter = st.counter;
|
|
2762
|
+
const groundRels = [];
|
|
2763
|
+
const otherPatterns = [];
|
|
2764
|
+
for (const p of patterns) {
|
|
2765
|
+
const pInst = instantiate(b0, p);
|
|
2766
|
+
const pvars = atomVars(pInst);
|
|
2767
|
+
if (pvars.length === 0) {
|
|
2768
|
+
otherPatterns.push(p);
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
const tuples = [];
|
|
2772
|
+
let allGround = true;
|
|
2773
|
+
for (const atom of getCandidates(pInst)) {
|
|
2774
|
+
const fresh = freshenRule(counter, atom, atom)[0];
|
|
2775
|
+
counter += 1;
|
|
2776
|
+
for (const mb of matchAtoms(pInst, fresh)) {
|
|
2777
|
+
const t = /* @__PURE__ */ new Map();
|
|
2778
|
+
for (const v of pvars) {
|
|
2779
|
+
const val = instantiate(mb, variable(v));
|
|
2780
|
+
t.set(v, val);
|
|
2781
|
+
if (!val.ground) allGround = false;
|
|
2782
|
+
}
|
|
2783
|
+
tuples.push(t);
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
if (allGround) groundRels.push({ vars: pvars, tuples });
|
|
2787
|
+
else otherPatterns.push(p);
|
|
2788
|
+
}
|
|
2789
|
+
let cur;
|
|
2790
|
+
if (groundRels.length > 0) {
|
|
2791
|
+
cur = [];
|
|
2792
|
+
for (const sol of wcoJoin(groundRels, mutexKey)) {
|
|
2793
|
+
let bs = [b0];
|
|
2794
|
+
for (const [v, val] of sol) {
|
|
2795
|
+
const nb = [];
|
|
2796
|
+
for (const b of bs) nb.push(...addVarBinding(b, v, val));
|
|
2797
|
+
bs = nb;
|
|
2798
|
+
}
|
|
2799
|
+
for (const b of bs) if (!hasLoop(b)) cur.push(b);
|
|
2800
|
+
}
|
|
2801
|
+
} else {
|
|
2802
|
+
cur = [b0];
|
|
2803
|
+
}
|
|
2804
|
+
for (const p of otherPatterns) {
|
|
2805
|
+
const next = [];
|
|
2806
|
+
const freshCache = /* @__PURE__ */ new Map();
|
|
2807
|
+
for (const b of cur) {
|
|
2808
|
+
const pInst = instantiate(b, p);
|
|
2809
|
+
for (const atom of getCandidates(pInst)) {
|
|
2810
|
+
let fresh = freshCache.get(atom);
|
|
2811
|
+
if (fresh === void 0) {
|
|
2812
|
+
fresh = freshenRule(counter, atom, atom)[0];
|
|
2813
|
+
counter += 1;
|
|
2814
|
+
freshCache.set(atom, fresh);
|
|
2815
|
+
}
|
|
2816
|
+
for (const mb of matchAtoms(pInst, fresh))
|
|
2817
|
+
for (const m of merge(b, mb)) if (!hasLoop(m)) next.push(m);
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
cur = next;
|
|
2821
|
+
}
|
|
2822
|
+
return [cur, { counter, world: st.world }];
|
|
2823
|
+
}
|
|
2824
|
+
function getDocOf(env, w, atom) {
|
|
2825
|
+
const atoms = selfAtoms(env, w);
|
|
2826
|
+
const ty = atom.kind === "sym" ? headOr(env.types.get(atom.name) ?? [], UNDEF) : env.exprTypes.find((p) => atomEq(p[0], atom))?.[1] ?? UNDEF;
|
|
2827
|
+
const doc = atoms.find(
|
|
2828
|
+
(a) => opOf(a) === "@doc" && a.kind === "expr" && a.items.length >= 2 && atomEq(a.items[1], atom)
|
|
2829
|
+
);
|
|
2830
|
+
if (doc === void 0 || doc.kind !== "expr") return sym("Empty");
|
|
2831
|
+
if (doc.items.length === 5) {
|
|
2832
|
+
const desc = doc.items[2];
|
|
2833
|
+
const paramsWrap = doc.items[3];
|
|
2834
|
+
const retWrap = doc.items[4];
|
|
2835
|
+
const params = paramsWrap.kind === "expr" ? paramsWrap.items[1] : void 0;
|
|
2836
|
+
const paramList = params && params.kind === "expr" ? params.items : [];
|
|
2837
|
+
const retDesc = retWrap.kind === "expr" ? retWrap.items[1] : UNDEF;
|
|
2838
|
+
const n = paramList.length;
|
|
2839
|
+
let paramTys;
|
|
2840
|
+
let retTy;
|
|
2841
|
+
if (opOf(ty) === "->" && ty.kind === "expr" && ty.items.length - 1 === n + 1) {
|
|
2842
|
+
const rest = ty.items.slice(1);
|
|
2843
|
+
paramTys = rest.slice(0, -1);
|
|
2844
|
+
retTy = rest[rest.length - 1];
|
|
2845
|
+
} else {
|
|
2846
|
+
paramTys = Array(n).fill(UNDEF);
|
|
2847
|
+
retTy = UNDEF;
|
|
2848
|
+
}
|
|
2849
|
+
const params2 = paramList.map((pp, i) => {
|
|
2850
|
+
if (opOf(pp) === "@param" && pp.kind === "expr" && pp.items.length === 2)
|
|
2851
|
+
return expr([
|
|
2852
|
+
sym("@param"),
|
|
2853
|
+
expr([sym("@type"), paramTys[i] ?? UNDEF]),
|
|
2854
|
+
expr([sym("@desc"), pp.items[1]])
|
|
2855
|
+
]);
|
|
2856
|
+
return pp;
|
|
2857
|
+
});
|
|
2858
|
+
return expr([
|
|
2859
|
+
sym("@doc-formal"),
|
|
2860
|
+
expr([sym("@item"), atom]),
|
|
2861
|
+
expr([sym("@kind"), sym("function")]),
|
|
2862
|
+
expr([sym("@type"), ty]),
|
|
2863
|
+
desc,
|
|
2864
|
+
expr([sym("@params"), expr(params2)]),
|
|
2865
|
+
expr([sym("@return"), expr([sym("@type"), retTy]), expr([sym("@desc"), retDesc])])
|
|
2866
|
+
]);
|
|
2867
|
+
}
|
|
2868
|
+
if (doc.items.length === 3) {
|
|
2869
|
+
return expr([
|
|
2870
|
+
sym("@doc-formal"),
|
|
2871
|
+
expr([sym("@item"), atom]),
|
|
2872
|
+
expr([sym("@kind"), sym("atom")]),
|
|
2873
|
+
expr([sym("@type"), ty]),
|
|
2874
|
+
doc.items[2]
|
|
2875
|
+
]);
|
|
2876
|
+
}
|
|
2877
|
+
return sym("Empty");
|
|
2878
|
+
}
|
|
2879
|
+
function* interpretStack1G(env, fuel, st, it) {
|
|
2880
|
+
if (it.stack === null) return [[], st];
|
|
2881
|
+
const top = it.stack.head;
|
|
2882
|
+
const prev = it.stack.tail;
|
|
2883
|
+
if (top.fin) {
|
|
2884
|
+
if (prev === null) return [[it], st];
|
|
2885
|
+
const pf = prev.head;
|
|
2886
|
+
const pprev = prev.tail;
|
|
2887
|
+
const res = instantiate(it.bnd, top.atom);
|
|
2888
|
+
if (pf.ret === "chain") {
|
|
2889
|
+
if (opOf(pf.atom) === "chain" && pf.atom.kind === "expr" && pf.atom.items.length === 4) {
|
|
2890
|
+
const v = pf.atom.items[2];
|
|
2891
|
+
const templ = pf.atom.items[3];
|
|
2892
|
+
const nf = frame(expr([sym("chain"), res, v, templ]), pf.ret, pf.vars, false);
|
|
2893
|
+
return [[{ stack: cons(nf, pprev), bnd: it.bnd }], st];
|
|
2894
|
+
}
|
|
2895
|
+
return [[finItem(pprev, errAtom(pf.atom, "chain: corrupt frame"), it.bnd)], st];
|
|
2896
|
+
}
|
|
2897
|
+
if (pf.ret === "function") {
|
|
2898
|
+
if (opOf(res) === "return" && res.kind === "expr" && res.items.length === 2)
|
|
2899
|
+
return [[finItem(pprev, res.items[1], it.bnd)], st];
|
|
2900
|
+
if (isEmbeddedOp(res))
|
|
2901
|
+
return [[{ stack: atomToStack(res, cons(pf, pprev)), bnd: it.bnd }], st];
|
|
2902
|
+
const target = pprev !== null ? pprev.head.atom : res;
|
|
2903
|
+
return [[finItem(pprev, errAtom(target, "NoReturn"), it.bnd)], st];
|
|
2904
|
+
}
|
|
2905
|
+
return [[], st];
|
|
2906
|
+
}
|
|
2907
|
+
const a = top.atom;
|
|
2908
|
+
const op = opOf(a);
|
|
2909
|
+
const it2 = a.kind === "expr" ? a.items : [];
|
|
2910
|
+
switch (op) {
|
|
2911
|
+
case "eval":
|
|
2912
|
+
if (it2.length === 2) return yield* evalOpG(env, st, prev, it2[1], it.bnd);
|
|
2913
|
+
break;
|
|
2914
|
+
case "evalc":
|
|
2915
|
+
if (it2.length === 3) return yield* evalOpG(env, st, prev, it2[1], it.bnd);
|
|
2916
|
+
break;
|
|
2917
|
+
case "chain":
|
|
2918
|
+
if (it2.length === 4 && it2[2].kind === "var") {
|
|
2919
|
+
const v = it2[2].name;
|
|
2920
|
+
const cont = applySubst([[v, it2[1]]], it2[3]);
|
|
2921
|
+
const bnd = restrictBnd(atomVars(cont, frameVars(prev)), it.bnd);
|
|
2922
|
+
return [[{ stack: atomToStack(cont, prev), bnd }], st];
|
|
2923
|
+
}
|
|
2924
|
+
break;
|
|
2925
|
+
case "unify":
|
|
2926
|
+
if (it2.length === 5) return [unifyOp(prev, it2[1], it2[2], it2[3], it2[4], it.bnd), st];
|
|
2927
|
+
break;
|
|
2928
|
+
case "cons-atom":
|
|
2929
|
+
if (it2.length === 3 && it2[2].kind === "expr")
|
|
2930
|
+
return [[finItem(prev, expr([it2[1], ...it2[2].items]), it.bnd)], st];
|
|
2931
|
+
if (it2.length === 3)
|
|
2932
|
+
return [[finItem(prev, errAtom(a, "cons-atom: expected expression tail"), it.bnd)], st];
|
|
2933
|
+
break;
|
|
2934
|
+
case "decons-atom":
|
|
2935
|
+
if (it2.length === 2 && it2[1].kind === "expr" && it2[1].items.length > 0) {
|
|
2936
|
+
const [h, ...t] = it2[1].items;
|
|
2937
|
+
return [[finItem(prev, expr([h, expr(t)]), it.bnd)], st];
|
|
2938
|
+
}
|
|
2939
|
+
if (it2.length === 2)
|
|
2940
|
+
return [
|
|
2941
|
+
[finItem(prev, errAtom(a, "decons-atom: expected non-empty expression"), it.bnd)],
|
|
2942
|
+
st
|
|
2943
|
+
];
|
|
2944
|
+
break;
|
|
2945
|
+
case "context-space":
|
|
2946
|
+
if (it2.length === 1) return [[finItem(prev, sym("&self"), it.bnd)], st];
|
|
2947
|
+
break;
|
|
2948
|
+
case "metta":
|
|
2949
|
+
case "capture":
|
|
2950
|
+
case "metta-thread": {
|
|
2951
|
+
const atom = it2[1];
|
|
2952
|
+
const [pairs, st2] = yield* mettaEvalG(env, fuel, st, it.bnd, atom);
|
|
2953
|
+
if (op === "metta-thread") {
|
|
2954
|
+
const out = [];
|
|
2955
|
+
for (const p of pairs)
|
|
2956
|
+
for (const m of merge(it.bnd, restrictBnd(scopeVars(it.bnd, prev), p[1])))
|
|
2957
|
+
out.push(finItem(prev, p[0], m));
|
|
2958
|
+
return [out, st2];
|
|
2959
|
+
}
|
|
2960
|
+
return [pairs.map((p) => finItem(prev, p[0], it.bnd)), st2];
|
|
2961
|
+
}
|
|
2962
|
+
case "get-type":
|
|
2963
|
+
case "get-type-space": {
|
|
2964
|
+
let typeEnv = env;
|
|
2965
|
+
if (op === "get-type-space") {
|
|
2966
|
+
const sp = instantiate(it.bnd, it2[1]);
|
|
2967
|
+
const sname = sp.kind === "sym" ? sp.name : void 0;
|
|
2968
|
+
if (sname !== void 0 && sname !== "&self") {
|
|
2969
|
+
const sa = st.world.spaces.get(sname);
|
|
2970
|
+
if (sa !== void 0 && sa.length > 0) typeEnv = buildEnv([...env.atoms, ...sa], env.gt);
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
const x = op === "get-type-space" ? it2[2] : it2[1];
|
|
2974
|
+
return yield* getTypeOpG(typeEnv, fuel, st, prev, instantiate(it.bnd, x), it.bnd);
|
|
2975
|
+
}
|
|
2976
|
+
case "get-doc":
|
|
2977
|
+
if (it2.length === 2)
|
|
2978
|
+
return [[finItem(prev, getDocOf(env, st.world, instantiate(it.bnd, it2[1])), it.bnd)], st];
|
|
2979
|
+
break;
|
|
2980
|
+
case "match":
|
|
2981
|
+
if (it2.length === 4) return matchOp(env, st, prev, it2[1], it2[2], it2[3], it.bnd);
|
|
2982
|
+
break;
|
|
2983
|
+
case "superpose-bind":
|
|
2984
|
+
if (it2.length === 2 && it2[1].kind === "expr")
|
|
2985
|
+
return [it2[1].items.map((p) => superposeItem(prev, it.bnd, p)), st];
|
|
2986
|
+
break;
|
|
2987
|
+
case "collapse-bind": {
|
|
2988
|
+
if (it2.length !== 2) break;
|
|
2989
|
+
const [atoms, st2] = yield* interpretLoopG(env, fuel, st, [
|
|
2990
|
+
{ stack: atomToStack(it2[1], null), bnd: it.bnd }
|
|
2991
|
+
]);
|
|
2992
|
+
return [[finItem(prev, expr(atoms.map((p) => expr([p[0], unitA]))), it.bnd)], st2];
|
|
2993
|
+
}
|
|
2994
|
+
// TS-native extension. `(transaction <body>)` evaluates the body and atomically commits its
|
|
2995
|
+
// space mutations only if the body succeeds. Because the world is threaded copy-on-write
|
|
2996
|
+
// (cloneWorld -> new St), commit/rollback is snapshot-and-restore: keep the body's world on
|
|
2997
|
+
// success, restore the pre-body world otherwise. Rollback trigger (spec A2.1): the body throws
|
|
2998
|
+
// (an Error atom result) for every result, or produces zero results. The gensym counter always
|
|
2999
|
+
// advances (never reused after rollback).
|
|
3000
|
+
case "transaction": {
|
|
3001
|
+
if (it2.length !== 2) break;
|
|
3002
|
+
const snapshotWorld = st.world;
|
|
3003
|
+
const [pairs, st2] = yield* mettaEvalG(env, fuel, st, it.bnd, it2[1]);
|
|
3004
|
+
const committed = pairs.length > 0 && pairs.some((p) => !isErrorAtom(p[0]));
|
|
3005
|
+
const world = committed ? st2.world : snapshotWorld;
|
|
3006
|
+
return [pairs.map((p) => finItem(prev, p[0], it.bnd)), { counter: st2.counter, world }];
|
|
3007
|
+
}
|
|
3008
|
+
// TS-native concurrency (async-only; see docs/.../concurrency-primitives.md).
|
|
3009
|
+
case "par": {
|
|
3010
|
+
const branches = it2.slice(1);
|
|
3011
|
+
pendingAsyncOp = "par";
|
|
3012
|
+
const results = yield Promise.all(
|
|
3013
|
+
branches.map((br) => mettaEvalAsync(env, fuel, st, it.bnd, br))
|
|
3014
|
+
);
|
|
3015
|
+
const out = [];
|
|
3016
|
+
let counter = st.counter;
|
|
3017
|
+
const worlds = [];
|
|
3018
|
+
for (const [pairs, st2] of results) {
|
|
3019
|
+
for (const p of pairs) out.push(finItem(prev, p[0], it.bnd));
|
|
3020
|
+
worlds.push(st2.world);
|
|
3021
|
+
if (st2.counter > counter) counter = st2.counter;
|
|
3022
|
+
}
|
|
3023
|
+
return [out, { counter, world: mergeWorlds(st.world, worlds) }];
|
|
3024
|
+
}
|
|
3025
|
+
case "race": {
|
|
3026
|
+
const branches = it2.slice(1);
|
|
3027
|
+
pendingAsyncOp = "race";
|
|
3028
|
+
const winner = yield (async () => {
|
|
3029
|
+
const ac = new AbortController();
|
|
3030
|
+
try {
|
|
3031
|
+
return await Promise.any(
|
|
3032
|
+
branches.map(async (br) => {
|
|
3033
|
+
const r = await mettaEvalAsync(env, fuel, st, it.bnd, br, ac.signal);
|
|
3034
|
+
if (r[0].length === 0) throw new Error("empty branch");
|
|
3035
|
+
return r;
|
|
3036
|
+
})
|
|
3037
|
+
);
|
|
3038
|
+
} catch {
|
|
3039
|
+
return [[], st];
|
|
3040
|
+
} finally {
|
|
3041
|
+
ac.abort();
|
|
3042
|
+
}
|
|
3043
|
+
})();
|
|
3044
|
+
return [winner[0].map((p) => finItem(prev, p[0], it.bnd)), winner[1]];
|
|
3045
|
+
}
|
|
3046
|
+
case "once": {
|
|
3047
|
+
if (it2.length !== 2) break;
|
|
3048
|
+
const par = tryParHyperpose(env, st.world, it.bnd, it2[1], true);
|
|
3049
|
+
if (par !== void 0) {
|
|
3050
|
+
const first2 = par.length > 0 ? [par[0]] : [];
|
|
3051
|
+
return [first2.map((a2) => finItem(prev, a2, it.bnd)), st];
|
|
3052
|
+
}
|
|
3053
|
+
const [pairs, st2] = yield* mettaEvalG(env, fuel, st, it.bnd, it2[1]);
|
|
3054
|
+
const first = pairs.length > 0 ? [pairs[0]] : [];
|
|
3055
|
+
return [first.map((p) => finItem(prev, p[0], it.bnd)), st2];
|
|
3056
|
+
}
|
|
3057
|
+
case "with-mutex": {
|
|
3058
|
+
if (it2.length !== 3) break;
|
|
3059
|
+
const name = mutexKey(instantiate(it.bnd, it2[1]));
|
|
3060
|
+
const body = it2[2];
|
|
3061
|
+
pendingAsyncOp = "with-mutex";
|
|
3062
|
+
const result = yield (async () => {
|
|
3063
|
+
const prior = env.mutexes.get(name) ?? Promise.resolve();
|
|
3064
|
+
let release;
|
|
3065
|
+
const held = new Promise((r) => release = r);
|
|
3066
|
+
const chained = prior.then(() => held);
|
|
3067
|
+
env.mutexes.set(name, chained);
|
|
3068
|
+
await prior;
|
|
3069
|
+
try {
|
|
3070
|
+
return await mettaEvalAsync(env, fuel, st, it.bnd, body);
|
|
3071
|
+
} finally {
|
|
3072
|
+
release();
|
|
3073
|
+
if (env.mutexes.get(name) === chained) env.mutexes.delete(name);
|
|
3074
|
+
}
|
|
3075
|
+
})();
|
|
3076
|
+
return [result[0].map((p) => finItem(prev, p[0], it.bnd)), result[1]];
|
|
3077
|
+
}
|
|
3078
|
+
case "new-state": {
|
|
3079
|
+
if (it2.length !== 2) break;
|
|
3080
|
+
const id = st.counter;
|
|
3081
|
+
const w = cloneWorld(st.world);
|
|
3082
|
+
w.store.set(id, instantiate(it.bnd, it2[1]));
|
|
3083
|
+
return [[finItem(prev, stateHandle(id), it.bnd)], { counter: id + 1, world: w }];
|
|
3084
|
+
}
|
|
3085
|
+
case "get-state": {
|
|
3086
|
+
if (it2.length !== 2) break;
|
|
3087
|
+
const id = stateId(st.world, instantiate(it.bnd, it2[1]));
|
|
3088
|
+
if (id !== void 0) return [[finItem(prev, st.world.store.get(id) ?? emptyA, it.bnd)], st];
|
|
3089
|
+
return [
|
|
3090
|
+
[finItem(prev, errAtom(instantiate(it.bnd, it2[1]), "get-state: not a state"), it.bnd)],
|
|
3091
|
+
st
|
|
3092
|
+
];
|
|
3093
|
+
}
|
|
3094
|
+
case "change-state!": {
|
|
3095
|
+
if (it2.length !== 3) break;
|
|
3096
|
+
const id = stateId(st.world, instantiate(it.bnd, it2[1]));
|
|
3097
|
+
if (id !== void 0) {
|
|
3098
|
+
const w = cloneWorld(st.world);
|
|
3099
|
+
w.store.set(id, instantiate(it.bnd, it2[2]));
|
|
3100
|
+
return [[finItem(prev, stateHandle(id), it.bnd)], { counter: st.counter, world: w }];
|
|
3101
|
+
}
|
|
3102
|
+
return [
|
|
3103
|
+
[
|
|
3104
|
+
finItem(
|
|
3105
|
+
prev,
|
|
3106
|
+
errAtom(instantiate(it.bnd, it2[1]), "change-state!: not a state"),
|
|
3107
|
+
it.bnd
|
|
3108
|
+
)
|
|
3109
|
+
],
|
|
3110
|
+
st
|
|
3111
|
+
];
|
|
3112
|
+
}
|
|
3113
|
+
case "new-space":
|
|
3114
|
+
case "new-mork-space": {
|
|
3115
|
+
const id = st.counter;
|
|
3116
|
+
const name = "&space-" + String(id);
|
|
3117
|
+
const w = cloneWorld(st.world);
|
|
3118
|
+
w.spaces.set(name, []);
|
|
3119
|
+
return [[finItem(prev, sym(name), it.bnd)], { counter: id + 1, world: w }];
|
|
3120
|
+
}
|
|
3121
|
+
case "fork-space": {
|
|
3122
|
+
if (it2.length !== 2) break;
|
|
3123
|
+
const src = spaceName(st.world, instantiate(it.bnd, it2[1]));
|
|
3124
|
+
if (src === void 0)
|
|
3125
|
+
return [
|
|
3126
|
+
[finItem(prev, errAtom(instantiate(it.bnd, it2[1]), "fork-space: not a space"), it.bnd)],
|
|
3127
|
+
st
|
|
3128
|
+
];
|
|
3129
|
+
const srcAtoms = src === "&self" ? selfAtoms(env, st.world) : st.world.spaces.get(src) ?? [];
|
|
3130
|
+
const id = st.counter;
|
|
3131
|
+
const name = "&space-" + String(id);
|
|
3132
|
+
const w = cloneWorld(st.world);
|
|
3133
|
+
w.spaces.set(name, [...srcAtoms]);
|
|
3134
|
+
return [[finItem(prev, sym(name), it.bnd)], { counter: id + 1, world: w }];
|
|
3135
|
+
}
|
|
3136
|
+
case "add-atom":
|
|
3137
|
+
if (it2.length === 3) {
|
|
3138
|
+
const added = instantiate(it.bnd, it2[2]);
|
|
3139
|
+
if (opOf(added) === "=") disableTabling(env);
|
|
3140
|
+
return spaceMutate(st, prev, it2[1], it.bnd, (w, name) => appendSpace(w, name, [added]));
|
|
3141
|
+
}
|
|
3142
|
+
break;
|
|
3143
|
+
case "remove-atom":
|
|
3144
|
+
if (it2.length === 3)
|
|
3145
|
+
return spaceMutate(
|
|
3146
|
+
st,
|
|
3147
|
+
prev,
|
|
3148
|
+
it2[1],
|
|
3149
|
+
it.bnd,
|
|
3150
|
+
(w, name) => eraseSpace(w, name, instantiate(it.bnd, it2[2]))
|
|
3151
|
+
);
|
|
3152
|
+
break;
|
|
3153
|
+
case "get-atoms": {
|
|
3154
|
+
if (it2.length !== 2) break;
|
|
3155
|
+
const name = spaceName(st.world, instantiate(it.bnd, it2[1]));
|
|
3156
|
+
if (name === void 0)
|
|
3157
|
+
return [
|
|
3158
|
+
[finItem(prev, errAtom(instantiate(it.bnd, it2[1]), "get-atoms: not a space"), it.bnd)],
|
|
3159
|
+
st
|
|
3160
|
+
];
|
|
3161
|
+
const list = name === "&self" ? selfAtoms(env, st.world) : st.world.spaces.get(name) ?? [];
|
|
3162
|
+
return [list.map((x) => finItem(prev, x, it.bnd)), st];
|
|
3163
|
+
}
|
|
3164
|
+
case "pragma!": {
|
|
3165
|
+
if (it2.length !== 3) break;
|
|
3166
|
+
const key = instantiate(it.bnd, it2[1]);
|
|
3167
|
+
if (key.kind === "sym" && key.name === "max-stack-depth") {
|
|
3168
|
+
const val = instantiate(it.bnd, it2[2]);
|
|
3169
|
+
const n = val.kind === "gnd" && val.value.g === "int" ? val.value.n : void 0;
|
|
3170
|
+
if (n === void 0 || n < 0 || typeof n === "number" && !Number.isInteger(n))
|
|
3171
|
+
return [[finItem(prev, errAtom(a, "UnsignedIntegerIsExpected"), it.bnd)], st];
|
|
3172
|
+
const w = cloneWorld(st.world);
|
|
3173
|
+
w.maxStackDepth = Number(n);
|
|
3174
|
+
return [[finItem(prev, emptyExpr, it.bnd)], { counter: st.counter, world: w }];
|
|
3175
|
+
}
|
|
3176
|
+
return [[finItem(prev, emptyExpr, it.bnd)], st];
|
|
3177
|
+
}
|
|
3178
|
+
case "bind!": {
|
|
3179
|
+
if (it2.length !== 3) break;
|
|
3180
|
+
const tok2 = instantiate(it.bnd, it2[1]);
|
|
3181
|
+
if (tok2.kind === "sym") {
|
|
3182
|
+
const w = cloneWorld(st.world);
|
|
3183
|
+
w.tokens.set(tok2.name, instantiate(it.bnd, it2[2]));
|
|
3184
|
+
return [[finItem(prev, emptyExpr, it.bnd)], { counter: st.counter, world: w }];
|
|
3185
|
+
}
|
|
3186
|
+
return [[finItem(prev, errAtom(tok2, "bind!: token must be a symbol"), it.bnd)], st];
|
|
3187
|
+
}
|
|
3188
|
+
case "import!": {
|
|
3189
|
+
if (it2.length !== 3) break;
|
|
3190
|
+
const fileAtom = instantiate(it.bnd, it2[2]);
|
|
3191
|
+
if (fileAtom.kind === "sym" && fileAtom.name === "curry") env.curry = true;
|
|
3192
|
+
const fileAtoms = fileAtom.kind === "sym" ? env.imports.get(fileAtom.name) ?? [] : [];
|
|
3193
|
+
registerImportedTypes(env, fileAtoms);
|
|
3194
|
+
if (fileAtoms.some((a2) => opOf(a2) === "=")) disableTabling(env);
|
|
3195
|
+
return spaceMutate(st, prev, it2[1], it.bnd, (w, name) => appendSpace(w, name, fileAtoms));
|
|
3196
|
+
}
|
|
3197
|
+
default:
|
|
3198
|
+
break;
|
|
3199
|
+
}
|
|
3200
|
+
if (isEmbeddedOp(a)) return [[finItem(prev, errAtom(a, "unsupported minimal op"), it.bnd)], st];
|
|
3201
|
+
return [[{ stack: cons(frame(top.atom, top.ret, top.vars, true), prev), bnd: it.bnd }], st];
|
|
3202
|
+
}
|
|
3203
|
+
function indexSelfRules(w, atoms) {
|
|
3204
|
+
for (const x of atoms) {
|
|
3205
|
+
if (opOf(x) === "=" && x.kind === "expr" && x.items.length === 3) {
|
|
3206
|
+
const lhs = x.items[1];
|
|
3207
|
+
const rhs = x.items[2];
|
|
3208
|
+
const k = headKey(lhs);
|
|
3209
|
+
if (k === void 0) w.selfVarRules = [...w.selfVarRules, [lhs, rhs]];
|
|
3210
|
+
else w.selfRules.set(k, [...w.selfRules.get(k) ?? [], [lhs, rhs]]);
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
function appendSpace(w0, name, atoms) {
|
|
3215
|
+
if (name === "&self") {
|
|
3216
|
+
let selfRules = w0.selfRules;
|
|
3217
|
+
let selfVarRules = w0.selfVarRules;
|
|
3218
|
+
let copiedRules = false;
|
|
3219
|
+
for (const x of atoms) {
|
|
3220
|
+
if (opOf(x) === "=" && x.kind === "expr" && x.items.length === 3) {
|
|
3221
|
+
if (!copiedRules) {
|
|
3222
|
+
selfRules = new Map(w0.selfRules);
|
|
3223
|
+
copiedRules = true;
|
|
3224
|
+
}
|
|
3225
|
+
const lhs = x.items[1];
|
|
3226
|
+
const rhs = x.items[2];
|
|
3227
|
+
const k = headKey(lhs);
|
|
3228
|
+
if (k === void 0) selfVarRules = [...selfVarRules, [lhs, rhs]];
|
|
3229
|
+
else selfRules.set(k, [...selfRules.get(k) ?? [], [lhs, rhs]]);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
return {
|
|
3233
|
+
spaces: w0.spaces,
|
|
3234
|
+
store: w0.store,
|
|
3235
|
+
tokens: w0.tokens,
|
|
3236
|
+
selfExtra: logAppendAll(w0.selfExtra, atoms),
|
|
3237
|
+
selfRules,
|
|
3238
|
+
selfVarRules,
|
|
3239
|
+
maxStackDepth: w0.maxStackDepth
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
const w = cloneWorld(w0);
|
|
3243
|
+
w.spaces.set(name, [...w.spaces.get(name) ?? [], ...atoms]);
|
|
3244
|
+
return w;
|
|
3245
|
+
}
|
|
3246
|
+
function eraseSpace(w0, name, a) {
|
|
3247
|
+
const w = cloneWorld(w0);
|
|
3248
|
+
const erase1 = (xs) => {
|
|
3249
|
+
const i = xs.findIndex((y) => atomEq(y, a));
|
|
3250
|
+
return i < 0 ? [...xs] : [...xs.slice(0, i), ...xs.slice(i + 1)];
|
|
3251
|
+
};
|
|
3252
|
+
if (name === "&self") {
|
|
3253
|
+
const xs = logToArray(w.selfExtra);
|
|
3254
|
+
const i = xs.findIndex((y) => atomEq(y, a));
|
|
3255
|
+
if (i >= 0) w.selfExtra = logFromArray([...xs.slice(0, i), ...xs.slice(i + 1)]);
|
|
3256
|
+
} else w.spaces.set(name, erase1(w.spaces.get(name) ?? []));
|
|
3257
|
+
return w;
|
|
3258
|
+
}
|
|
3259
|
+
function spaceMutate(st, prev, s, b, f) {
|
|
3260
|
+
const name = spaceName(st.world, instantiate(b, s));
|
|
3261
|
+
if (name === void 0)
|
|
3262
|
+
return [[finItem(prev, errAtom(instantiate(b, s), "not a space"), b)], st];
|
|
3263
|
+
return [[finItem(prev, emptyExpr, b)], { counter: st.counter, world: f(st.world, name) }];
|
|
3264
|
+
}
|
|
3265
|
+
function* getTypeOpG(env, fuel, st, prev, xi, b) {
|
|
3266
|
+
const emit = function* (st0) {
|
|
3267
|
+
let acc = [];
|
|
3268
|
+
let cur = st0;
|
|
3269
|
+
for (const t of getTypesForQuery(env, typePrep(st.world, xi))) {
|
|
3270
|
+
const [rs, st2] = yield* mettaEvalG(env, fuel, cur, b, t);
|
|
3271
|
+
acc = [...acc, ...rs.map((p) => finItem(prev, p[0], b))];
|
|
3272
|
+
cur = st2;
|
|
3273
|
+
}
|
|
3274
|
+
return [acc, cur];
|
|
3275
|
+
};
|
|
3276
|
+
if (xi.kind === "expr" && xi.items.length > 0) {
|
|
3277
|
+
const head = xi.items[0];
|
|
3278
|
+
const args = xi.items.slice(1);
|
|
3279
|
+
if (head.kind === "sym") {
|
|
3280
|
+
if (typeMismatch(env, st.world, head.name, args) !== void 0) return [[], st];
|
|
3281
|
+
return yield* emit(st);
|
|
3282
|
+
}
|
|
3283
|
+
const illTyped = getTypes(env, typePrep(st.world, head)).some((ft) => {
|
|
3284
|
+
if (opOf(ft) === "->" && ft.kind === "expr")
|
|
3285
|
+
return typeCheckArgs(env, st.world, ft.items.slice(1, -1), 0, [], args) !== void 0;
|
|
3286
|
+
return false;
|
|
3287
|
+
});
|
|
3288
|
+
return illTyped ? [[], st] : yield* emit(st);
|
|
3289
|
+
}
|
|
3290
|
+
return yield* emit(st);
|
|
3291
|
+
}
|
|
3292
|
+
function matchOp(env, st, prev, space, pattern, template, b) {
|
|
3293
|
+
const sn = spaceName(st.world, instantiate(b, space));
|
|
3294
|
+
const subbed = subTokens(st.world, pattern);
|
|
3295
|
+
const patterns = opOf(subbed) === "," && subbed.kind === "expr" ? subbed.items.slice(1).map((p) => resolveStates(st.world, p)) : [resolveStates(st.world, subbed)];
|
|
3296
|
+
let getCandidates;
|
|
3297
|
+
if (sn === void 0 || sn === "&self") {
|
|
3298
|
+
getCandidates = (pInst) => matchCandidates(env, st.world, pInst);
|
|
3299
|
+
} else {
|
|
3300
|
+
const named = (st.world.spaces.get(sn) ?? []).map((x) => resolveStates(st.world, x));
|
|
3301
|
+
getCandidates = () => named;
|
|
3302
|
+
}
|
|
3303
|
+
const [sols, st2] = patterns.length >= 2 ? matchConjJoin(getCandidates, patterns, st, b) : matchConj(getCandidates, patterns, st, [b]);
|
|
3304
|
+
const out = [];
|
|
3305
|
+
for (const m of sols) if (!hasLoop(m)) out.push(finItem(prev, instantiate(m, template), m));
|
|
3306
|
+
return [out, st2];
|
|
3307
|
+
}
|
|
3308
|
+
function* interpretLoopG(env, fuel, st, work, sink) {
|
|
3309
|
+
const done = [];
|
|
3310
|
+
const emit = (pair) => {
|
|
3311
|
+
if (sink !== void 0) sink(pair);
|
|
3312
|
+
else done.push(pair);
|
|
3313
|
+
};
|
|
3314
|
+
const stack = [];
|
|
3315
|
+
for (let i = work.length - 1; i >= 0; i--) stack.push(work[i]);
|
|
3316
|
+
let cur = st;
|
|
3317
|
+
let f = fuel;
|
|
3318
|
+
while (stack.length > 0) {
|
|
3319
|
+
if (f <= 0) {
|
|
3320
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
3321
|
+
const it2 = stack[i];
|
|
3322
|
+
emit(isFinal(it2) ? finalPair(it2) : exhaustedPair(it2));
|
|
3323
|
+
}
|
|
3324
|
+
return [done, cur];
|
|
3325
|
+
}
|
|
3326
|
+
const it = stack.pop();
|
|
3327
|
+
if (cur.world.maxStackDepth > 0) {
|
|
3328
|
+
let depth = 0;
|
|
3329
|
+
for (let p = it.stack; p !== null; p = p.tail) depth++;
|
|
3330
|
+
if (depth >= cur.world.maxStackDepth) {
|
|
3331
|
+
emit(isFinal(it) ? finalPair(it) : exhaustedPair(it));
|
|
3332
|
+
continue;
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
const [results, st2] = yield* interpretStack1G(env, f - 1, cur, it);
|
|
3336
|
+
cur = st2;
|
|
3337
|
+
f -= 1;
|
|
3338
|
+
const more = [];
|
|
3339
|
+
for (const r of results) {
|
|
3340
|
+
if (isFinal(r)) {
|
|
3341
|
+
if (sink !== void 0) sink(finalPair(r));
|
|
3342
|
+
else done.push(finalPair(r));
|
|
3343
|
+
} else more.push(r);
|
|
3344
|
+
}
|
|
3345
|
+
for (let i = more.length - 1; i >= 0; i--) stack.push(more[i]);
|
|
3346
|
+
}
|
|
3347
|
+
return [done, cur];
|
|
3348
|
+
}
|
|
3349
|
+
var evaluatedAtoms = /* @__PURE__ */ new WeakSet();
|
|
3350
|
+
function* reduceChildrenG(env, fuel, st, pairs, onTerminal) {
|
|
3351
|
+
const out = [];
|
|
3352
|
+
let cur = st;
|
|
3353
|
+
for (const p of pairs) {
|
|
3354
|
+
const term = onTerminal(p);
|
|
3355
|
+
if (term !== void 0) {
|
|
3356
|
+
out.push(...term);
|
|
3357
|
+
} else {
|
|
3358
|
+
const [more, st3] = yield* mettaEvalG(env, fuel - 1, cur, p[1], p[0]);
|
|
3359
|
+
cur = st3;
|
|
3360
|
+
out.push(...more);
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
return [out, cur];
|
|
3364
|
+
}
|
|
3365
|
+
var runtimeRuleVersionCounter = 0;
|
|
3366
|
+
var runtimeRuleVersions = /* @__PURE__ */ new WeakMap();
|
|
3367
|
+
function rulesVersion(rules) {
|
|
3368
|
+
if (rules === void 0) return 0;
|
|
3369
|
+
let v = runtimeRuleVersions.get(rules);
|
|
3370
|
+
if (v === void 0) {
|
|
3371
|
+
v = ++runtimeRuleVersionCounter;
|
|
3372
|
+
runtimeRuleVersions.set(rules, v);
|
|
3373
|
+
}
|
|
3374
|
+
return v;
|
|
3375
|
+
}
|
|
3376
|
+
function collectHeadSyms(a, out) {
|
|
3377
|
+
if (a.kind === "expr" && a.items.length > 0) {
|
|
3378
|
+
if (a.items[0].kind === "sym") out.add(a.items[0].name);
|
|
3379
|
+
for (const it of a.items) collectHeadSyms(it, out);
|
|
3380
|
+
}
|
|
3381
|
+
}
|
|
3382
|
+
var runtimePureCache = /* @__PURE__ */ new Map();
|
|
3383
|
+
function runtimeFunctorPure(env, w, op) {
|
|
3384
|
+
if (env.varRules.some(([lhs]) => isVariableHeaded(lhs)) || w.selfVarRules.length > 0)
|
|
3385
|
+
return false;
|
|
3386
|
+
const ck = op + "@" + rulesVersion(w.selfRules.get(op));
|
|
3387
|
+
const cached = runtimePureCache.get(ck);
|
|
3388
|
+
if (cached !== void 0) return cached;
|
|
3389
|
+
const visit = (f, seen) => {
|
|
3390
|
+
if (seen.has(f)) return true;
|
|
3391
|
+
seen.add(f);
|
|
3392
|
+
const rules = [...env.ruleIndex.get(f) ?? [], ...w.selfRules.get(f) ?? []];
|
|
3393
|
+
for (const [, rhs] of rules) {
|
|
3394
|
+
const heads = /* @__PURE__ */ new Set();
|
|
3395
|
+
collectHeadSyms(rhs, heads);
|
|
3396
|
+
for (const h of heads) {
|
|
3397
|
+
if (IMPURE_OPS.has(h)) return false;
|
|
3398
|
+
if ((env.ruleIndex.has(h) || w.selfRules.has(h)) && !visit(h, seen)) return false;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
return true;
|
|
3402
|
+
};
|
|
3403
|
+
const pure = visit(op, /* @__PURE__ */ new Set());
|
|
3404
|
+
runtimePureCache.set(ck, pure);
|
|
3405
|
+
return pure;
|
|
3406
|
+
}
|
|
3407
|
+
var COUNT_UNIT = sym("u");
|
|
3408
|
+
function countOnlyMatch(z) {
|
|
3409
|
+
return z.kind === "expr" && z.items.length === 4 && opOf(z) === "match" ? expr([z.items[0], z.items[1], z.items[2], COUNT_UNIT]) : z;
|
|
3410
|
+
}
|
|
3411
|
+
function* mettaEvalG(env, fuel, st, bnd, a) {
|
|
3412
|
+
if (fuel <= 0)
|
|
3413
|
+
return [[[expr([sym("Error"), instantiate(bnd, a), sym("StackOverflow")]), bnd]], st];
|
|
3414
|
+
const w = instantiate(bnd, a);
|
|
3415
|
+
if (w.kind === "expr" && w.ground && evaluatedAtoms.has(w)) return [[[w, bnd]], st];
|
|
3416
|
+
const isErr = (x) => x.kind === "expr" && x.items.length >= 1 && x.items[0].kind === "sym" && x.items[0].name === "Error";
|
|
3417
|
+
if (w.kind === "expr" && w.items.length > 0 && w.items[0].kind === "sym") {
|
|
3418
|
+
let la = a;
|
|
3419
|
+
let lbnd = bnd;
|
|
3420
|
+
let lst = st;
|
|
3421
|
+
let lw = w;
|
|
3422
|
+
const pendingKeys = [];
|
|
3423
|
+
const flushReturn = (res, stR) => {
|
|
3424
|
+
if (pendingKeys.length > 0 && env.table !== void 0 && res.every((p) => p[0].ground)) {
|
|
3425
|
+
const prod = res.map((p) => p[0]);
|
|
3426
|
+
for (const k of pendingKeys) env.table.set(k, prod);
|
|
3427
|
+
}
|
|
3428
|
+
return [res, stR];
|
|
3429
|
+
};
|
|
3430
|
+
reduceTrampoline: for (; ; ) {
|
|
3431
|
+
const op = lw.items[0].name;
|
|
3432
|
+
const args = lw.items.slice(1);
|
|
3433
|
+
if ((op === "length" || op === "size-atom") && args.length === 1 && args[0].kind === "expr" && opOf(args[0]) === "collapse" && args[0].items.length === 2 && !env.ruleIndex.has(op) && !lst.world.selfRules.has(op)) {
|
|
3434
|
+
let count = 0;
|
|
3435
|
+
const [, stC] = yield* interpretLoopG(
|
|
3436
|
+
env,
|
|
3437
|
+
fuel,
|
|
3438
|
+
lst,
|
|
3439
|
+
[
|
|
3440
|
+
{
|
|
3441
|
+
stack: atomToStack(
|
|
3442
|
+
expr([sym("metta"), countOnlyMatch(args[0].items[1]), UNDEF, sym("&self")]),
|
|
3443
|
+
null
|
|
3444
|
+
),
|
|
3445
|
+
bnd: lbnd
|
|
3446
|
+
}
|
|
3447
|
+
],
|
|
3448
|
+
() => {
|
|
3449
|
+
count++;
|
|
3450
|
+
}
|
|
3451
|
+
);
|
|
3452
|
+
return flushReturn([[gint(BigInt(count)), lbnd]], stC);
|
|
3453
|
+
}
|
|
3454
|
+
const opSig = env.sigs.get(op);
|
|
3455
|
+
if (opSig !== void 0 && opSig.length >= 1 && args.length !== opSig.length - 1) {
|
|
3456
|
+
const hasTupleType = (env.types.get(op) ?? []).some((t) => opOf(t) !== "->");
|
|
3457
|
+
const underAppliedCurry = env.curry && args.length >= 1 && args.length < opSig.length - 1;
|
|
3458
|
+
if (!hasTupleType && !underAppliedCurry)
|
|
3459
|
+
return flushReturn(
|
|
3460
|
+
[
|
|
3461
|
+
[
|
|
3462
|
+
expr([sym("Error"), expr([sym(op), ...args]), sym("IncorrectNumberOfArguments")]),
|
|
3463
|
+
lbnd
|
|
3464
|
+
]
|
|
3465
|
+
],
|
|
3466
|
+
lst
|
|
3467
|
+
);
|
|
3468
|
+
}
|
|
3469
|
+
const mm = typeMismatch(env, lst.world, op, args, opSig);
|
|
3470
|
+
if (mm !== void 0) {
|
|
3471
|
+
const [pos, expected, actual] = mm;
|
|
3472
|
+
return flushReturn(
|
|
3473
|
+
[
|
|
3474
|
+
[
|
|
3475
|
+
expr([
|
|
3476
|
+
sym("Error"),
|
|
3477
|
+
expr([sym(op), ...args]),
|
|
3478
|
+
expr([sym("BadArgType"), gint(pos), expected, actual])
|
|
3479
|
+
]),
|
|
3480
|
+
lbnd
|
|
3481
|
+
]
|
|
3482
|
+
],
|
|
3483
|
+
lst
|
|
3484
|
+
);
|
|
3485
|
+
}
|
|
3486
|
+
const queryVars = args.flatMap((x) => atomVars(x));
|
|
3487
|
+
const sig = opSig;
|
|
3488
|
+
const opReturnsAtom = sig !== void 0 && sig.length > 0 && atomEq(sig[sig.length - 1], sym("Atom"));
|
|
3489
|
+
const mask = LAZY_ARGS_OPS.has(op) ? args.map(() => false) : argMask(sig, args.length);
|
|
3490
|
+
let partials = [[[], []]];
|
|
3491
|
+
let cur = lst;
|
|
3492
|
+
for (let i = 0; i < args.length; i++) {
|
|
3493
|
+
const ae = args[i];
|
|
3494
|
+
const evalThis = mask[i];
|
|
3495
|
+
const nextParts = [];
|
|
3496
|
+
for (const [accAtoms, accB] of partials) {
|
|
3497
|
+
if (evalThis) {
|
|
3498
|
+
const [ps, st2] = yield* mettaEvalG(env, fuel - 1, cur, accB, ae);
|
|
3499
|
+
cur = st2;
|
|
3500
|
+
for (const p of ps) {
|
|
3501
|
+
nextParts.push([[...accAtoms, p[0]], mergeRestrict(queryVars, accB, p[1])]);
|
|
3502
|
+
}
|
|
3503
|
+
} else {
|
|
3504
|
+
nextParts.push([[...accAtoms, instantiate(accB, ae)], accB]);
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
partials = nextParts;
|
|
3508
|
+
}
|
|
3509
|
+
const out = [];
|
|
3510
|
+
let cur2 = cur;
|
|
3511
|
+
const tabling = env.table !== void 0 && queryVars.length === 0;
|
|
3512
|
+
const staticPure = env.pureFunctors?.has(op) ?? false;
|
|
3513
|
+
for (const [partAtoms, partB] of partials) {
|
|
3514
|
+
let errFound;
|
|
3515
|
+
for (let i = 0; i < partAtoms.length; i++) {
|
|
3516
|
+
if (isErr(partAtoms[i]) && !atomEq(partAtoms[i], args[i])) {
|
|
3517
|
+
errFound = partAtoms[i];
|
|
3518
|
+
break;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
if (errFound !== void 0) {
|
|
3522
|
+
out.push([errFound, partB]);
|
|
3523
|
+
continue;
|
|
3524
|
+
}
|
|
3525
|
+
const wApp = expr([sym(op), ...partAtoms]);
|
|
3526
|
+
if (env.curry && partAtoms.length >= 1) {
|
|
3527
|
+
const ar = functionArity(env, cur2.world, op);
|
|
3528
|
+
if (ar !== void 0 && partAtoms.length < ar) {
|
|
3529
|
+
out.push([expr([sym("partial"), sym(op), expr(partAtoms)]), partB]);
|
|
3530
|
+
continue;
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
if (env.compiled !== void 0) {
|
|
3534
|
+
const cr = runCompiled(env, op, partAtoms);
|
|
3535
|
+
if (cr !== void 0) {
|
|
3536
|
+
out.push([cr, partB]);
|
|
3537
|
+
continue;
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
let eligible = false;
|
|
3541
|
+
let key = "";
|
|
3542
|
+
if (tabling && wApp.ground && keyWellFormed(wApp)) {
|
|
3543
|
+
if (cur2.world.selfRules.has(op)) {
|
|
3544
|
+
if (runtimeFunctorPure(env, cur2.world, op)) {
|
|
3545
|
+
eligible = true;
|
|
3546
|
+
key = tableKey(wApp) + "@v" + rulesVersion(cur2.world.selfRules.get(op));
|
|
3547
|
+
}
|
|
3548
|
+
} else if (staticPure) {
|
|
3549
|
+
eligible = true;
|
|
3550
|
+
key = tableKey(wApp);
|
|
3551
|
+
}
|
|
3552
|
+
if (eligible) {
|
|
3553
|
+
const hit = env.table.get(key);
|
|
3554
|
+
if (hit !== void 0) {
|
|
3555
|
+
for (const r of hit) out.push([r, partB]);
|
|
3556
|
+
continue;
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
const before = out.length;
|
|
3561
|
+
const [pairs2, st3] = yield* interpretLoopG(env, fuel, cur2, [
|
|
3562
|
+
{ stack: atomToStack(expr([sym("eval"), wApp]), null), bnd: lbnd }
|
|
3563
|
+
]);
|
|
3564
|
+
cur2 = st3;
|
|
3565
|
+
if (partials.length === 1 && queryVars.length === 0 && pairs2.length === 1) {
|
|
3566
|
+
const p = pairs2[0];
|
|
3567
|
+
const isData = atomEq(p[0], notReducibleA) || atomEq(p[0], wApp);
|
|
3568
|
+
if (!isData && !(opReturnsAtom && !isEmbeddedOp(p[0])) && opOf(p[0]) !== void 0) {
|
|
3569
|
+
const pb = mergeRestrict(queryVars, partB, p[1]);
|
|
3570
|
+
if (eligible) pendingKeys.push(key);
|
|
3571
|
+
la = p[0];
|
|
3572
|
+
lbnd = pb;
|
|
3573
|
+
lst = cur2;
|
|
3574
|
+
lw = instantiate(lbnd, la);
|
|
3575
|
+
continue reduceTrampoline;
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
for (const p of pairs2) {
|
|
3579
|
+
const pb = mergeRestrict(queryVars, partB, p[1]);
|
|
3580
|
+
if (atomEq(p[0], notReducibleA) || atomEq(p[0], wApp)) {
|
|
3581
|
+
if (wApp.ground) evaluatedAtoms.add(wApp);
|
|
3582
|
+
out.push([wApp, partB]);
|
|
3583
|
+
} else if (opReturnsAtom && !isEmbeddedOp(p[0])) {
|
|
3584
|
+
out.push([p[0], pb]);
|
|
3585
|
+
} else {
|
|
3586
|
+
const [more, st4] = yield* mettaEvalG(env, fuel - 1, cur2, pb, p[0]);
|
|
3587
|
+
cur2 = st4;
|
|
3588
|
+
for (const m of more) {
|
|
3589
|
+
out.push([m[0], mergeRestrict(queryVars, pb, m[1])]);
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
if (eligible) {
|
|
3594
|
+
const produced = out.slice(before).map((p) => p[0]);
|
|
3595
|
+
if (produced.every((a2) => a2.ground)) env.table.set(key, produced);
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3598
|
+
return flushReturn(out, cur2);
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
if (w.kind === "expr" && w.items.length > 0) {
|
|
3602
|
+
const [ruleRes, st12] = yield* interpretLoopG(env, fuel, st, [
|
|
3603
|
+
{ stack: atomToStack(expr([sym("eval"), w]), null), bnd }
|
|
3604
|
+
]);
|
|
3605
|
+
const reduced = ruleRes.filter((p) => !atomEq(p[0], w) && !atomEq(p[0], notReducibleA));
|
|
3606
|
+
if (reduced.length === 0) {
|
|
3607
|
+
const [tupleRes, st2] = yield* interpretLoopG(env, fuel, st12, [
|
|
3608
|
+
{
|
|
3609
|
+
stack: atomToStack(
|
|
3610
|
+
expr([sym("eval"), expr([sym("interpret-tuple"), w, sym("&self")])]),
|
|
3611
|
+
null
|
|
3612
|
+
),
|
|
3613
|
+
bnd
|
|
3614
|
+
}
|
|
3615
|
+
]);
|
|
3616
|
+
return yield* reduceChildrenG(
|
|
3617
|
+
env,
|
|
3618
|
+
fuel,
|
|
3619
|
+
st2,
|
|
3620
|
+
tupleRes,
|
|
3621
|
+
(p) => atomEq(p[0], w) ? [p] : void 0
|
|
3622
|
+
);
|
|
3623
|
+
}
|
|
3624
|
+
return yield* reduceChildrenG(env, fuel, st12, reduced, () => void 0);
|
|
3625
|
+
}
|
|
3626
|
+
const [pairs, st1] = yield* interpretLoopG(env, fuel, st, [
|
|
3627
|
+
{ stack: atomToStack(expr([sym("eval"), w]), null), bnd }
|
|
3628
|
+
]);
|
|
3629
|
+
return yield* reduceChildrenG(
|
|
3630
|
+
env,
|
|
3631
|
+
fuel,
|
|
3632
|
+
st1,
|
|
3633
|
+
pairs,
|
|
3634
|
+
(p) => atomEq(p[0], notReducibleA) || atomEq(p[0], w) ? [[w, bnd]] : returnsAtom(env, w) && !isEmbeddedOp(p[0]) ? [p] : void 0
|
|
3635
|
+
);
|
|
3636
|
+
}
|
|
3637
|
+
var DEFAULT_FUEL = 2e6;
|
|
3638
|
+
function isNativeStackOverflow(e) {
|
|
3639
|
+
return e instanceof RangeError && /call stack/i.test(e.message);
|
|
3640
|
+
}
|
|
3641
|
+
function stackOverflowResult(st, bnd, a) {
|
|
3642
|
+
return [[[expr([sym("Error"), instantiate(bnd, a), sym("StackOverflow")]), bnd]], st];
|
|
3643
|
+
}
|
|
3644
|
+
function mettaEval(env, fuel, st, bnd, a) {
|
|
3645
|
+
ensureCompiled(env);
|
|
3646
|
+
try {
|
|
3647
|
+
return runGenSync(mettaEvalG(env, fuel, st, bnd, a));
|
|
3648
|
+
} catch (e) {
|
|
3649
|
+
if (isNativeStackOverflow(e)) return stackOverflowResult(st, bnd, a);
|
|
3650
|
+
throw e;
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
function mettaEvalAsync(env, fuel, st, bnd, a, signal) {
|
|
3654
|
+
ensureCompiled(env);
|
|
3655
|
+
return runGenAsync(mettaEvalG(env, fuel, st, bnd, a), signal).catch((e) => {
|
|
3656
|
+
if (isNativeStackOverflow(e)) return stackOverflowResult(st, bnd, a);
|
|
3657
|
+
throw e;
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
function evalAtom(env, atom, st = initSt(), fuel = DEFAULT_FUEL) {
|
|
3661
|
+
const [pairs, st2] = mettaEval(env, fuel, st, [], atom);
|
|
3662
|
+
return [pairs.map((p) => p[0]), st2];
|
|
3663
|
+
}
|
|
3664
|
+
|
|
3665
|
+
// src/tabling.ts
|
|
3666
|
+
var IMPURE_OPS = /* @__PURE__ */ new Set([
|
|
3667
|
+
"add-atom",
|
|
3668
|
+
"remove-atom",
|
|
3669
|
+
"add-reduct",
|
|
3670
|
+
"add-reducts",
|
|
3671
|
+
"add-atoms",
|
|
3672
|
+
"new-state",
|
|
3673
|
+
"get-state",
|
|
3674
|
+
"change-state!",
|
|
3675
|
+
"new-space",
|
|
3676
|
+
"new-mork-space",
|
|
3677
|
+
"fork-space",
|
|
3678
|
+
"get-atoms",
|
|
3679
|
+
"bind!",
|
|
3680
|
+
"import!",
|
|
3681
|
+
"transaction",
|
|
3682
|
+
"context-space",
|
|
3683
|
+
"par",
|
|
3684
|
+
"race",
|
|
3685
|
+
"once",
|
|
3686
|
+
"with-mutex",
|
|
3687
|
+
"superpose",
|
|
3688
|
+
"hyperpose",
|
|
3689
|
+
"collapse",
|
|
3690
|
+
"collapse-bind",
|
|
3691
|
+
"superpose-bind",
|
|
3692
|
+
"collapse-extract",
|
|
3693
|
+
"match",
|
|
3694
|
+
"metta",
|
|
3695
|
+
"metta-thread",
|
|
3696
|
+
"capture",
|
|
3697
|
+
"println!",
|
|
3698
|
+
"print!",
|
|
3699
|
+
"trace!",
|
|
3700
|
+
"pragma!",
|
|
3701
|
+
"register-module!",
|
|
3702
|
+
"get-type",
|
|
3703
|
+
"get-type-space",
|
|
3704
|
+
"get-doc",
|
|
3705
|
+
"empty"
|
|
3706
|
+
]);
|
|
3707
|
+
function headSymbols(a, out) {
|
|
3708
|
+
if (a.kind === "expr" && a.items.length > 0) {
|
|
3709
|
+
if (a.items[0].kind === "sym") out.add(a.items[0].name);
|
|
3710
|
+
for (const it of a.items) headSymbols(it, out);
|
|
3711
|
+
}
|
|
3712
|
+
return out;
|
|
3713
|
+
}
|
|
3714
|
+
function variableHeaded(a) {
|
|
3715
|
+
return a.kind === "var" || a.kind === "expr" && a.items.length > 0 && variableHeaded(a.items[0]);
|
|
3716
|
+
}
|
|
3717
|
+
function analyzePurity(env) {
|
|
3718
|
+
if (env.varRules.some(([lhs]) => variableHeaded(lhs))) return /* @__PURE__ */ new Set();
|
|
3719
|
+
const deps = /* @__PURE__ */ new Map();
|
|
3720
|
+
for (const [k, eqs] of env.ruleIndex) {
|
|
3721
|
+
const s = /* @__PURE__ */ new Set();
|
|
3722
|
+
for (const [, rhs] of eqs) headSymbols(rhs, s);
|
|
3723
|
+
deps.set(k, s);
|
|
3724
|
+
}
|
|
3725
|
+
const impure = /* @__PURE__ */ new Set();
|
|
3726
|
+
for (const [k, s] of deps) {
|
|
3727
|
+
for (const h of s)
|
|
3728
|
+
if (IMPURE_OPS.has(h)) {
|
|
3729
|
+
impure.add(k);
|
|
3730
|
+
break;
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
let changed = true;
|
|
3734
|
+
while (changed) {
|
|
3735
|
+
changed = false;
|
|
3736
|
+
for (const [k, s] of deps) {
|
|
3737
|
+
if (impure.has(k)) continue;
|
|
3738
|
+
for (const h of s)
|
|
3739
|
+
if (impure.has(h)) {
|
|
3740
|
+
impure.add(k);
|
|
3741
|
+
changed = true;
|
|
3742
|
+
break;
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
}
|
|
3746
|
+
const pure = /* @__PURE__ */ new Set();
|
|
3747
|
+
for (const k of deps.keys()) if (!impure.has(k)) pure.add(k);
|
|
3748
|
+
return pure;
|
|
3749
|
+
}
|
|
3750
|
+
function tableKey(call) {
|
|
3751
|
+
return format(call);
|
|
3752
|
+
}
|
|
3753
|
+
function keyWellFormed(a) {
|
|
3754
|
+
if (a.kind === "gnd") return a.value.g !== "float";
|
|
3755
|
+
if (a.kind === "expr") return a.items.every(keyWellFormed);
|
|
3756
|
+
return true;
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
// src/unify.ts
|
|
3760
|
+
function decomposeEq(a, b) {
|
|
3761
|
+
if (a.kind === "var" && b.kind === "var") return a.name === b.name ? [] : [[a.name, b]];
|
|
3762
|
+
if (a.kind === "var") return [[a.name, b]];
|
|
3763
|
+
if (b.kind === "var") return [[b.name, a]];
|
|
3764
|
+
if (a.kind === "sym" && b.kind === "sym") return a.name === b.name ? [] : null;
|
|
3765
|
+
if (a.kind === "gnd" && b.kind === "gnd") return atomEq(a, b) ? [] : null;
|
|
3766
|
+
if (a.kind === "expr" && b.kind === "expr") return decomposeList(a.items, b.items);
|
|
3767
|
+
return null;
|
|
3768
|
+
}
|
|
3769
|
+
function decomposeList(xs, ys) {
|
|
3770
|
+
if (xs.length !== ys.length) return null;
|
|
3771
|
+
const out = [];
|
|
3772
|
+
for (let i = 0; i < xs.length; i++) {
|
|
3773
|
+
const c = decomposeEq(xs[i], ys[i]);
|
|
3774
|
+
if (c === null) return null;
|
|
3775
|
+
out.push(...c);
|
|
3776
|
+
}
|
|
3777
|
+
return out;
|
|
3778
|
+
}
|
|
3779
|
+
function decomposeAll(eqs) {
|
|
3780
|
+
const out = [];
|
|
3781
|
+
for (const [a, b] of eqs) {
|
|
3782
|
+
const c = decomposeEq(a, b);
|
|
3783
|
+
if (c === null) return null;
|
|
3784
|
+
out.push(...c);
|
|
3785
|
+
}
|
|
3786
|
+
return out;
|
|
3787
|
+
}
|
|
3788
|
+
function unifyRounds(fuel, eqs, s) {
|
|
3789
|
+
const decomposed = decomposeAll(eqs);
|
|
3790
|
+
if (decomposed === null) return null;
|
|
3791
|
+
if (decomposed.length === 0) return s;
|
|
3792
|
+
if (fuel <= 0) return null;
|
|
3793
|
+
const [x, t] = decomposed[0];
|
|
3794
|
+
const rest = decomposed.slice(1);
|
|
3795
|
+
if (occurs(x, t)) return null;
|
|
3796
|
+
const sub = [[x, t]];
|
|
3797
|
+
const rest2 = rest.map((p) => [
|
|
3798
|
+
applySubst(sub, variable(p[0])),
|
|
3799
|
+
applySubst(sub, p[1])
|
|
3800
|
+
]);
|
|
3801
|
+
return unifyRounds(fuel - 1, rest2, extendSubst(s, x, t));
|
|
3802
|
+
}
|
|
3803
|
+
function unifyTop(a, b) {
|
|
3804
|
+
return unifyRounds(atomSize(a) + atomSize(b), [[a, b]], []);
|
|
3805
|
+
}
|
|
3806
|
+
function unifiable(a, b) {
|
|
3807
|
+
return unifyTop(a, b) !== null;
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// src/space.ts
|
|
3811
|
+
var InMemorySpace = class {
|
|
3812
|
+
store = [];
|
|
3813
|
+
add(atom) {
|
|
3814
|
+
this.store.push(atom);
|
|
3815
|
+
}
|
|
3816
|
+
remove(atom) {
|
|
3817
|
+
const i = this.store.findIndex((a) => atomEq(a, atom));
|
|
3818
|
+
if (i < 0) return false;
|
|
3819
|
+
this.store.splice(i, 1);
|
|
3820
|
+
return true;
|
|
3821
|
+
}
|
|
3822
|
+
query(pattern, freshen) {
|
|
3823
|
+
const out = [];
|
|
3824
|
+
for (const a of this.store) {
|
|
3825
|
+
const target = freshen ? freshen(a) : a;
|
|
3826
|
+
for (const b of matchAtoms(pattern, target)) out.push(b);
|
|
3827
|
+
}
|
|
3828
|
+
return out;
|
|
3829
|
+
}
|
|
3830
|
+
atoms() {
|
|
3831
|
+
return this.store;
|
|
3832
|
+
}
|
|
3833
|
+
};
|
|
3834
|
+
|
|
3835
|
+
// src/prelude.ts
|
|
3836
|
+
var PRELUDE_SRC = '(: + (-> Number Number Number))\n (: - (-> Number Number Number))\n (: * (-> Number Number Number))\n (: / (-> Number Number Number))\n (: % (-> Number Number Number))\n (: = (-> $t $t %Undefined%))\n (: == (-> $t $t Bool))\n (: < (-> Number Number Bool))\n (: > (-> Number Number Bool))\n (: <= (-> Number Number Bool))\n (: >= (-> Number Number Bool))\n (: get-type (-> Atom Atom))\n (: get-doc (-> Atom %Undefined%))\n (: help! (-> Atom %Undefined%))\n (: eval (-> Atom Atom))\n (: evalc (-> Atom SpaceType Atom))\n (: chain (-> Atom Variable Atom %Undefined%))\n (: unify (-> Atom Atom Atom Atom %Undefined%))\n (: function (-> Atom Atom))\n (: return (-> Atom Atom))\n (: cons-atom (-> Atom Expression Atom))\n (: decons-atom (-> Expression Atom))\n (: collapse-bind (-> Atom Expression))\n (: superpose-bind (-> Expression Atom))\n (: metta (-> Atom Atom Atom Atom))\n (: quote (-> Atom Atom))\n (: new-state (-> $t (StateMonad $t)))\n (: change-state! (-> (StateMonad $t) $t (StateMonad $t)))\n (: if (-> Bool Atom Atom $t))\n (: let (-> Atom %Undefined% Atom %Undefined%))\n (: let* (-> Expression Atom %Undefined%))\n (: car-atom (-> Expression %Undefined%))\n (: cdr-atom (-> Expression Expression))\n (: switch (-> %Undefined% Expression %Undefined%))\n (: interpret-tuple (-> Atom Atom Atom))\n (= (interpret-tuple $expr $space)\n (function (eval (if-equal $expr ()\n (return ())\n (chain (decons-atom $expr) $ht\n (unify ($head $tail) $ht\n (chain (metta-thread $head %Undefined% $space) $rhead\n (chain (eval (interpret-tuple $tail $space)) $rtail\n (chain (cons-atom $rhead $rtail) $res (return $res))))\n (return $expr)))))))\n (: switch-minimal (-> Atom Expression Atom))\n (: switch-internal (-> Atom Expression Atom))\n (: collapse (-> Atom Atom))\n (: unique (-> Atom %Undefined%))\n (: union (-> Atom Atom %Undefined%))\n (: intersection (-> Atom Atom %Undefined%))\n (: subtraction (-> Atom Atom %Undefined%))\n (: Error (-> Atom Atom Atom))\n (: noeval (-> Atom Atom))\n (: id (-> $t $t))\n (: match (-> Atom Atom Atom %Undefined%))\n (: if-decons-expr (-> Expression Variable Variable Atom Atom %Undefined%))\n (: foldl-atom (-> Expression Atom Variable Variable Atom %Undefined%))\n (: assert (-> Atom (->)))\n (: assertIncludes (-> Atom Expression (->)))\n (: assertEqual (-> Atom Atom (->)))\n (: assertEqualMsg (-> Atom Atom Atom (->)))\n (: assertEqualToResult (-> Atom Atom (->)))\n (: assertEqualToResultMsg (-> Atom Atom Atom (->)))\n (: assertAlphaEqual (-> Atom Atom (->)))\n (: assertAlphaEqualMsg (-> Atom Atom Atom (->)))\n (: assertAlphaEqualToResult (-> Atom Atom (->)))\n (: assertAlphaEqualToResultMsg (-> Atom Atom Atom (->)))\n (= (if True $t $e) $t)\n (= (if False $t $e) $e)\n (= (id $x) $x)\n (= (noeval $x) $x)\n (= (quote $atom) NotReducible)\n (= (unquote (quote $atom)) $atom)\n (= (nop) ())\n (= (let $pattern $atom $template) (unify $atom $pattern $template Empty))\n (= (let* $pairs $template)\n (chain (decons-atom $pairs) $ht\n (unify ($head $tail) $ht\n (unify ($pat $at) $head\n (let $pat $at (let* $tail $template))\n (Error (let* $pairs $template) bad-let-star))\n $template)))\n (= (car-atom $a)\n (chain (decons-atom $a) $ht (unify ($head $tail) $ht $head (Error (car-atom $a) car-atom-empty))))\n (= (cdr-atom $a)\n (chain (decons-atom $a) $ht (unify ($head $tail) $ht $tail (Error (cdr-atom $a) cdr-atom-empty))))\n (= (switch $atom $cases) (id (switch-minimal $atom $cases)))\n (= (switch-minimal $atom $cases)\n (function (chain (decons-atom $cases) $list\n (chain (eval (switch-internal $atom $list)) $res\n (chain (eval (if-equal $res NotReducible Empty $res)) $x (return $x))))))\n (= (switch-internal $atom (($pattern $template) $tail))\n (function (unify $atom $pattern\n (return $template)\n (chain (eval (switch-minimal $atom $tail)) $ret (return $ret)))))\n (: case (-> Atom Expression %Undefined%))\n (= (case $atom $cases)\n (function\n (chain (context-space) $space\n (chain (collapse-bind (metta $atom %Undefined% $space)) $c\n (chain (eval (== $c ())) $is_empty\n (unify $is_empty True\n (chain (eval (switch-minimal Empty $cases)) $r (return $r))\n (chain (superpose-bind $c) $e\n (chain (eval (switch-minimal $e $cases)) $r (return $r)))))))))\n (= (collapse $atom)\n (function (chain (context-space) $space\n (chain (collapse-bind (metta $atom %Undefined% $space)) $pairs\n (chain (eval (collapse-extract $pairs)) $r (return $r))))))\n (= (unique $arg) (let $c (collapse $arg) (let $u (unique-atom $c) (superpose $u))))\n (= (union $a $b) (let $c1 (collapse $a) (let $c2 (collapse $b) (let $u (union-atom $c1 $c2) (superpose $u)))))\n (= (intersection $a $b) (let $c1 (collapse $a) (let $c2 (collapse $b) (let $u (intersection-atom $c1 $c2) (superpose $u)))))\n (= (subtraction $a $b) (let $c1 (collapse $a) (let $c2 (collapse $b) (let $u (subtraction-atom $c1 $c2) (superpose $u)))))\n (: atom-subst (-> Atom Variable Atom Atom))\n (= (atom-subst $atom $var $templ)\n (function (chain (eval (noeval $atom)) $var (return $templ))))\n (: map-atom (-> Expression Variable Atom Expression))\n (= (map-atom $list $var $map)\n (function (chain (decons-atom $list) $ht\n (unify ($head $tail) $ht\n (chain (eval (sealed ($var) $map)) $sealedmap\n (chain (eval (map-atom $tail $var $sealedmap)) $tail-mapped\n (chain (eval (atom-subst $head $var $sealedmap)) $map-expr\n (chain (metta $map-expr %Undefined% &self) $head-mapped\n (chain (cons-atom $head-mapped $tail-mapped) $res (return $res))))))\n (return ())))))\n (: filter-atom (-> Expression Variable Atom Expression))\n (= (filter-atom $list $var $filter)\n (function (chain (decons-atom $list) $ht\n (unify ($head $tail) $ht\n (chain (eval (sealed ($var) $filter)) $sealedfilter\n (chain (eval (filter-atom $tail $var $sealedfilter)) $tail-filtered\n (chain (eval (atom-subst $head $var $sealedfilter)) $filter-expr\n (chain (metta $filter-expr %Undefined% &self) $is-filtered\n (eval (if $is-filtered\n (chain (cons-atom $head $tail-filtered) $res (return $res))\n (return $tail-filtered)))))))\n (return ())))))\n (= (if-decons-expr $atom $head $tail $then $else)\n (function (eval (if-equal $atom ()\n (return $else)\n (chain (decons-atom $atom) $list\n (unify $list ($head $tail) (return $then) (return $else)))))))\n (= (foldl-atom $list $init $a $b $op)\n (function (eval (if-equal $list ()\n (return $init)\n (chain (decons-atom $list) $ht\n (unify ($head $tail) $ht\n (chain (eval (atom-subst $init $a $op)) $op1\n (chain (eval (atom-subst $head $b $op1)) $op2\n (chain (metta $op2 %Undefined% &self) $newacc\n (chain (eval (foldl-atom $tail $newacc $a $b $op)) $r (return $r)))))\n (return $init)))))))\n (= (assert $atom)\n (chain (context-space) $space\n (chain (metta $atom %Undefined% $space) $eval-atom\n (unify $eval-atom True () (Error (assert $atom) ($atom not True))))))\n (= (assertIncludes $atom $content)\n (let $eval_atom (collapse $atom)\n (let $diff (subtraction-atom $content $eval_atom)\n (if (== $diff ())\n ()\n (Error (assertIncludes $atom $content)\n (assertIncludes error: $diff not included in result: $eval_atom))))))\n (= (assertEqual $actual $expected)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (chain (metta (collapse $expected) %Undefined% $space) $expected-results\n (eval (_assert-results-are-equal $actual-results $expected-results (assertEqual $actual $expected)))))))\n (= (assertEqualMsg $actual $expected $msg)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (chain (metta (collapse $expected) %Undefined% $space) $expected-results\n (eval (_assert-results-are-equal-msg $actual-results $expected-results (assertEqualMsg $actual $expected) $msg))))))\n (= (assertEqualToResult $actual $expected-results)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (eval (_assert-results-are-equal $actual-results $expected-results (assertEqualToResult $actual $expected-results))))))\n (= (assertEqualToResultMsg $actual $expected-results $msg)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (eval (_assert-results-are-equal-msg $actual-results $expected-results (assertEqualToResultMsg $actual $expected-results) $msg)))))\n (= (assertAlphaEqual $actual $expected)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (chain (metta (collapse $expected) %Undefined% $space) $expected-results\n (eval (_assert-results-are-alpha-equal $actual-results $expected-results (assertAlphaEqual $actual $expected)))))))\n (= (assertAlphaEqualMsg $actual $expected $msg)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (chain (metta (collapse $expected) %Undefined% $space) $expected-results\n (eval (_assert-results-are-alpha-equal-msg $actual-results $expected-results (assertAlphaEqualMsg $actual $expected) $msg))))))\n (= (assertAlphaEqualToResult $actual $expected-results)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (eval (_assert-results-are-alpha-equal $actual-results $expected-results (assertAlphaEqualToResult $actual $expected-results))))))\n (= (assertAlphaEqualToResultMsg $actual $expected-results $msg)\n (chain (context-space) $space\n (chain (metta (collapse $actual) %Undefined% $space) $actual-results\n (eval (_assert-results-are-alpha-equal-msg $actual-results $expected-results (assertAlphaEqualToResultMsg $actual $expected-results) $msg)))))\n (: noreduce-eq (-> Atom Atom Bool))\n (= (noreduce-eq $a $b) (== (quote $a) (quote $b)))\n (: if-error (-> Atom Atom Atom %Undefined%))\n (= (if-error $atom $then $else)\n (function (chain (eval (get-metatype $atom)) $meta\n (eval (if-equal $meta Expression\n (eval (if-equal $atom ()\n (return $else)\n (chain (decons-atom $atom) $list\n (unify $list ($head $tail)\n (eval (if-equal $head Error (return $then) (return $else)))\n (return $else) ))))\n (return $else) )))))\n (: return-on-error (-> Atom Atom %Undefined%))\n (= (return-on-error $atom $then)\n (function (eval (if-equal $atom Empty (return (return Empty))\n (eval (if-error $atom (return (return $atom))\n (return $then) ))))))\n (: for-each-in-atom (-> Expression Atom (->)))\n (= (for-each-in-atom $expr $func)\n (if (noreduce-eq $expr ())\n ()\n (let $head (car-atom $expr)\n (let $tail (cdr-atom $expr)\n (let $_ ($func $head)\n (for-each-in-atom $tail $func) )))))\n (: is-function (-> Type Bool))\n (= (is-function $type)\n (let $mtype (get-metatype $type)\n (unify $mtype Expression\n (let $size (size-atom $type)\n (unify $size 0\n False\n (let ($h $t) (decons-atom $type)\n (unify $h -> True False))))\n False)))\n (: match-types (-> Type Type Atom Atom %Undefined%))\n (= (match-types $type1 $type2 $then $else)\n (function (eval (if-equal $type1 %Undefined%\n (return $then)\n (eval (if-equal $type2 %Undefined%\n (return $then)\n (eval (if-equal $type1 Atom\n (return $then)\n (eval (if-equal $type2 Atom\n (return $then)\n (unify $type1 $type2 (return $then) (return $else)) ))))))))))\n (: match-type-or (-> Bool Atom Type Bool))\n (= (match-type-or $folded $next $type)\n (function\n (chain (eval (match-types $next $type True False)) $matched\n (chain (eval (or $folded $matched)) $or (return $or)) )))\n (: first-from-pair (-> Expression Atom))\n (= (first-from-pair $pair)\n (function\n (unify $pair ($first $second)\n (return $first)\n (return (Error (first-from-pair $pair) "incorrect pair format")))))\n (: type-cast-error-or-bad-type (-> Atom Expression Atom))\n (= (type-cast-error-or-bad-type $atom $actual-types)\n (function\n (chain (eval (filter-atom $actual-types $actual (eval (if-error $actual True False)))) $actual-errors\n (chain (decons-atom $actual-errors) $error-and-tail\n (unify $error-and-tail ($error $tail)\n (return $error)\n (return (Error $atom BadType)))))))\n (: type-cast (-> Atom Type Space %Undefined%))\n (= (type-cast $atom $type $space)\n (function (chain (eval (get-metatype $atom)) $meta\n (eval (if-equal $type $meta\n (return $atom)\n (chain (eval (collapse-bind (eval (get-type $atom $space)))) $collapsed\n (chain (eval (map-atom $collapsed $pair (eval (first-from-pair $pair)))) $actual-types\n (chain (eval (foldl-atom $actual-types False $a $b (eval (match-type-or $a $b $type)))) $is-some-comp\n (eval (if $is-some-comp\n (return $atom)\n (chain (eval (type-cast-error-or-bad-type $atom $actual-types)) $error (return $error)) ))))))))))\n (: ErrorType Type)\n (: SpaceType Type)\n (: BadType (-> Type Type ErrorDescription))\n (: BadArgType (-> Number Type Type ErrorDescription))\n (: IncorrectNumberOfArguments ErrorDescription)\n (: add-atom (-> SpaceType Atom (->)))\n (: remove-atom (-> SpaceType Atom (->)))\n (: add-reduct (-> SpaceType %Undefined% (->)))\n (= (add-reduct $dst $atom) (add-atom $dst $atom))\n (: add-reducts (-> SpaceType %Undefined% (->)))\n (= (add-reducts $space $tuple) (foldl-atom $tuple () $a $b (add-reduct $space $b)))\n (: add-atoms (-> SpaceType Expression (->)))\n (= (add-atoms $space $tuple) (foldl-atom $tuple () $a $b (add-atom $space $b)))\n';
|
|
3837
|
+
|
|
3838
|
+
// src/extensions.ts
|
|
3839
|
+
var CONCURRENCY_MODULE_SRC = `
|
|
3840
|
+
(: transaction (-> Atom %Undefined%))
|
|
3841
|
+
`;
|
|
3842
|
+
var CURRY_MODULE_SRC = `
|
|
3843
|
+
(: partial (-> Atom Expression Atom))
|
|
3844
|
+
|
|
3845
|
+
; Apply a closure to further arguments: append them to the bound list, rebuild the call, evaluate it.
|
|
3846
|
+
; append is forced through its own let (cons-atom would otherwise take it as a literal subexpression),
|
|
3847
|
+
; and the rebuilt call is fully reduced with metta (eval is a single step), which re-curries if still
|
|
3848
|
+
; under-applied.
|
|
3849
|
+
(= ((partial $f $bound) $a)
|
|
3850
|
+
(let $args (append $bound ($a))
|
|
3851
|
+
(let $call (cons-atom $f $args) (metta $call %Undefined% &self))))
|
|
3852
|
+
(= ((partial $f $bound) $a $b)
|
|
3853
|
+
(let $args (append $bound ($a $b))
|
|
3854
|
+
(let $call (cons-atom $f $args) (metta $call %Undefined% &self))))
|
|
3855
|
+
|
|
3856
|
+
; An under-applied |-> lambda (head is an expression, so the core hook does not see it) becomes a
|
|
3857
|
+
; partial closure over the lambda value; applying it later rebuilds the full application.
|
|
3858
|
+
(= ((|-> ($p1 $p2) $body) $a1)
|
|
3859
|
+
(partial (|-> ($p1 $p2) $body) ($a1)))
|
|
3860
|
+
(= ((|-> ($p1 $p2 $p3) $body) $a1)
|
|
3861
|
+
(partial (|-> ($p1 $p2 $p3) $body) ($a1)))
|
|
3862
|
+
(= ((|-> ($p1 $p2 $p3) $body) $a1 $a2)
|
|
3863
|
+
(partial (|-> ($p1 $p2 $p3) $body) ($a1 $a2)))
|
|
3864
|
+
`;
|
|
3865
|
+
var moduleCache = /* @__PURE__ */ new Map();
|
|
3866
|
+
function parseModule(src) {
|
|
3867
|
+
return parseAll(src, standardTokenizer()).filter((t) => !t.bang).map((t) => t.atom);
|
|
3868
|
+
}
|
|
3869
|
+
function builtinModules() {
|
|
3870
|
+
if (moduleCache.size === 0) {
|
|
3871
|
+
moduleCache.set("concurrency", parseModule(CONCURRENCY_MODULE_SRC));
|
|
3872
|
+
moduleCache.set("curry", parseModule(CURRY_MODULE_SRC));
|
|
3873
|
+
}
|
|
3874
|
+
return moduleCache;
|
|
3875
|
+
}
|
|
3876
|
+
function withBuiltinModules(extra) {
|
|
3877
|
+
const out = new Map(builtinModules());
|
|
3878
|
+
if (extra) {
|
|
3879
|
+
for (const [k, v] of extra) if (!out.has(k)) out.set(k, v);
|
|
3880
|
+
}
|
|
3881
|
+
return out;
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
// src/stdlib.ts
|
|
3885
|
+
var STDLIB_SRC = `
|
|
3886
|
+
; ---- Types of the grounded ops (math, bool, atom). Hyperon's grounded atoms carry their type
|
|
3887
|
+
; intrinsically and \`get-type\` reads it; @metta-ts grounds these as host functions in builtins.ts,
|
|
3888
|
+
; so the type signature is declared here to match. Values from hyperon-experimental math.rs/atom.rs
|
|
3889
|
+
; (math ops are f64-valued, so e.g. pow-math/sqrt-math return Number; min-atom/max-atom take any
|
|
3890
|
+
; expression, typed %Undefined% -> Number). The core arithmetic and comparison ops (+ - < == \u2026) are
|
|
3891
|
+
; already declared in the prelude.
|
|
3892
|
+
(: pow-math (-> Number Number Number))
|
|
3893
|
+
(: sqrt-math (-> Number Number))
|
|
3894
|
+
(: abs-math (-> Number Number))
|
|
3895
|
+
(: log-math (-> Number Number Number))
|
|
3896
|
+
(: trunc-math (-> Number Number))
|
|
3897
|
+
(: ceil-math (-> Number Number))
|
|
3898
|
+
(: floor-math (-> Number Number))
|
|
3899
|
+
(: round-math (-> Number Number))
|
|
3900
|
+
(: sin-math (-> Number Number))
|
|
3901
|
+
(: asin-math (-> Number Number))
|
|
3902
|
+
(: cos-math (-> Number Number))
|
|
3903
|
+
(: acos-math (-> Number Number))
|
|
3904
|
+
(: tan-math (-> Number Number))
|
|
3905
|
+
(: atan-math (-> Number Number))
|
|
3906
|
+
(: isnan-math (-> Number Bool))
|
|
3907
|
+
(: isinf-math (-> Number Bool))
|
|
3908
|
+
(: min-atom (-> %Undefined% Number))
|
|
3909
|
+
(: max-atom (-> %Undefined% Number))
|
|
3910
|
+
(: and (-> Bool Bool Bool))
|
|
3911
|
+
(: or (-> Bool Bool Bool))
|
|
3912
|
+
(: not (-> Bool Bool))
|
|
3913
|
+
(: xor (-> Bool Bool Bool))
|
|
3914
|
+
|
|
3915
|
+
; sealed alpha-renames the variables of its second argument. That argument is Atom-typed so the
|
|
3916
|
+
; body reaches sealed unevaluated (hyperon-experimental core.rs: (-> Expression Atom Atom)); without
|
|
3917
|
+
; this the reduce loop would evaluate the body first, e.g. collapsing (== 1 $e) before renaming.
|
|
3918
|
+
(: sealed (-> Expression Atom Atom))
|
|
3919
|
+
|
|
3920
|
+
; ---- IO (host primitives grounded in builtins.ts) ----
|
|
3921
|
+
(: println! (-> %Undefined% (->)))
|
|
3922
|
+
(: print! (-> %Undefined% (->)))
|
|
3923
|
+
(: format-args (-> String Expression String))
|
|
3924
|
+
; repr renders an atom's textual form. The argument is Atom-typed (not evaluated) so repr shows the
|
|
3925
|
+
; atom as written; to repr a reduced form, evaluate it first (e.g. bind it with let).
|
|
3926
|
+
(: repr (-> Atom String))
|
|
3927
|
+
|
|
3928
|
+
; trace! prints its first argument and returns the (evaluated) second.
|
|
3929
|
+
(: trace! (-> %Undefined% %Undefined% %Undefined%))
|
|
3930
|
+
(= (trace! $msg $ret) (let $unit (println! $msg) $ret))
|
|
3931
|
+
|
|
3932
|
+
; include = import a module's contents into the current space.
|
|
3933
|
+
(: include (-> Atom %Undefined%))
|
|
3934
|
+
(= (include $module) (import! &self $module))
|
|
3935
|
+
|
|
3936
|
+
; ---- Error system ----
|
|
3937
|
+
(: ErrorType Type)
|
|
3938
|
+
(: ErrorDescription Type)
|
|
3939
|
+
(: IncorrectNumberOfArguments ErrorDescription)
|
|
3940
|
+
(: BadType (-> Type Type ErrorDescription))
|
|
3941
|
+
(: BadArgType (-> Number Type Type ErrorDescription))
|
|
3942
|
+
|
|
3943
|
+
; ---- Module system (minimal: @metta-ts resolves modules via import! into a space) ----
|
|
3944
|
+
(: module-space-no-deps (-> SpaceType SpaceType))
|
|
3945
|
+
(= (module-space-no-deps $s) $s)
|
|
3946
|
+
(: print-mods! (-> (->)))
|
|
3947
|
+
(= (print-mods!) ())
|
|
3948
|
+
(: git-module! (-> Atom (->)))
|
|
3949
|
+
(= (git-module! $url) (Error (git-module! $url) "git-module! is not supported in @metta-ts"))
|
|
3950
|
+
|
|
3951
|
+
; ---- Documentation system (ported from hyperon stdlib.metta) ----
|
|
3952
|
+
(: DocDescription Type)
|
|
3953
|
+
(: DocInformal Type)
|
|
3954
|
+
(: DocFormal Type)
|
|
3955
|
+
(: DocItem Type)
|
|
3956
|
+
(: DocKindFunction Type)
|
|
3957
|
+
(: DocKindAtom Type)
|
|
3958
|
+
(: DocType Type)
|
|
3959
|
+
(: DocParameters Type)
|
|
3960
|
+
(: DocParameter Type)
|
|
3961
|
+
(: DocParameterInformal Type)
|
|
3962
|
+
(: DocReturn Type)
|
|
3963
|
+
(: DocReturnInformal Type)
|
|
3964
|
+
(: @doc (-> Atom DocDescription DocParameters DocReturnInformal DocInformal))
|
|
3965
|
+
(: @desc (-> String DocDescription))
|
|
3966
|
+
(: @param (-> DocType DocDescription DocParameter))
|
|
3967
|
+
(: @return (-> DocType DocDescription DocReturn))
|
|
3968
|
+
(: @doc-formal (-> DocItem DocKindFunction DocType DocDescription DocParameters DocReturn DocFormal))
|
|
3969
|
+
(: @item (-> Atom DocItem))
|
|
3970
|
+
(: @kind (-> Atom DocKindFunction))
|
|
3971
|
+
(: @type (-> Type DocType))
|
|
3972
|
+
(: @params (-> Expression DocParameters))
|
|
3973
|
+
|
|
3974
|
+
(= (get-doc-single-atom $space $atom)
|
|
3975
|
+
(let $type (get-type-space $space $atom)
|
|
3976
|
+
(if (is-function $type)
|
|
3977
|
+
(get-doc-function $space $atom $type)
|
|
3978
|
+
(get-doc-atom $space $atom) )))
|
|
3979
|
+
(= (get-doc-function $space $name $type)
|
|
3980
|
+
(unify $space (@doc $name $desc (@params $params) $ret)
|
|
3981
|
+
(let $type' (if (== $type %Undefined%) (undefined-doc-function-type $params) (cdr-atom $type))
|
|
3982
|
+
(let ($params' $ret') (get-doc-params $params $ret $type')
|
|
3983
|
+
(@doc-formal (@item $name) (@kind function) (@type $type) $desc (@params $params') $ret')))
|
|
3984
|
+
Empty ))
|
|
3985
|
+
(= (get-doc-atom $space $atom)
|
|
3986
|
+
(let $type (get-type-space $space $atom)
|
|
3987
|
+
(unify $space (@doc $atom $desc)
|
|
3988
|
+
(@doc-formal (@item $atom) (@kind atom) (@type $type) $desc)
|
|
3989
|
+
(unify $space (@doc $atom $desc' (@params $params) $ret)
|
|
3990
|
+
(get-doc-function $space $atom %Undefined%)
|
|
3991
|
+
Empty ))))
|
|
3992
|
+
(= (get-doc-params $params $ret $types)
|
|
3993
|
+
(let $head-type (car-atom $types)
|
|
3994
|
+
(let $tail-types (cdr-atom $types)
|
|
3995
|
+
(if (== () $params)
|
|
3996
|
+
(let (@return $ret-desc) $ret
|
|
3997
|
+
(() (@return (@type $head-type) (@desc $ret-desc))) )
|
|
3998
|
+
(let (@param $param-desc) (car-atom $params)
|
|
3999
|
+
(let $tail-params (cdr-atom $params)
|
|
4000
|
+
(let ($params' $result-ret) (get-doc-params $tail-params $ret $tail-types)
|
|
4001
|
+
(let $result-params (cons-atom (@param (@type $head-type) (@desc $param-desc)) $params')
|
|
4002
|
+
($result-params $result-ret) ))))))))
|
|
4003
|
+
(= (undefined-doc-function-type $params)
|
|
4004
|
+
(if (== () $params) (%Undefined%)
|
|
4005
|
+
(let $params-tail (cdr-atom $params)
|
|
4006
|
+
(let $tail (undefined-doc-function-type $params-tail)
|
|
4007
|
+
(cons-atom %Undefined% $tail) ))))
|
|
4008
|
+
(= (help-param! $param)
|
|
4009
|
+
(let (@param (@type $type) (@desc $desc)) $param
|
|
4010
|
+
(println! (format-args " {} {}" ((type $type) $desc))) ))
|
|
4011
|
+
(: help-space! (-> SpaceType (->)))
|
|
4012
|
+
(= (help-space! $space)
|
|
4013
|
+
(let $_ (collapse
|
|
4014
|
+
(unify $space (@doc $name (@desc $desc) $params $ret)
|
|
4015
|
+
(let () (println! (format-args "{} {}" ($name $desc))) Empty)
|
|
4016
|
+
Empty )) ()))
|
|
4017
|
+
|
|
4018
|
+
; mod-space! loads a module into a fresh space and returns it.
|
|
4019
|
+
(: mod-space! (-> Atom SpaceType))
|
|
4020
|
+
(= (mod-space! $module) (let $s (new-space) (let $u (import! $s $module) $s)))
|
|
4021
|
+
`;
|
|
4022
|
+
var cache;
|
|
4023
|
+
function stdlibAtoms() {
|
|
4024
|
+
if (cache === void 0)
|
|
4025
|
+
cache = parseAll(STDLIB_SRC, standardTokenizer()).filter((t) => !t.bang).map((t) => t.atom);
|
|
4026
|
+
return cache;
|
|
4027
|
+
}
|
|
4028
|
+
|
|
4029
|
+
// src/petta-stdlib.ts
|
|
4030
|
+
var PETTA_STDLIB_SRC = `
|
|
4031
|
+
; ---- Types of the PeTTa-compat grounded ops (grounded in builtins.ts pettaEntries). These are not
|
|
4032
|
+
; Hyperon ops; PeTTa's lib_builtin_types declares them, so the types are declared here to match. ----
|
|
4033
|
+
(: exp (-> Number Number))
|
|
4034
|
+
(: min (-> Number Number Number))
|
|
4035
|
+
(: max (-> Number Number Number))
|
|
4036
|
+
|
|
4037
|
+
; A |-> lambda is a value: (|-> (params) body) has no rewrite of its own, only its application does.
|
|
4038
|
+
; The body is Atom-typed so it is carried unevaluated. Without this, evaluating the lambda value (e.g.
|
|
4039
|
+
; when it is bound by let, whose value slot is %Undefined%-typed and so evaluated) would reduce the body
|
|
4040
|
+
; early, collapsing a nondeterministic body before the lambda is ever applied.
|
|
4041
|
+
(: |-> (-> Expression Atom Atom))
|
|
4042
|
+
|
|
4043
|
+
; ---- anonymous function application: ((|-> (params...) body) args...) ----
|
|
4044
|
+
; Each clause seals the (params body) to fresh variables, binds the fresh params to the arguments, then
|
|
4045
|
+
; evaluates the fresh body. sealing is what makes a lambda reusable inside a higher-order function.
|
|
4046
|
+
; Limitation: one clause per arity (1-5 here). A single variadic clause is not expressible because a
|
|
4047
|
+
; MeTTa rule head has a fixed shape \u2014 it cannot match "the lambda applied to any number of arguments";
|
|
4048
|
+
; extend by adding the next arity. (PeTTa handles this in its translator, not in MeTTa.)
|
|
4049
|
+
(= ((|-> ($p1) $body) $a1)
|
|
4050
|
+
(let* (((($q1) $sb) (sealed () (($p1) $body))) ($q1 $a1)) $sb))
|
|
4051
|
+
(= ((|-> ($p1 $p2) $body) $a1 $a2)
|
|
4052
|
+
(let* (((($q1 $q2) $sb) (sealed () (($p1 $p2) $body))) ($q1 $a1) ($q2 $a2)) $sb))
|
|
4053
|
+
(= ((|-> ($p1 $p2 $p3) $body) $a1 $a2 $a3)
|
|
4054
|
+
(let* (((($q1 $q2 $q3) $sb) (sealed () (($p1 $p2 $p3) $body))) ($q1 $a1) ($q2 $a2) ($q3 $a3)) $sb))
|
|
4055
|
+
(= ((|-> ($p1 $p2 $p3 $p4) $body) $a1 $a2 $a3 $a4)
|
|
4056
|
+
(let* (((($q1 $q2 $q3 $q4) $sb) (sealed () (($p1 $p2 $p3 $p4) $body)))
|
|
4057
|
+
($q1 $a1) ($q2 $a2) ($q3 $a3) ($q4 $a4)) $sb))
|
|
4058
|
+
(= ((|-> ($p1 $p2 $p3 $p4 $p5) $body) $a1 $a2 $a3 $a4 $a5)
|
|
4059
|
+
(let* (((($q1 $q2 $q3 $q4 $q5) $sb) (sealed () (($p1 $p2 $p3 $p4 $p5) $body)))
|
|
4060
|
+
($q1 $a1) ($q2 $a2) ($q3 $a3) ($q4 $a4) ($q5 $a5)) $sb))
|
|
4061
|
+
|
|
4062
|
+
; ---- foldall: fold an aggregator over ALL nondeterministic results of a generator ----
|
|
4063
|
+
; The generator is Atom-typed so it reaches foldall unevaluated; collapse then runs it and collects the
|
|
4064
|
+
; results into a tuple, which fold-over walks left to right. The aggregator stays Atom-typed (a symbol or a
|
|
4065
|
+
; lambda); the accumulator is evaluated so each application reduces.
|
|
4066
|
+
(: foldall (-> Atom Atom Atom %Undefined%))
|
|
4067
|
+
(: fold-over (-> Atom %Undefined% Atom %Undefined%))
|
|
4068
|
+
(= (fold-over $agg $acc $t)
|
|
4069
|
+
(if (== $t ())
|
|
4070
|
+
$acc
|
|
4071
|
+
(let* (($h (car-atom $t)) ($r (cdr-atom $t)))
|
|
4072
|
+
(fold-over $agg ($agg $acc $h) $r))))
|
|
4073
|
+
(= (foldall $agg $gen $init)
|
|
4074
|
+
(let $rs (collapse $gen) (fold-over $agg $init $rs)))
|
|
4075
|
+
|
|
4076
|
+
; ---- cons (PeTTa alias of cons-atom) ----
|
|
4077
|
+
(= (cons $h $t) (cons-atom $h $t))
|
|
4078
|
+
|
|
4079
|
+
; ---- progn: evaluate each argument in order, return the last (arguments evaluate applicatively, so the
|
|
4080
|
+
; earlier ones run for their side effects) ----
|
|
4081
|
+
(= (progn $a) $a)
|
|
4082
|
+
(= (progn $a $b) $b)
|
|
4083
|
+
(= (progn $a $b $c) $c)
|
|
4084
|
+
(= (progn $a $b $c $d) $d)
|
|
4085
|
+
|
|
4086
|
+
; ---- prog1: evaluate each argument in order, return the FIRST (the others run for their side effects) ----
|
|
4087
|
+
(= (prog1 $a) $a)
|
|
4088
|
+
(= (prog1 $a $b) $a)
|
|
4089
|
+
(= (prog1 $a $b $c) $a)
|
|
4090
|
+
(= (prog1 $a $b $c $d) $a)
|
|
4091
|
+
|
|
4092
|
+
; ---- forall: True iff every nondeterministic result of the generator passes the check ----
|
|
4093
|
+
(: forall (-> Atom Atom Bool))
|
|
4094
|
+
(: all-true (-> Atom %Undefined% Bool))
|
|
4095
|
+
(= (all-true $check $rs)
|
|
4096
|
+
(if (== $rs ())
|
|
4097
|
+
True
|
|
4098
|
+
(let* (($h (car-atom $rs)) ($r (cdr-atom $rs)) ($ok ($check $h)))
|
|
4099
|
+
(if $ok (all-true $check $r) False))))
|
|
4100
|
+
(= (forall $gen $check)
|
|
4101
|
+
(let $rs (collapse $gen) (all-true $check $rs)))
|
|
4102
|
+
|
|
4103
|
+
; ---- foldl: fold a function over a list, init as the seed; applies ($f elem acc), left to right ----
|
|
4104
|
+
(: foldl (-> Atom %Undefined% %Undefined% %Undefined%))
|
|
4105
|
+
(= (foldl $f $list $acc)
|
|
4106
|
+
(if (== $list ())
|
|
4107
|
+
$acc
|
|
4108
|
+
(let* (($h (car-atom $list)) ($t (cdr-atom $list)) ($a1 ($f $h $acc)))
|
|
4109
|
+
(foldl $f $t $a1))))
|
|
4110
|
+
|
|
4111
|
+
; ---- reduce: PeTTa's full-evaluation operator. Its argument is %Undefined%-typed, so @metta-ts has
|
|
4112
|
+
; already evaluated it to a normal form by the time the rule fires; returning it (identity) is
|
|
4113
|
+
; therefore exactly "fully evaluate the argument". Hyperon's single-step eval is the distinct op.
|
|
4114
|
+
(= (reduce $x) $x)
|
|
4115
|
+
|
|
4116
|
+
; ---- find: True iff a pattern matches anything in a space, else False (PeTTa lib_spaces; the
|
|
4117
|
+
; minimal-MeTTa unify-space case as a boolean). Uses match + case, both Hyperon ops. ----
|
|
4118
|
+
(= (find $space $pattern)
|
|
4119
|
+
(case (match $space $pattern True)
|
|
4120
|
+
((True True)
|
|
4121
|
+
(Empty False))))
|
|
4122
|
+
|
|
4123
|
+
; ---- match-count: count matches of a pattern without listifying them (PeTTa lib_spaces). ----
|
|
4124
|
+
(= (match-count $space $pattern)
|
|
4125
|
+
(foldall + (match $space $pattern 1) 0))
|
|
4126
|
+
|
|
4127
|
+
; ---- iterate: apply $step ($i $state) -> $state' n times, counting $i up (PeTTa lib_patrick). $step is
|
|
4128
|
+
; a symbol or a |-> lambda; ($step $i $state) is an ordinary application. ----
|
|
4129
|
+
(= (iterate $i $n $state $step)
|
|
4130
|
+
(if (== $n 0)
|
|
4131
|
+
$state
|
|
4132
|
+
(iterate (+ $i 1) (- $n 1) ($step $i $state) $step)))
|
|
4133
|
+
|
|
4134
|
+
; ---- maplist: apply a function (symbol or lambda) to each element of a tuple ----
|
|
4135
|
+
; cons-atom's head is Atom-typed (unevaluated), so the application ($f $h) and the recursive call are
|
|
4136
|
+
; forced through let* before being consed.
|
|
4137
|
+
(: maplist (-> Atom Atom %Undefined%))
|
|
4138
|
+
(= (maplist $f $list)
|
|
4139
|
+
(if (== $list ())
|
|
4140
|
+
()
|
|
4141
|
+
(let* (($h (car-atom $list))
|
|
4142
|
+
($t (cdr-atom $list))
|
|
4143
|
+
($fh ($f $h))
|
|
4144
|
+
($rest (maplist $f $t)))
|
|
4145
|
+
(cons-atom $fh $rest))))
|
|
4146
|
+
`;
|
|
4147
|
+
var cache2;
|
|
4148
|
+
function pettaStdlibAtoms() {
|
|
4149
|
+
if (cache2 === void 0)
|
|
4150
|
+
cache2 = parseAll(PETTA_STDLIB_SRC, standardTokenizer()).filter((t) => !t.bang).map((t) => t.atom);
|
|
4151
|
+
return cache2;
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
// src/runner.ts
|
|
4155
|
+
function standardTokenizer() {
|
|
4156
|
+
const t = new Tokenizer();
|
|
4157
|
+
t.register(/^-?\d+$/, (s) => gint(BigInt(s)));
|
|
4158
|
+
t.register(/^-?\d+\.\d+$/, (s) => gfloat(Number(s)));
|
|
4159
|
+
t.register(/^-?\d+(\.\d+)?[eE][-+]?\d+$/, (s) => gfloat(Number(s)));
|
|
4160
|
+
t.register(/^True$/, () => gbool(true));
|
|
4161
|
+
t.register(/^False$/, () => gbool(false));
|
|
4162
|
+
return t;
|
|
4163
|
+
}
|
|
4164
|
+
var preludeCache;
|
|
4165
|
+
function preludeAtoms() {
|
|
4166
|
+
if (preludeCache === void 0)
|
|
4167
|
+
preludeCache = parseAll(PRELUDE_SRC, standardTokenizer()).filter((t) => !t.bang).map((t) => t.atom);
|
|
4168
|
+
return preludeCache;
|
|
4169
|
+
}
|
|
4170
|
+
var DEFAULT_FUEL2 = 1e5;
|
|
4171
|
+
var DEFAULT_TABLING = true;
|
|
4172
|
+
function buildDefaultEnv(imports, tabling) {
|
|
4173
|
+
const env = buildEnv(
|
|
4174
|
+
[...preludeAtoms(), ...stdlibAtoms(), ...pettaStdlibAtoms()],
|
|
4175
|
+
stdTable()
|
|
4176
|
+
);
|
|
4177
|
+
env.imports = withBuiltinModules(imports);
|
|
4178
|
+
if (tabling) {
|
|
4179
|
+
env.table = /* @__PURE__ */ new Map();
|
|
4180
|
+
env.pureFunctors = analyzePurity(env);
|
|
4181
|
+
env.compiled = /* @__PURE__ */ new Map();
|
|
4182
|
+
env.compileDirty = true;
|
|
4183
|
+
}
|
|
4184
|
+
return env;
|
|
4185
|
+
}
|
|
4186
|
+
function evalSequential(atoms, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map(), opts = {}) {
|
|
4187
|
+
const out = [];
|
|
4188
|
+
let st = initSt();
|
|
4189
|
+
if (opts.maxStackDepth !== void 0) st.world.maxStackDepth = opts.maxStackDepth;
|
|
4190
|
+
const env = buildDefaultEnv(imports, opts.tabling ?? DEFAULT_TABLING);
|
|
4191
|
+
if (opts.parEvalImpl !== void 0) {
|
|
4192
|
+
const rulesSrc = atoms.filter((a) => !a.bang).map((a) => format(a.atom)).join("\n");
|
|
4193
|
+
const impl = opts.parEvalImpl;
|
|
4194
|
+
env.parEval = (branchSrcs, firstOnly) => impl(rulesSrc, branchSrcs, firstOnly).map(
|
|
4195
|
+
(r) => r === null ? null : r.flatMap((s) => parseAll(s, standardTokenizer()).map((p) => p.atom))
|
|
4196
|
+
);
|
|
4197
|
+
}
|
|
4198
|
+
for (const { atom, bang } of atoms) {
|
|
4199
|
+
if (!bang) {
|
|
4200
|
+
addAtomToEnv(env, atom);
|
|
4201
|
+
continue;
|
|
4202
|
+
}
|
|
4203
|
+
const [pairs, st2] = mettaEval(env, fuel, st, [], atom);
|
|
4204
|
+
st = st2;
|
|
4205
|
+
out.push({ query: atom, results: pairs.map((p) => p[0]) });
|
|
4206
|
+
}
|
|
4207
|
+
return out;
|
|
4208
|
+
}
|
|
4209
|
+
function runProgram(src, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map(), opts = {}) {
|
|
4210
|
+
return evalSequential(parseAll(src, standardTokenizer()), fuel, imports, opts);
|
|
4211
|
+
}
|
|
4212
|
+
async function runProgramAsync(src, asyncOps = /* @__PURE__ */ new Map(), fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map()) {
|
|
4213
|
+
const parsed = parseAll(src, standardTokenizer());
|
|
4214
|
+
const env = buildDefaultEnv(imports, false);
|
|
4215
|
+
for (const [k, v] of asyncOps) env.agt.set(k, v);
|
|
4216
|
+
const out = [];
|
|
4217
|
+
let st = initSt();
|
|
4218
|
+
for (const { atom, bang } of parsed) {
|
|
4219
|
+
if (!bang) {
|
|
4220
|
+
addAtomToEnv(env, atom);
|
|
4221
|
+
continue;
|
|
4222
|
+
}
|
|
4223
|
+
const [pairs, st2] = await mettaEvalAsync(env, fuel, st, [], atom);
|
|
4224
|
+
st = st2;
|
|
4225
|
+
out.push({ query: atom, results: pairs.map((p) => p[0]) });
|
|
4226
|
+
}
|
|
4227
|
+
return out;
|
|
4228
|
+
}
|
|
4229
|
+
function collectImports(src) {
|
|
4230
|
+
const out = [];
|
|
4231
|
+
for (const { atom } of parseAll(src, standardTokenizer())) {
|
|
4232
|
+
if (atom.kind === "expr" && atom.items.length === 3 && atom.items[0].kind === "sym" && atom.items[0].name === "import!" && atom.items[2].kind === "sym")
|
|
4233
|
+
out.push(atom.items[2].name);
|
|
4234
|
+
}
|
|
4235
|
+
return out;
|
|
4236
|
+
}
|
|
4237
|
+
function isOraclePass(r) {
|
|
4238
|
+
return r.results.length === 1 && r.results[0].kind === "expr" && r.results[0].items.length === 0;
|
|
4239
|
+
}
|
|
4240
|
+
function oracleReport(src, fuel = DEFAULT_FUEL2, imports = /* @__PURE__ */ new Map()) {
|
|
4241
|
+
const results = runProgram(src, fuel, imports);
|
|
4242
|
+
let passed = 0;
|
|
4243
|
+
const failures = [];
|
|
4244
|
+
for (const r of results) {
|
|
4245
|
+
if (isOraclePass(r)) passed++;
|
|
4246
|
+
else
|
|
4247
|
+
failures.push(
|
|
4248
|
+
`FAIL: ${format(r.query)}
|
|
4249
|
+
got: ${r.results.map(format).join(" ") || "(no results)"}`
|
|
4250
|
+
);
|
|
4251
|
+
}
|
|
4252
|
+
return { total: results.length, passed, failures };
|
|
4253
|
+
}
|
|
4254
|
+
|
|
4255
|
+
// src/flat-kb.ts
|
|
4256
|
+
var TAG_ARITY = 0;
|
|
4257
|
+
var TAG_SYMBOL = 1;
|
|
4258
|
+
var TAG_NEWVAR = 2;
|
|
4259
|
+
var TAG_VARREF = 3;
|
|
4260
|
+
var tagOf = (tok2) => tok2 >>> 28 & 15;
|
|
4261
|
+
var payloadOf = (tok2) => tok2 & 268435455;
|
|
4262
|
+
var tok = (tag, payload = 0) => tag << 28 | payload | 0;
|
|
4263
|
+
var Interner = class {
|
|
4264
|
+
byKey = /* @__PURE__ */ new Map();
|
|
4265
|
+
entries = [];
|
|
4266
|
+
add(key, entry) {
|
|
4267
|
+
const existing = this.byKey.get(key);
|
|
4268
|
+
if (existing !== void 0) return existing;
|
|
4269
|
+
const id = this.entries.length;
|
|
4270
|
+
if (id > 268435455) throw new Error("flat-kb: interner exceeded 2^28 unique leaves");
|
|
4271
|
+
this.entries.push(entry);
|
|
4272
|
+
this.byKey.set(key, id);
|
|
4273
|
+
return id;
|
|
4274
|
+
}
|
|
4275
|
+
internSym(name) {
|
|
4276
|
+
return this.add("s\0" + name, { kind: "sym", name });
|
|
4277
|
+
}
|
|
4278
|
+
internGround(value) {
|
|
4279
|
+
return this.add(groundKey(value), { kind: "gnd", value });
|
|
4280
|
+
}
|
|
4281
|
+
/** The id for a symbol/ground if already interned, else undefined (a pattern symbol absent from the
|
|
4282
|
+
* KB can never match, so its lookup short-circuits). */
|
|
4283
|
+
lookupSym(name) {
|
|
4284
|
+
return this.byKey.get("s\0" + name);
|
|
4285
|
+
}
|
|
4286
|
+
lookupGround(value) {
|
|
4287
|
+
return this.byKey.get(groundKey(value));
|
|
4288
|
+
}
|
|
4289
|
+
/** Reconstruct the atom for a leaf id. */
|
|
4290
|
+
decodeLeaf(id) {
|
|
4291
|
+
const e = this.entries[id];
|
|
4292
|
+
return e.kind === "sym" ? sym(e.name) : gnd(e.value);
|
|
4293
|
+
}
|
|
4294
|
+
get size() {
|
|
4295
|
+
return this.entries.length;
|
|
4296
|
+
}
|
|
4297
|
+
};
|
|
4298
|
+
function groundKey(v) {
|
|
4299
|
+
switch (v.g) {
|
|
4300
|
+
case "int":
|
|
4301
|
+
return "i\0" + v.n;
|
|
4302
|
+
case "float":
|
|
4303
|
+
return "f\0" + v.n;
|
|
4304
|
+
case "str":
|
|
4305
|
+
return "S\0" + v.s;
|
|
4306
|
+
case "bool":
|
|
4307
|
+
return "b\0" + (v.b ? "1" : "0");
|
|
4308
|
+
case "unit":
|
|
4309
|
+
return "u";
|
|
4310
|
+
case "error":
|
|
4311
|
+
return "e\0" + v.msg;
|
|
4312
|
+
case "ext":
|
|
4313
|
+
return "x\0" + v.kind + "\0" + v.id;
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
function encodeInto(a, out, it, varMap) {
|
|
4317
|
+
switch (a.kind) {
|
|
4318
|
+
case "sym":
|
|
4319
|
+
out.push(tok(TAG_SYMBOL, it.internSym(a.name)));
|
|
4320
|
+
return;
|
|
4321
|
+
case "gnd":
|
|
4322
|
+
out.push(tok(TAG_SYMBOL, it.internGround(a.value)));
|
|
4323
|
+
return;
|
|
4324
|
+
case "var": {
|
|
4325
|
+
const existing = varMap.get(a.name);
|
|
4326
|
+
if (existing === void 0) {
|
|
4327
|
+
varMap.set(a.name, varMap.size);
|
|
4328
|
+
out.push(tok(TAG_NEWVAR));
|
|
4329
|
+
} else {
|
|
4330
|
+
out.push(tok(TAG_VARREF, existing));
|
|
4331
|
+
}
|
|
4332
|
+
return;
|
|
4333
|
+
}
|
|
4334
|
+
case "expr":
|
|
4335
|
+
out.push(tok(TAG_ARITY, a.items.length));
|
|
4336
|
+
for (const child of a.items) encodeInto(child, out, it, varMap);
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
function encodeAtom(a, it) {
|
|
4341
|
+
const out = [];
|
|
4342
|
+
encodeInto(a, out, it, /* @__PURE__ */ new Map());
|
|
4343
|
+
return out;
|
|
4344
|
+
}
|
|
4345
|
+
function decodeAt(tokens, pos, it) {
|
|
4346
|
+
let nextVar = 0;
|
|
4347
|
+
const go = (p) => {
|
|
4348
|
+
const t = tokens[p];
|
|
4349
|
+
const tag = tagOf(t);
|
|
4350
|
+
const payload = payloadOf(t);
|
|
4351
|
+
switch (tag) {
|
|
4352
|
+
case TAG_SYMBOL:
|
|
4353
|
+
return [it.decodeLeaf(payload), p + 1];
|
|
4354
|
+
case TAG_NEWVAR:
|
|
4355
|
+
return [variable(String(nextVar++)), p + 1];
|
|
4356
|
+
case TAG_VARREF:
|
|
4357
|
+
return [variable(String(payload)), p + 1];
|
|
4358
|
+
case TAG_ARITY: {
|
|
4359
|
+
const items = [];
|
|
4360
|
+
let q = p + 1;
|
|
4361
|
+
for (let i = 0; i < payload; i++) {
|
|
4362
|
+
const [child, nq] = go(q);
|
|
4363
|
+
items.push(child);
|
|
4364
|
+
q = nq;
|
|
4365
|
+
}
|
|
4366
|
+
return [expr(items), q];
|
|
4367
|
+
}
|
|
4368
|
+
default:
|
|
4369
|
+
throw new Error(`flat-kb: bad token tag ${tag}`);
|
|
4370
|
+
}
|
|
4371
|
+
};
|
|
4372
|
+
return go(pos);
|
|
4373
|
+
}
|
|
4374
|
+
function decodeAtom(tokens, it) {
|
|
4375
|
+
return decodeAt(tokens, 0, it)[0];
|
|
4376
|
+
}
|
|
4377
|
+
function subtermLen(tokens, pos) {
|
|
4378
|
+
const t = tokens[pos];
|
|
4379
|
+
if (tagOf(t) === TAG_ARITY) {
|
|
4380
|
+
let len = 1;
|
|
4381
|
+
let p = pos + 1;
|
|
4382
|
+
for (let i = 0; i < payloadOf(t); i++) {
|
|
4383
|
+
const l = subtermLen(tokens, p);
|
|
4384
|
+
len += l;
|
|
4385
|
+
p += l;
|
|
4386
|
+
}
|
|
4387
|
+
return len;
|
|
4388
|
+
}
|
|
4389
|
+
return 1;
|
|
4390
|
+
}
|
|
4391
|
+
function rangeEq(a, as, b, bs) {
|
|
4392
|
+
const len = subtermLen(a, as);
|
|
4393
|
+
if (len !== subtermLen(b, bs)) return false;
|
|
4394
|
+
for (let i = 0; i < len; i++) if (a[as + i] !== b[bs + i]) return false;
|
|
4395
|
+
return true;
|
|
4396
|
+
}
|
|
4397
|
+
function encodePattern(a, it) {
|
|
4398
|
+
const tokens = [];
|
|
4399
|
+
const varNames = [];
|
|
4400
|
+
const varMap = /* @__PURE__ */ new Map();
|
|
4401
|
+
const go = (x) => {
|
|
4402
|
+
switch (x.kind) {
|
|
4403
|
+
case "sym": {
|
|
4404
|
+
const id = it.lookupSym(x.name);
|
|
4405
|
+
if (id === void 0) return false;
|
|
4406
|
+
tokens.push(tok(TAG_SYMBOL, id));
|
|
4407
|
+
return true;
|
|
4408
|
+
}
|
|
4409
|
+
case "gnd": {
|
|
4410
|
+
const id = it.lookupGround(x.value);
|
|
4411
|
+
if (id === void 0) return false;
|
|
4412
|
+
tokens.push(tok(TAG_SYMBOL, id));
|
|
4413
|
+
return true;
|
|
4414
|
+
}
|
|
4415
|
+
case "var": {
|
|
4416
|
+
const existing = varMap.get(x.name);
|
|
4417
|
+
if (existing === void 0) {
|
|
4418
|
+
varMap.set(x.name, varNames.length);
|
|
4419
|
+
varNames.push(x.name);
|
|
4420
|
+
tokens.push(tok(TAG_NEWVAR));
|
|
4421
|
+
} else {
|
|
4422
|
+
tokens.push(tok(TAG_VARREF, existing));
|
|
4423
|
+
}
|
|
4424
|
+
return true;
|
|
4425
|
+
}
|
|
4426
|
+
case "expr":
|
|
4427
|
+
tokens.push(tok(TAG_ARITY, x.items.length));
|
|
4428
|
+
for (const c of x.items) if (!go(c)) return false;
|
|
4429
|
+
return true;
|
|
4430
|
+
}
|
|
4431
|
+
};
|
|
4432
|
+
return go(a) ? { tokens, varNames } : null;
|
|
4433
|
+
}
|
|
4434
|
+
function matchFlatAt(pat, fact, factStart) {
|
|
4435
|
+
const binds = /* @__PURE__ */ new Map();
|
|
4436
|
+
let varCounter = 0;
|
|
4437
|
+
let pp = 0;
|
|
4438
|
+
let fp = factStart;
|
|
4439
|
+
const go = () => {
|
|
4440
|
+
const pt = pat[pp];
|
|
4441
|
+
const ptag = tagOf(pt);
|
|
4442
|
+
if (ptag === TAG_NEWVAR) {
|
|
4443
|
+
const len = subtermLen(fact, fp);
|
|
4444
|
+
binds.set(varCounter++, [fp, fp + len]);
|
|
4445
|
+
pp += 1;
|
|
4446
|
+
fp += len;
|
|
4447
|
+
return true;
|
|
4448
|
+
}
|
|
4449
|
+
if (ptag === TAG_VARREF) {
|
|
4450
|
+
const ref = binds.get(payloadOf(pt));
|
|
4451
|
+
if (ref === void 0) return false;
|
|
4452
|
+
if (!rangeEq(fact, ref[0], fact, fp)) return false;
|
|
4453
|
+
pp += 1;
|
|
4454
|
+
fp += subtermLen(fact, fp);
|
|
4455
|
+
return true;
|
|
4456
|
+
}
|
|
4457
|
+
if (ptag === TAG_SYMBOL) {
|
|
4458
|
+
if (fact[fp] !== pt) return false;
|
|
4459
|
+
pp += 1;
|
|
4460
|
+
fp += 1;
|
|
4461
|
+
return true;
|
|
4462
|
+
}
|
|
4463
|
+
if (fact[fp] !== pt) return false;
|
|
4464
|
+
const n = payloadOf(pt);
|
|
4465
|
+
pp += 1;
|
|
4466
|
+
fp += 1;
|
|
4467
|
+
for (let i = 0; i < n; i++) if (!go()) return false;
|
|
4468
|
+
return true;
|
|
4469
|
+
};
|
|
4470
|
+
return go() ? binds : null;
|
|
4471
|
+
}
|
|
4472
|
+
var FlatKB = class {
|
|
4473
|
+
interner = new Interner();
|
|
4474
|
+
tokens = [];
|
|
4475
|
+
// functor id -> list of fact start offsets. Facts whose head is not a symbol (var-headed or non-expr)
|
|
4476
|
+
// are not keyed here; they go in `other`.
|
|
4477
|
+
byFunctor = /* @__PURE__ */ new Map();
|
|
4478
|
+
other = [];
|
|
4479
|
+
offsets = [];
|
|
4480
|
+
/** The token array (for packing into a SharedArrayBuffer). */
|
|
4481
|
+
get tokenArray() {
|
|
4482
|
+
return this.tokens;
|
|
4483
|
+
}
|
|
4484
|
+
/** Every fact's start offset, in insertion order (for sharding across workers). */
|
|
4485
|
+
get factOffsets() {
|
|
4486
|
+
return this.offsets;
|
|
4487
|
+
}
|
|
4488
|
+
/** Add a (typically ground) atom to the KB. */
|
|
4489
|
+
add(a) {
|
|
4490
|
+
const start = this.tokens.length;
|
|
4491
|
+
this.offsets.push(start);
|
|
4492
|
+
encodeInto(a, this.tokens, this.interner, /* @__PURE__ */ new Map());
|
|
4493
|
+
const head = this.tokens[start];
|
|
4494
|
+
if (tagOf(head) === TAG_ARITY) {
|
|
4495
|
+
const fid = this.tokens[start + 1];
|
|
4496
|
+
if (tagOf(fid) === TAG_SYMBOL) {
|
|
4497
|
+
const k = payloadOf(fid);
|
|
4498
|
+
const cur = this.byFunctor.get(k);
|
|
4499
|
+
if (cur === void 0) this.byFunctor.set(k, [start]);
|
|
4500
|
+
else cur.push(start);
|
|
4501
|
+
return;
|
|
4502
|
+
}
|
|
4503
|
+
} else if (tagOf(head) === TAG_SYMBOL) {
|
|
4504
|
+
const k = payloadOf(head);
|
|
4505
|
+
const cur = this.byFunctor.get(k);
|
|
4506
|
+
if (cur === void 0) this.byFunctor.set(k, [start]);
|
|
4507
|
+
else cur.push(start);
|
|
4508
|
+
return;
|
|
4509
|
+
}
|
|
4510
|
+
this.other.push(start);
|
|
4511
|
+
}
|
|
4512
|
+
/** Candidate fact offsets for a pattern, using the functor index when the pattern head is a known
|
|
4513
|
+
* symbol; otherwise every fact. */
|
|
4514
|
+
candidates(pattern) {
|
|
4515
|
+
const head = pattern.kind === "expr" && pattern.items.length > 0 ? pattern.items[0] : pattern;
|
|
4516
|
+
if (head !== void 0 && head.kind === "sym") {
|
|
4517
|
+
const fid = this.interner.lookupSym(head.name);
|
|
4518
|
+
if (fid === void 0) return [];
|
|
4519
|
+
return [...this.byFunctor.get(fid) ?? [], ...this.other];
|
|
4520
|
+
}
|
|
4521
|
+
return "all";
|
|
4522
|
+
}
|
|
4523
|
+
/** Match `pattern` against the KB, returning a binding map (variable name -> matched atom) per match. */
|
|
4524
|
+
match(pattern) {
|
|
4525
|
+
const enc = encodePattern(pattern, this.interner);
|
|
4526
|
+
if (enc === null) return [];
|
|
4527
|
+
const cand = this.candidates(pattern);
|
|
4528
|
+
const offsets = cand === "all" ? this.offsets : cand;
|
|
4529
|
+
const out = [];
|
|
4530
|
+
for (const off of offsets) {
|
|
4531
|
+
const binds = matchFlatAt(enc.tokens, this.tokens, off);
|
|
4532
|
+
if (binds === null) continue;
|
|
4533
|
+
const m = /* @__PURE__ */ new Map();
|
|
4534
|
+
for (const [idx, [s]] of binds)
|
|
4535
|
+
m.set(enc.varNames[idx], decodeAt(this.tokens, s, this.interner)[0]);
|
|
4536
|
+
out.push(m);
|
|
4537
|
+
}
|
|
4538
|
+
return out;
|
|
4539
|
+
}
|
|
4540
|
+
get size() {
|
|
4541
|
+
return this.offsets.length;
|
|
4542
|
+
}
|
|
4543
|
+
};
|
|
4544
|
+
var _internals = { tok, tagOf, payloadOf, subtermLen };
|
|
4545
|
+
|
|
4546
|
+
// src/flat-william.ts
|
|
4547
|
+
var { tagOf: tagOf2, payloadOf: payloadOf2 } = _internals;
|
|
4548
|
+
function eachSubterm(tokens, factStart, cb) {
|
|
4549
|
+
const go = (pos) => {
|
|
4550
|
+
const t = tokens[pos];
|
|
4551
|
+
const start = pos;
|
|
4552
|
+
if (tagOf2(t) === TAG_ARITY) {
|
|
4553
|
+
let p = pos + 1;
|
|
4554
|
+
for (let i = 0; i < payloadOf2(t); i++) p = go(p);
|
|
4555
|
+
cb(start, p);
|
|
4556
|
+
return p;
|
|
4557
|
+
}
|
|
4558
|
+
cb(start, pos + 1);
|
|
4559
|
+
return pos + 1;
|
|
4560
|
+
};
|
|
4561
|
+
go(factStart);
|
|
4562
|
+
}
|
|
4563
|
+
function williamTopK(kb, k, refCost = 4) {
|
|
4564
|
+
const tokens = kb.tokenArray;
|
|
4565
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4566
|
+
for (const factStart of kb.factOffsets) {
|
|
4567
|
+
eachSubterm(tokens, factStart, (s, e) => {
|
|
4568
|
+
let key = "";
|
|
4569
|
+
for (let i = s; i < e; i++) key += tokens[i] + ",";
|
|
4570
|
+
const info = counts.get(key);
|
|
4571
|
+
if (info !== void 0) info.count++;
|
|
4572
|
+
else counts.set(key, { count: 1, len: e - s, start: s });
|
|
4573
|
+
});
|
|
4574
|
+
}
|
|
4575
|
+
const scored = [];
|
|
4576
|
+
for (const info of counts.values()) {
|
|
4577
|
+
if (info.count < 2 || info.len < 2) continue;
|
|
4578
|
+
const gain = (info.count - 1) * info.len - info.count * refCost;
|
|
4579
|
+
if (gain > 0) scored.push({ ...info, gain });
|
|
4580
|
+
}
|
|
4581
|
+
scored.sort((a, b) => b.gain - a.gain || b.count - a.count);
|
|
4582
|
+
return scored.slice(0, k).map((s) => ({
|
|
4583
|
+
pattern: decodeAt(tokens, s.start, kb.interner)[0],
|
|
4584
|
+
count: s.count,
|
|
4585
|
+
len: s.len,
|
|
4586
|
+
gain: s.gain
|
|
4587
|
+
}));
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
// src/trail.ts
|
|
4591
|
+
var Trail = class {
|
|
4592
|
+
binds = /* @__PURE__ */ new Map();
|
|
4593
|
+
trail = [];
|
|
4594
|
+
/** A restore point: the current trail length. */
|
|
4595
|
+
mark() {
|
|
4596
|
+
return this.trail.length;
|
|
4597
|
+
}
|
|
4598
|
+
/** Undo every binding made since `m`. */
|
|
4599
|
+
undo(m) {
|
|
4600
|
+
const t = this.trail;
|
|
4601
|
+
while (t.length > m) this.binds.delete(t.pop());
|
|
4602
|
+
}
|
|
4603
|
+
/** Bind `$name` to `a` and record it on the trail. The caller guarantees `$name` is currently unbound. */
|
|
4604
|
+
bind(name, a) {
|
|
4605
|
+
this.binds.set(name, a);
|
|
4606
|
+
this.trail.push(name);
|
|
4607
|
+
}
|
|
4608
|
+
/** Follow variable bindings to the representative: a non-variable, or an unbound variable. */
|
|
4609
|
+
deref(a) {
|
|
4610
|
+
let cur = a;
|
|
4611
|
+
while (cur.kind === "var") {
|
|
4612
|
+
const v = this.binds.get(cur.name);
|
|
4613
|
+
if (v === void 0) return cur;
|
|
4614
|
+
cur = v;
|
|
4615
|
+
}
|
|
4616
|
+
return cur;
|
|
4617
|
+
}
|
|
4618
|
+
/** Resolve `a` against the current bindings, one pass (the same discipline as the immutable
|
|
4619
|
+
* `instantiate`/`applySubst`): a variable becomes its bound value as-is; the value's own variables are
|
|
4620
|
+
* not re-resolved, and an expression's children are resolved. This matches the evaluator exactly,
|
|
4621
|
+
* including that a cyclic binding (`$y = (.. $y ..)`, which `matchAtoms` produces and `hasLoop` does not
|
|
4622
|
+
* reject) terminates instead of looping. A new term is built only where a child changed. */
|
|
4623
|
+
resolve(a) {
|
|
4624
|
+
if (a.kind === "var") return this.deref(a);
|
|
4625
|
+
if (a.kind !== "expr" || a.ground) return a;
|
|
4626
|
+
const its = a.items;
|
|
4627
|
+
let items = null;
|
|
4628
|
+
for (let i = 0; i < its.length; i++) {
|
|
4629
|
+
const it = its[i];
|
|
4630
|
+
const r = this.resolve(it);
|
|
4631
|
+
if (items !== null) items.push(r);
|
|
4632
|
+
else if (r !== it) {
|
|
4633
|
+
items = its.slice(0, i);
|
|
4634
|
+
items.push(r);
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
return items === null ? a : { ...a, items };
|
|
4638
|
+
}
|
|
4639
|
+
};
|
|
4640
|
+
function unifyTrail(tr, l0, r0) {
|
|
4641
|
+
const l = tr.deref(l0);
|
|
4642
|
+
const r = tr.deref(r0);
|
|
4643
|
+
if (l === r) return true;
|
|
4644
|
+
if (l.kind === "var") {
|
|
4645
|
+
if (r.kind === "var" && l.name === r.name) return true;
|
|
4646
|
+
tr.bind(l.name, r);
|
|
4647
|
+
return true;
|
|
4648
|
+
}
|
|
4649
|
+
if (r.kind === "var") {
|
|
4650
|
+
tr.bind(r.name, l);
|
|
4651
|
+
return true;
|
|
4652
|
+
}
|
|
4653
|
+
if (l.kind === "sym") return r.kind === "sym" && l.name === r.name;
|
|
4654
|
+
if (l.kind === "gnd") return r.kind === "gnd" && atomEq(l, r);
|
|
4655
|
+
if (r.kind !== "expr" || l.items.length !== r.items.length) return false;
|
|
4656
|
+
for (let i = 0; i < l.items.length; i++)
|
|
4657
|
+
if (!unifyTrail(tr, l.items[i], r.items[i])) return false;
|
|
4658
|
+
return true;
|
|
4659
|
+
}
|
|
4660
|
+
export {
|
|
4661
|
+
AsyncInSyncError,
|
|
4662
|
+
BAIL,
|
|
4663
|
+
CONCURRENCY_MODULE_SRC,
|
|
4664
|
+
CURRY_MODULE_SRC,
|
|
4665
|
+
DEFAULT_FUEL2 as DEFAULT_FUEL,
|
|
4666
|
+
FlatKB,
|
|
4667
|
+
IMPURE_OPS,
|
|
4668
|
+
InMemorySpace,
|
|
4669
|
+
Interner,
|
|
4670
|
+
STDLIB_SRC,
|
|
4671
|
+
TAG_ARITY,
|
|
4672
|
+
TAG_NEWVAR,
|
|
4673
|
+
TAG_SYMBOL,
|
|
4674
|
+
TAG_VARREF,
|
|
4675
|
+
Tokenizer,
|
|
4676
|
+
Trail,
|
|
4677
|
+
_internals,
|
|
4678
|
+
addAtomToEnv,
|
|
4679
|
+
addEqRaw,
|
|
4680
|
+
addInt,
|
|
4681
|
+
addValRaw,
|
|
4682
|
+
addVarBinding,
|
|
4683
|
+
addVarEquality,
|
|
4684
|
+
alphaEq,
|
|
4685
|
+
analyzePurity,
|
|
4686
|
+
applySubst,
|
|
4687
|
+
atomEq,
|
|
4688
|
+
atomSize,
|
|
4689
|
+
atomVars,
|
|
4690
|
+
baseTable,
|
|
4691
|
+
bindingsToSubst,
|
|
4692
|
+
buildEnv,
|
|
4693
|
+
builtinModules,
|
|
4694
|
+
callGrounded,
|
|
4695
|
+
canonInt,
|
|
4696
|
+
cmpIntVal,
|
|
4697
|
+
collectImports,
|
|
4698
|
+
collectVars,
|
|
4699
|
+
compileEnv,
|
|
4700
|
+
decodeAt,
|
|
4701
|
+
decodeAtom,
|
|
4702
|
+
emptyBindings,
|
|
4703
|
+
emptyEnv,
|
|
4704
|
+
emptyExpr,
|
|
4705
|
+
emptySubst,
|
|
4706
|
+
encodeAtom,
|
|
4707
|
+
encodeInto,
|
|
4708
|
+
encodePattern,
|
|
4709
|
+
eraseSubst,
|
|
4710
|
+
evalAtom,
|
|
4711
|
+
evalSequential,
|
|
4712
|
+
expr,
|
|
4713
|
+
extendSubst,
|
|
4714
|
+
format,
|
|
4715
|
+
freshenRule,
|
|
4716
|
+
gbool,
|
|
4717
|
+
getTypes,
|
|
4718
|
+
gfloat,
|
|
4719
|
+
gint,
|
|
4720
|
+
gnd,
|
|
4721
|
+
groundEq,
|
|
4722
|
+
groundType,
|
|
4723
|
+
gstr,
|
|
4724
|
+
gunit,
|
|
4725
|
+
hasLoop,
|
|
4726
|
+
hashOf,
|
|
4727
|
+
initSt,
|
|
4728
|
+
instantiate,
|
|
4729
|
+
intAbs,
|
|
4730
|
+
intDiv,
|
|
4731
|
+
intMod,
|
|
4732
|
+
isErrorAtom,
|
|
4733
|
+
isExpr,
|
|
4734
|
+
isGnd,
|
|
4735
|
+
isOraclePass,
|
|
4736
|
+
isSym,
|
|
4737
|
+
isVar,
|
|
4738
|
+
isZero,
|
|
4739
|
+
keyWellFormed,
|
|
4740
|
+
lookupSubst,
|
|
4741
|
+
lookupVal,
|
|
4742
|
+
matchAtoms,
|
|
4743
|
+
matchAtomsScoped,
|
|
4744
|
+
matchAtomsWith,
|
|
4745
|
+
matchFlatAt,
|
|
4746
|
+
merge,
|
|
4747
|
+
metaType,
|
|
4748
|
+
mettaEval,
|
|
4749
|
+
mettaEvalAsync,
|
|
4750
|
+
mulInt,
|
|
4751
|
+
occurs,
|
|
4752
|
+
oracleReport,
|
|
4753
|
+
parse,
|
|
4754
|
+
parseAll,
|
|
4755
|
+
pettaOpNames,
|
|
4756
|
+
preludeAtoms,
|
|
4757
|
+
removeVal,
|
|
4758
|
+
runCompiled,
|
|
4759
|
+
runProgram,
|
|
4760
|
+
runProgramAsync,
|
|
4761
|
+
setOutputSink,
|
|
4762
|
+
setRawSink,
|
|
4763
|
+
standardTokenizer,
|
|
4764
|
+
stdTable,
|
|
4765
|
+
stdlibAtoms,
|
|
4766
|
+
subInt,
|
|
4767
|
+
sym,
|
|
4768
|
+
tableKey,
|
|
4769
|
+
toF64,
|
|
4770
|
+
unifiable,
|
|
4771
|
+
unifyTop,
|
|
4772
|
+
unifyTrail,
|
|
4773
|
+
variable,
|
|
4774
|
+
wcoJoin,
|
|
4775
|
+
williamTopK,
|
|
4776
|
+
withBuiltinModules
|
|
4777
|
+
};
|