@mark1russell7/coeval 0.7.0 → 0.8.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/build/index.js CHANGED
@@ -357,6 +357,17 @@ function describe(value) {
357
357
  //#endregion
358
358
  //#region src/world.ts
359
359
  /**
360
+ * This function gives the type of a bare equation of a kind (D42). It is the type `of` of the shape of its parts, or
361
+ * else the type `of` of the shape `rest` of a record. The plan, the reference and `check` read it with this one function.
362
+ *
363
+ * @param kind - The kind.
364
+ * @returns The type, or `undefined` when the shape declares none.
365
+ */
366
+ function equationType(kind) {
367
+ const parts = kind.parts;
368
+ return parts?.of ?? parts?.rest?.of;
369
+ }
370
+ /**
360
371
  * This function tells if an entry of the world is a kind.
361
372
  *
362
373
  * @param entry - The entry.
@@ -759,7 +770,7 @@ function fits(found, expected, domains) {
759
770
  return fitsAt(found, expected, domains, 0);
760
771
  }
761
772
  /** This function sets an own field of a new record. Only the key `__proto__` needs `defineProperty`. */
762
- function setOwn$4(target, key, value) {
773
+ function setOwn$5(target, key, value) {
763
774
  if (key === "__proto__") Object.defineProperty(target, key, {
764
775
  value,
765
776
  enumerable: true,
@@ -778,10 +789,10 @@ function joinRecords(a, b, domains, depth) {
778
789
  const inA = Object.hasOwn(a.fields, key);
779
790
  const inB = Object.hasOwn(b.fields, key);
780
791
  if (inA && inB) {
781
- setOwn$4(fields, key, joinAt(a.fields[key], b.fields[key], domains, depth));
792
+ setOwn$5(fields, key, joinAt(a.fields[key], b.fields[key], domains, depth));
782
793
  if (a.optional.has(key) || b.optional.has(key)) optional.push(key);
783
794
  } else if (closed) {
784
- setOwn$4(fields, key, inA ? a.fields[key] : b.fields[key]);
795
+ setOwn$5(fields, key, inA ? a.fields[key] : b.fields[key]);
785
796
  optional.push(key);
786
797
  }
787
798
  }
@@ -1185,7 +1196,7 @@ function keyOf(path) {
1185
1196
  return JSON.stringify(path.map(String));
1186
1197
  }
1187
1198
  /** This function sets an own data property. An assignment to the key `__proto__` changes the prototype. */
1188
- function setOwn$3(target, key, value) {
1199
+ function setOwn$4(target, key, value) {
1189
1200
  if (key === "__proto__") Object.defineProperty(target, key, {
1190
1201
  value,
1191
1202
  enumerable: true,
@@ -1202,7 +1213,7 @@ function defined(value) {
1202
1213
  if (Array.isArray(value)) return value.map(defined);
1203
1214
  if (!isRecord(value)) return value;
1204
1215
  const out = {};
1205
- for (const key of Object.keys(value)) if (value[key] !== void 0) setOwn$3(out, key, defined(value[key]));
1216
+ for (const key of Object.keys(value)) if (value[key] !== void 0) setOwn$4(out, key, defined(value[key]));
1206
1217
  return out;
1207
1218
  }
1208
1219
  /** Two values are the same when they are equal by `docEquals`. A function and a host value are equal only to themselves. */
@@ -1247,7 +1258,7 @@ function extendDomain(name, more) {
1247
1258
  ...Object.keys(steps).length === 0 ? {} : { steps }
1248
1259
  };
1249
1260
  const domains = {};
1250
- setOwn$3(domains, name, domain);
1261
+ setOwn$4(domains, name, domain);
1251
1262
  return {
1252
1263
  domains,
1253
1264
  replaces: [["domains", name]]
@@ -1297,10 +1308,10 @@ function mergeLeaf(m, table, key, later, path, part, replaces, equal, reason) {
1297
1308
  if (later === void 0) return;
1298
1309
  const earlier = own$2(table, key);
1299
1310
  if (earlier === void 0) {
1300
- setOwn$3(table, key, later);
1311
+ setOwn$4(table, key, later);
1301
1312
  m.give(path, part);
1302
1313
  } else if (replaces.has(keyOf(path))) {
1303
- setOwn$3(table, key, later);
1314
+ setOwn$4(table, key, later);
1304
1315
  m.replace(path, part);
1305
1316
  } else if (!equal(earlier, later)) m.clash(path, part, reason);
1306
1317
  }
@@ -1321,9 +1332,9 @@ function mergeEntries(m, into, from, path, part, replaces) {
1321
1332
  const at = [...path, key];
1322
1333
  const earlier = own$2(into, key);
1323
1334
  if (earlier === void 0) {
1324
- setOwn$3(into, key, later);
1335
+ setOwn$4(into, key, later);
1325
1336
  m.give(at, part);
1326
- } else setOwn$3(into, key, mergeEntry(m, earlier, later, at, part, replaces));
1337
+ } else setOwn$4(into, key, mergeEntry(m, earlier, later, at, part, replaces));
1327
1338
  }
1328
1339
  }
1329
1340
  /** This function merges two entries at one path. Two namespaces merge key by key, and their fallbacks merge too. */
@@ -1476,8 +1487,8 @@ function mergeCode(m, draft, part, index, replaces) {
1476
1487
  const runnerPath = ["runners", name];
1477
1488
  if (replaces.has(keyOf(evaluatorPath)) || replaces.has(keyOf(runnerPath))) {
1478
1489
  if (evaluator === void 0) delete draft.evaluators[name];
1479
- else setOwn$3(draft.evaluators, name, evaluator);
1480
- if (runner !== void 0) setOwn$3(draft.runners ??= {}, name, runner);
1490
+ else setOwn$4(draft.evaluators, name, evaluator);
1491
+ if (runner !== void 0) setOwn$4(draft.runners ??= {}, name, runner);
1481
1492
  else if (draft.runners !== void 0) delete draft.runners[name];
1482
1493
  m.replace(evaluatorPath, index);
1483
1494
  m.replace(runnerPath, index);
@@ -1600,7 +1611,7 @@ function removeEntry(entries, path) {
1600
1611
  }
1601
1612
  const out = { ...entries };
1602
1613
  if (next === void 0) delete out[key];
1603
- else setOwn$3(out, key, next);
1614
+ else setOwn$4(out, key, next);
1604
1615
  return out;
1605
1616
  }
1606
1617
  /**
@@ -1694,7 +1705,7 @@ const RUNGS = [
1694
1705
  "kind",
1695
1706
  "default"
1696
1707
  ];
1697
- function entryOf(verbs, verb) {
1708
+ function entryOf$1(verbs, verb) {
1698
1709
  return verbs !== void 0 && Object.hasOwn(verbs, verb) ? verbs[verb] : void 0;
1699
1710
  }
1700
1711
  /**
@@ -1735,18 +1746,18 @@ const EACH_NAME = () => true;
1735
1746
  * @returns The evaluator name and its rung, or `undefined` when no rung answers.
1736
1747
  */
1737
1748
  function answerOf(world, own, kind, verb, has = EACH_NAME) {
1738
- const ownName = entryOf(own, verb);
1749
+ const ownName = entryOf$1(own, verb);
1739
1750
  if (ownName !== void 0 && has(ownName)) return {
1740
1751
  name: ownName,
1741
1752
  rung: "own"
1742
1753
  };
1743
1754
  if (kind === null) return void 0;
1744
- const kindName = kind === void 0 ? void 0 : entryOf(kind.verbs, verb);
1755
+ const kindName = kind === void 0 ? void 0 : entryOf$1(kind.verbs, verb);
1745
1756
  if (kindName !== void 0 && has(kindName)) return {
1746
1757
  name: kindName,
1747
1758
  rung: "kind"
1748
1759
  };
1749
- const fallback = entryOf(world.defaults, verb);
1760
+ const fallback = entryOf$1(world.defaults, verb);
1750
1761
  return fallback !== void 0 && has(fallback) ? {
1751
1762
  name: fallback,
1752
1763
  rung: "default"
@@ -1768,7 +1779,7 @@ function answerOf(world, own, kind, verb, has = EACH_NAME) {
1768
1779
  */
1769
1780
  function ask(world, doc, verb, options = {}) {
1770
1781
  const steps = [];
1771
- const own = entryOf(doc.own, verb);
1782
+ const own = entryOf$1(doc.own, verb);
1772
1783
  if (own !== void 0) {
1773
1784
  steps.push({
1774
1785
  rung: "own",
@@ -1808,7 +1819,7 @@ function ask(world, doc, verb, options = {}) {
1808
1819
  steps
1809
1820
  };
1810
1821
  }
1811
- const entry = entryOf(kind.verbs, verb);
1822
+ const entry = entryOf$1(kind.verbs, verb);
1812
1823
  if (entry !== void 0) {
1813
1824
  steps.push({
1814
1825
  rung: "kind",
@@ -1831,7 +1842,7 @@ function ask(world, doc, verb, options = {}) {
1831
1842
  source
1832
1843
  });
1833
1844
  }
1834
- const fallback = entryOf(world.defaults, verb);
1845
+ const fallback = entryOf$1(world.defaults, verb);
1835
1846
  if (fallback !== void 0) {
1836
1847
  steps.push({
1837
1848
  rung: "default",
@@ -2412,7 +2423,7 @@ var Bad = class {
2412
2423
  }
2413
2424
  };
2414
2425
  /** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
2415
- function setOwn$2(target, key, value) {
2426
+ function setOwn$3(target, key, value) {
2416
2427
  if (key === "__proto__") Object.defineProperty(target, key, {
2417
2428
  value,
2418
2429
  enumerable: true,
@@ -2584,7 +2595,7 @@ function splitParts(shape, value) {
2584
2595
  const out = {};
2585
2596
  for (const [key, child] of node.fields) {
2586
2597
  const kept = strip(child);
2587
- if (kept !== void 0) setOwn$2(out, key, kept);
2598
+ if (kept !== void 0) setOwn$3(out, key, kept);
2588
2599
  }
2589
2600
  return out;
2590
2601
  };
@@ -2593,7 +2604,7 @@ function splitParts(shape, value) {
2593
2604
  if (node.t === "slot") return handles[node.index];
2594
2605
  if (node.t === "list") return node.items.map((child) => fillWith(child, handles));
2595
2606
  const out = {};
2596
- for (const [key, child] of node.fields) setOwn$2(out, key, fillWith(child, handles));
2607
+ for (const [key, child] of node.fields) setOwn$3(out, key, fillWith(child, handles));
2597
2608
  return out;
2598
2609
  };
2599
2610
  return {
@@ -2667,6 +2678,75 @@ function pathMatches(path, pattern) {
2667
2678
  }
2668
2679
  return true;
2669
2680
  }
2681
+ function valueAt(value, path) {
2682
+ let here = value;
2683
+ for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
2684
+ else if (isRecord(here) && Object.hasOwn(here, String(key))) here = here[String(key)];
2685
+ else return void 0;
2686
+ return here;
2687
+ }
2688
+ function headerName(item) {
2689
+ return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
2690
+ }
2691
+ function namesOf(source, value, covered) {
2692
+ if ("fixed" in source) return source.fixed;
2693
+ if ("keysAt" in source) {
2694
+ const at = valueAt(value, source.keysAt);
2695
+ return isRecord(at) ? Object.keys(at) : [];
2696
+ }
2697
+ if ("listAt" in source) {
2698
+ const at = valueAt(value, source.listAt);
2699
+ return Array.isArray(at) ? at.filter((item) => typeof item === "string") : [];
2700
+ }
2701
+ if ("textAt" in source) {
2702
+ const at = valueAt(value, source.textAt);
2703
+ if (typeof at === "string") return [at];
2704
+ return source.otherwise === void 0 ? [] : [source.otherwise];
2705
+ }
2706
+ return covered.map((slot) => headerName(slot.item)).filter((name) => name !== void 0);
2707
+ }
2708
+ /**
2709
+ * This function gives the names that the scope rules of a kind give each part, and the names that only later parts
2710
+ * see. `check`, `conforms` and the plan read the scope rules with it.
2711
+ *
2712
+ * @param rules - The scope rules of the kind.
2713
+ * @param value - The value of the document.
2714
+ * @param slots - The parts of the value, in order.
2715
+ * @returns The names that each part sees, and the names that only the later parts see, by the index of the part.
2716
+ */
2717
+ function scopesOf(rules, value, slots) {
2718
+ const sees = slots.map(() => []);
2719
+ const later = slots.map(() => []);
2720
+ for (const rule of rules ?? []) {
2721
+ const covered = slots.map((slot, index) => ({
2722
+ slot,
2723
+ index
2724
+ })).filter(({ slot }) => rule.in.some((pattern) => pathMatches(slot.path, pattern)));
2725
+ if (rule.sequential !== true) {
2726
+ const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
2727
+ for (const { index } of covered) sees[index]?.push(...names);
2728
+ continue;
2729
+ }
2730
+ if ("headers" in rule.names) {
2731
+ covered.forEach(({ index }, position) => {
2732
+ const before = covered.slice(0, position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
2733
+ const after = covered.slice(position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
2734
+ sees[index]?.push(...before);
2735
+ later[index]?.push(...after);
2736
+ });
2737
+ continue;
2738
+ }
2739
+ const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
2740
+ covered.forEach(({ index }, position) => {
2741
+ if (position > 0) sees[index]?.push(...names);
2742
+ else later[index]?.push(...names);
2743
+ });
2744
+ }
2745
+ return {
2746
+ sees,
2747
+ later
2748
+ };
2749
+ }
2670
2750
  //#endregion
2671
2751
  //#region src/evaluate.ts
2672
2752
  /**
@@ -2727,7 +2807,7 @@ function narrow(parent, next) {
2727
2807
  };
2728
2808
  }
2729
2809
  /** No capabilities. One list serves each masked part. */
2730
- const NO_CAPS$1 = /* @__PURE__ */ Object.freeze([]);
2810
+ const NO_CAPS$2 = /* @__PURE__ */ Object.freeze([]);
2731
2811
  /** No capability rules. One list serves each part that no rule narrows. */
2732
2812
  const NO_RULES = /* @__PURE__ */ Object.freeze([]);
2733
2813
  /**
@@ -2755,7 +2835,7 @@ function rulesFor(rules, path) {
2755
2835
  function capsUnder(rules, caps) {
2756
2836
  let out = caps;
2757
2837
  for (const rule of rules) {
2758
- if (rule.rule === "mask") return NO_CAPS$1;
2838
+ if (rule.rule === "mask") return NO_CAPS$2;
2759
2839
  if (rule.rule === "only") out = intersectCaps(out, rule.caps);
2760
2840
  }
2761
2841
  return out;
@@ -2786,7 +2866,7 @@ const GRANT = /* @__PURE__ */ Symbol("coeval.grant");
2786
2866
  function granted(ctx) {
2787
2867
  const grant = ctx[GRANT];
2788
2868
  if (grant === ctx.caps) return ctx;
2789
- const caps = grant === void 0 ? NO_CAPS$1 : ctx.caps.every((cap) => permits(grant, cap)) ? ctx.caps : ctx.caps.filter((cap) => permits(grant, cap));
2869
+ const caps = grant === void 0 ? NO_CAPS$2 : ctx.caps.every((cap) => permits(grant, cap)) ? ctx.caps : ctx.caps.filter((cap) => permits(grant, cap));
2790
2870
  return {
2791
2871
  ...ctx,
2792
2872
  caps,
@@ -2952,6 +3032,10 @@ var Session = class {
2952
3032
  get effects() {
2953
3033
  return this.list ??= [];
2954
3034
  }
3035
+ /** `true` when the evaluation records its reads. Then folded code evaluates again, thus each read goes in the list (PLAN.FOLD). */
3036
+ get recording() {
3037
+ return this.reading !== void 0;
3038
+ }
2955
3039
  resolve(ctx, path, options) {
2956
3040
  return this.read(ctx, path, void 0, options);
2957
3041
  }
@@ -3416,6 +3500,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
3416
3500
  let meta = meta0;
3417
3501
  let name;
3418
3502
  let unknown;
3503
+ let quick;
3419
3504
  if (c.traced) {
3420
3505
  const answer = ask(world, envelope ?? {}, c.verb, declared === void 0 ? {} : { declaredType: declared });
3421
3506
  meta = {
@@ -3426,7 +3511,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
3426
3511
  name = answer.evaluator;
3427
3512
  unknown = answer.error === "unknown-kind";
3428
3513
  } else {
3429
- const quick = answerOf(world, envelope?.own, kind ?? null, c.verb);
3514
+ quick = answerOf(world, envelope?.own, kind ?? null, c.verb);
3430
3515
  name = quick?.name;
3431
3516
  unknown = quick === void 0 && kind === void 0;
3432
3517
  }
@@ -3437,9 +3522,11 @@ function compileNode(c, value, place, declared, depth, address = false) {
3437
3522
  const evaluator = name !== void 0 && Object.hasOwn(c.machine.evaluators, name) ? c.machine.evaluators[name] : void 0;
3438
3523
  if (name === void 0 || runner === void 0 && evaluator === void 0) return failing(c, meta, place, "#NOEVAL", `No rung gives an evaluator for ${kindText}.`);
3439
3524
  if (!split.ok) return failing(c, meta, place, "#VALUE!", split.reason);
3525
+ const frees = c.fold ? [] : void 0;
3440
3526
  const parts = split.parts.map((slot) => {
3441
3527
  const item = slot.item;
3442
3528
  const own = compileNode(c, item, place.concat(slot.path), slot.of, depth + 1, slot.address === true);
3529
+ frees?.push(own.free);
3443
3530
  const rules = rulesFor(kind?.caps, slot.path);
3444
3531
  const compiled = rules.length === 0 ? own : gated(rules, own);
3445
3532
  const header = typeof item?.name === "string" && isEnvelope(item) ? item.name : void 0;
@@ -3457,9 +3544,10 @@ function compileNode(c, value, place, declared, depth, address = false) {
3457
3544
  run
3458
3545
  };
3459
3546
  });
3547
+ const typePath = read.typePath ?? [];
3460
3548
  const input = {
3461
3549
  kind: kindText,
3462
- typePath: read.typePath ?? [],
3550
+ typePath,
3463
3551
  doc,
3464
3552
  value: split.parts.length === 0 ? doc.value : split.fill(parts),
3465
3553
  data: split.data,
@@ -3485,7 +3573,238 @@ function compileNode(c, value, place, declared, depth, address = false) {
3485
3573
  } catch (error) {
3486
3574
  return failingWith(c, meta, placed(thrown(error, `the evaluator ${name}`), place));
3487
3575
  }
3488
- return finish$1(c, meta, placedCode(inner, place, name), void 0);
3576
+ const done = finish$1(c, meta, placedCode(inner, place, name), void 0);
3577
+ if (frees === void 0 || kind === void 0 || !pureCode(c, envelope, kind, typePath, name, quick)) return done;
3578
+ const free = freeOf(doc, kind, split.parts, frees);
3579
+ if (free === void 0) return done;
3580
+ return free.length === 0 ? folded(c, done) : {
3581
+ code: done.code,
3582
+ run: done.run,
3583
+ free
3584
+ };
3585
+ }
3586
+ /** The free names of a closed part. */
3587
+ const CLOSED = /* @__PURE__ */ Object.freeze([]);
3588
+ /**
3589
+ * This function tells if the code of a document is pure, by the facts of D24 (FACTS.PURE). It reads the facts as
3590
+ * `factsOf` reads them. A kind with a run side, with declared effects or with volatile code is not pure here.
3591
+ */
3592
+ function pureCode(c, envelope, kind, typePath, name, quick) {
3593
+ if (kind.side === "run" || kind.effects !== void 0 && kind.effects.length > 0) return false;
3594
+ let answer;
3595
+ try {
3596
+ answer = c.machine.facts?.(typePath, name);
3597
+ } catch {
3598
+ return false;
3599
+ }
3600
+ const described = c.verb === "eval" && (envelope === void 0 || quick?.rung !== "own" || name === answerOf(c.machine.world, void 0, kind, c.verb)?.name);
3601
+ const pure = described ? answer?.pure ?? kind.pure : answer?.pure;
3602
+ const volatile = described ? answer?.volatile ?? kind.volatile : answer?.volatile;
3603
+ return pure === true && volatile !== true;
3604
+ }
3605
+ /**
3606
+ * This function gives the names that a document reads and does not bind, or `undefined` when the document can read
3607
+ * other roots. A reference reads the name of its path. Each other document reads the free names of its parts, less
3608
+ * the names that its scope rules give each part (STATIC.REFS).
3609
+ */
3610
+ function freeOf(doc, kind, slots, frees) {
3611
+ if (isRef(doc)) {
3612
+ const path = doc.value;
3613
+ if (path.length < 2 || path[0] !== "names" || !path.every((step, index) => index === 0 || isKey(step))) return void 0;
3614
+ return [String(path[1])];
3615
+ }
3616
+ let sees;
3617
+ let out;
3618
+ for (let index = 0; index < frees.length; index += 1) {
3619
+ const free = frees[index];
3620
+ if (free === void 0) return void 0;
3621
+ if (free.length === 0) continue;
3622
+ if (sees === void 0) sees = kind.scope === void 0 || kind.scope.length === 0 ? [] : scopesOf(kind.scope, doc.value, slots).sees;
3623
+ const bound = sees[index] ?? CLOSED;
3624
+ for (const name of free) {
3625
+ if (bound.includes(name)) continue;
3626
+ out ??= [];
3627
+ if (!out.includes(name)) out.push(name);
3628
+ }
3629
+ }
3630
+ return out ?? CLOSED;
3631
+ }
3632
+ /** This class is the runtime of a fold. It reads only the names that the folded part binds, and it causes no effect. */
3633
+ var Probe = class {
3634
+ machine;
3635
+ running = false;
3636
+ /** `true` after the part asked for something that a fold cannot give. */
3637
+ refused = false;
3638
+ /** The count of the names that the part read. */
3639
+ reads = 0;
3640
+ /**
3641
+ * The context of the folded part. Its roots `self`, `event` and `names` are traps: a direct read of a field
3642
+ * refuses the fold, as a resolution of these roots does. A copy of the record of the names reads no field.
3643
+ */
3644
+ root;
3645
+ constructor(machine) {
3646
+ this.machine = machine;
3647
+ const refuse = () => {
3648
+ this.refused = true;
3649
+ };
3650
+ const root = {
3651
+ self: trap(refuse, false),
3652
+ event: trap(refuse, false),
3653
+ names: trap(refuse, true),
3654
+ world: worldThing(machine.world),
3655
+ caps: NO_CAPS$2,
3656
+ [GRANT]: NO_CAPS$2
3657
+ };
3658
+ this.root = root;
3659
+ }
3660
+ resolve(ctx, path) {
3661
+ const name = path[1];
3662
+ if (path[0] === "names" && isKey(name) && Object.hasOwn(ctx.names, String(name))) {
3663
+ this.reads += 1;
3664
+ const found = resolve(this.machine, ctx, path, WITH_HOPS);
3665
+ if (found.hops.some((hop) => hop.by === "collapse" || isRef(hop.thing))) this.refused = true;
3666
+ return found;
3667
+ }
3668
+ this.refused = true;
3669
+ return {
3670
+ ok: false,
3671
+ code: "#REF!",
3672
+ reason: "A folded part reads only the names that it binds.",
3673
+ hops: []
3674
+ };
3675
+ }
3676
+ effect() {
3677
+ this.refused = true;
3678
+ return fail("#CAP!", "A folded part causes no effect.");
3679
+ }
3680
+ *runEffect() {
3681
+ return this.effect();
3682
+ }
3683
+ *all() {
3684
+ this.refused = true;
3685
+ return [];
3686
+ }
3687
+ keepsContext() {
3688
+ this.refused = true;
3689
+ }
3690
+ };
3691
+ /**
3692
+ * This function makes a trap for a root of the context of a fold. Each read of a field calls `refuse`. A trap of the
3693
+ * names gives no keys, thus a copy of the names reads no field.
3694
+ */
3695
+ function trap(refuse, copies) {
3696
+ const no = () => {
3697
+ refuse();
3698
+ };
3699
+ return new Proxy({}, {
3700
+ get: no,
3701
+ getOwnPropertyDescriptor: no,
3702
+ has: () => (refuse(), false),
3703
+ ownKeys: () => {
3704
+ if (!copies) refuse();
3705
+ return [];
3706
+ },
3707
+ getPrototypeOf: () => (refuse(), null),
3708
+ set: () => (refuse(), false),
3709
+ defineProperty: () => (refuse(), false),
3710
+ deleteProperty: () => (refuse(), false)
3711
+ });
3712
+ }
3713
+ /**
3714
+ * This function folds the code of a closed pure part. The part evaluates one time with the probe. Its result becomes
3715
+ * one deeply frozen copy, and the code gives that copy at each evaluation (PLAN.SHARED). A fold that the probe cancels
3716
+ * gives the code without free names, thus no parent tries the fold again.
3717
+ */
3718
+ function folded(c, done) {
3719
+ const probe = c.probe ??= new Probe(c.machine);
3720
+ probe.refused = false;
3721
+ probe.reads = 0;
3722
+ let constant;
3723
+ try {
3724
+ const result = done.code(probe.root, probe);
3725
+ if (!probe.refused && (result.ok || result.error.code !== "#DEPTH!")) constant = sharedCopy(result);
3726
+ } catch {
3727
+ constant = void 0;
3728
+ }
3729
+ if (constant === void 0) return {
3730
+ code: done.code,
3731
+ run: done.run
3732
+ };
3733
+ const value = constant;
3734
+ if (probe.reads === 0) return {
3735
+ code: () => value,
3736
+ run: void 0,
3737
+ free: CLOSED
3738
+ };
3739
+ const original = done.code;
3740
+ return {
3741
+ code: (ctx, rt) => rt instanceof Session && !rt.traced && !rt.recording ? value : original(ctx, rt),
3742
+ run: void 0,
3743
+ free: CLOSED
3744
+ };
3745
+ }
3746
+ /** The objects that a fold made. Each one is deeply frozen, thus a later fold uses it again and does not copy it. */
3747
+ const SHARED = /* @__PURE__ */ new WeakSet();
3748
+ /** The mark of a value that is not plain data. */
3749
+ const NOT_PLAIN = /* @__PURE__ */ Symbol("not plain");
3750
+ /**
3751
+ * This function gives a deeply frozen copy of plain data, or `undefined` for other values. Plain data is a primitive or
3752
+ * an array without holes and extra keys. It is also a record of enumerable data fields with the prototype of an object
3753
+ * or no prototype. The copy keeps cycles and shared objects. The objects of the host do not change.
3754
+ */
3755
+ function sharedCopy(value) {
3756
+ try {
3757
+ const out = copyPlain(value, /* @__PURE__ */ new Map());
3758
+ return out === NOT_PLAIN ? void 0 : out;
3759
+ } catch {
3760
+ return;
3761
+ }
3762
+ }
3763
+ /** This function copies one value for `sharedCopy`. The map holds the copy of each object that the copy saw. */
3764
+ function copyPlain(value, memo) {
3765
+ if (typeof value === "function") return NOT_PLAIN;
3766
+ if (typeof value !== "object" || value === null) return value;
3767
+ if (SHARED.has(value)) return value;
3768
+ const seen = memo.get(value);
3769
+ if (seen !== void 0) return seen;
3770
+ const proto = Object.getPrototypeOf(value);
3771
+ const keys = Reflect.ownKeys(value);
3772
+ let out;
3773
+ if (Array.isArray(value)) {
3774
+ if (proto !== Array.prototype || keys.length !== value.length + 1) return NOT_PLAIN;
3775
+ const list = [];
3776
+ memo.set(value, list);
3777
+ for (let index = 0; index < value.length; index += 1) {
3778
+ const field = Object.getOwnPropertyDescriptor(value, index);
3779
+ if (field === void 0 || !("value" in field) || field.enumerable !== true) return NOT_PLAIN;
3780
+ const item = copyPlain(field.value, memo);
3781
+ if (item === NOT_PLAIN) return NOT_PLAIN;
3782
+ list.push(item);
3783
+ }
3784
+ out = list;
3785
+ } else {
3786
+ if (proto !== Object.prototype && proto !== null) return NOT_PLAIN;
3787
+ const record = proto === null ? Object.create(null) : {};
3788
+ memo.set(value, record);
3789
+ for (const key of keys) {
3790
+ if (typeof key !== "string") return NOT_PLAIN;
3791
+ const field = Object.getOwnPropertyDescriptor(value, key);
3792
+ if (field === void 0 || !("value" in field) || field.enumerable !== true) return NOT_PLAIN;
3793
+ const item = copyPlain(field.value, memo);
3794
+ if (item === NOT_PLAIN) return NOT_PLAIN;
3795
+ if (key === "__proto__") Object.defineProperty(record, key, {
3796
+ value: item,
3797
+ enumerable: true,
3798
+ writable: true,
3799
+ configurable: true
3800
+ });
3801
+ else record[key] = item;
3802
+ }
3803
+ out = record;
3804
+ }
3805
+ Object.freeze(out);
3806
+ SHARED.add(out);
3807
+ return out;
3489
3808
  }
3490
3809
  /**
3491
3810
  * This function gives the code of a document: the code of its evaluator, with the place of each error and of each
@@ -3555,7 +3874,7 @@ function fillOf(split, doc) {
3555
3874
  return (items) => split.parts.length === 0 ? doc.value : split.fill(items);
3556
3875
  }
3557
3876
  function interpret(fn, input, fill) {
3558
- const { kind, typePath, doc, data, place } = input;
3877
+ const { kind, typePath, doc, data, place, machine } = input;
3559
3878
  const address = input.address === true ? { address: true } : {};
3560
3879
  const refill = input.fill;
3561
3880
  const compiled = input.parts;
@@ -3576,6 +3895,7 @@ function interpret(fn, input, fill) {
3576
3895
  parts,
3577
3896
  context: ctx,
3578
3897
  place,
3898
+ machine,
3579
3899
  ...address,
3580
3900
  resolve: (path, options) => rt.resolve(ctx, path, options),
3581
3901
  effect: (effectKind, payload) => rt.effect(ctx, effectKind, payload, place),
@@ -3584,7 +3904,7 @@ function interpret(fn, input, fill) {
3584
3904
  };
3585
3905
  }
3586
3906
  function interpretRun(fn, input, fill) {
3587
- const { kind, typePath, doc, data, place } = input;
3907
+ const { kind, typePath, doc, data, place, machine } = input;
3588
3908
  const refill = input.fill;
3589
3909
  const compiled = input.parts;
3590
3910
  const hasParts = compiled.length > 0;
@@ -3604,6 +3924,7 @@ function interpretRun(fn, input, fill) {
3604
3924
  parts,
3605
3925
  context: ctx,
3606
3926
  place,
3927
+ machine,
3607
3928
  resolve: (path, options) => rt.resolve(ctx, path, options),
3608
3929
  effect: (effectKind, payload) => rt.runEffect(ctx, effectKind, payload, place),
3609
3930
  all: (list, options) => rt.all(list.map((part) => () => part.evaluate()), options),
@@ -3648,12 +3969,14 @@ function prepare(machine, doc, options = {}) {
3648
3969
  error: "no-answer",
3649
3970
  steps: []
3650
3971
  };
3972
+ const traced = options.trace === true;
3651
3973
  const c = {
3652
3974
  machine,
3653
- traced: options.trace === true,
3975
+ traced,
3654
3976
  maxDepth: machine.maxDepth ?? 1e3,
3655
3977
  verb,
3656
- noAnswer
3978
+ noAnswer,
3979
+ fold: !traced && options.fold !== false
3657
3980
  };
3658
3981
  let root;
3659
3982
  try {
@@ -3751,8 +4074,8 @@ function record(s, result) {
3751
4074
  * tells where its parts are. The evaluator gets each part sealed: it can evaluate the part, and it cannot read its
3752
4075
  * value.
3753
4076
  *
3754
- * A failure gives an error value, and the function does not throw. An effect is recorded in its order, and the host
3755
- * does not do it. A mock can answer each effect at once (RUN.MOCK).
4077
+ * A failure gives an error value, and the function does not throw. The function records each effect in its order,
4078
+ * and the host does not do it. A mock can answer each effect at once (RUN.MOCK).
3756
4079
  *
3757
4080
  * @param machine - The world and the code of the evaluators.
3758
4081
  * @param doc - The document, as JSON.
@@ -4110,6 +4433,56 @@ const STD_EVALUATORS = {
4110
4433
  };
4111
4434
  /** The brand of a node of the decorated tree. Its value is the state that the kit reads. */
4112
4435
  const TREE_NODE = /* @__PURE__ */ Symbol.for("coeval.tree.node");
4436
+ /** The rungs of the ladder of an attribute, in their order (TREE.LADDER, D42). */
4437
+ const ATTRIBUTE_RUNGS = /* @__PURE__ */ Object.freeze([
4438
+ "own",
4439
+ "kind",
4440
+ "parent",
4441
+ "copy",
4442
+ "default"
4443
+ ]);
4444
+ /** The capabilities of an equation: none (CAP.PURE). */
4445
+ const NO_CAPS$1 = /* @__PURE__ */ Object.freeze([]);
4446
+ /** The names of an equation of `equations`, of a `unit` and of a `default`. */
4447
+ const NO_NAMES$1 = /* @__PURE__ */ Object.freeze({});
4448
+ /** The planners of equations, for each machine and each type of a bare equation (TREE.PLAN). */
4449
+ const equationPlanners = /* @__PURE__ */ new WeakMap();
4450
+ /**
4451
+ * This function gives the plan of an equation. Each equation compiles one time for each machine (PLAN.CACHE). The
4452
+ * plan of the document does not keep it (PLAN.LEAN).
4453
+ */
4454
+ function equationPlan(machine, of, term) {
4455
+ let byType = equationPlanners.get(machine);
4456
+ if (byType === void 0) {
4457
+ byType = /* @__PURE__ */ new Map();
4458
+ equationPlanners.set(machine, byType);
4459
+ }
4460
+ const key = of ?? "";
4461
+ let plans = byType.get(key);
4462
+ if (plans === void 0) {
4463
+ plans = planner(machine, of === void 0 ? {} : { declaredType: of });
4464
+ byType.set(key, plans);
4465
+ }
4466
+ return plans(term);
4467
+ }
4468
+ /** This function gives the own entry of a table of a tree contract, or `undefined`. */
4469
+ function entryOf(table, key) {
4470
+ return table !== void 0 && Object.hasOwn(table, key) ? table[key] : void 0;
4471
+ }
4472
+ const NO_CONTRACT = /* @__PURE__ */ Object.freeze({
4473
+ tree: void 0,
4474
+ of: void 0
4475
+ });
4476
+ /** This function finds the tree contract of the kind of a node in the world of the machine. */
4477
+ function contractOf$1(machine, typePath) {
4478
+ if (machine === void 0 || typePath.length === 0) return NO_CONTRACT;
4479
+ const found = lookupKind(machine.world, typePath);
4480
+ if (!found.ok || found.kind.tree === void 0) return NO_CONTRACT;
4481
+ return {
4482
+ tree: found.kind.tree,
4483
+ of: equationType(found.kind)
4484
+ };
4485
+ }
4113
4486
  const BUSY = /* @__PURE__ */ Object.freeze({ busy: true });
4114
4487
  /** The attributes in evaluation, in the order of their demands. An evaluation does not wait, thus one list serves. */
4115
4488
  const demands = [];
@@ -4177,28 +4550,92 @@ function plainOf(value, path) {
4177
4550
  }
4178
4551
  /**
4179
4552
  * This function makes a node of the decorated tree. A step `parent` gives the self of the context of the node, and a
4180
- * step `type` gives its type. A step with the key of a part reads that attribute. A failed attribute throws `Failure`
4181
- * with its own error, thus a reference to it gives that error.
4553
+ * step `type` gives its type. Another step reads an attribute through its ladder (TREE.LADDER). The rungs are a part of
4554
+ * the node, an equation of its kind and an equation `down` of the kind of its parent. A copy from the parent, then a
4555
+ * fold or a default, come last. A failed attribute throws `Failure` with its own error, thus a reference to it gives that error.
4182
4556
  */
4183
- function treeThing(parts, context, type, place, build) {
4557
+ function treeThing(input, build) {
4558
+ const { parts, context, kind: type, place, machine } = input;
4559
+ const { tree, of } = contractOf$1(machine, input.typePath);
4560
+ const above = stateOf(context.self);
4561
+ const up = above !== void 0 && above.build === build ? above : void 0;
4184
4562
  const cells = /* @__PURE__ */ new Map();
4563
+ /** The positions of the items of the list `children`, for the names of the children. */
4564
+ let positions;
4565
+ const fold = (key, declared) => {
4566
+ let acc = state.equation(declared.unit, NO_NAMES$1);
4567
+ if (!acc.ok) return acc;
4568
+ const children = read("children");
4569
+ if (children === void 0) return acc;
4570
+ if (!children.ok) return children;
4571
+ if (!Array.isArray(children.value)) return fail("#VALUE!", `The fold of ${key} needs a list in children.`);
4572
+ for (const item of children.value) {
4573
+ const child = stateOf(item);
4574
+ if (child === void 0 || child.build !== build) continue;
4575
+ const value = child.read(key);
4576
+ if (value === void 0) return fail("#N/A", `No rung gives ${attributeText(key, child.type, child.place)}.`);
4577
+ if (!value.ok) return value;
4578
+ acc = state.equation(declared.combine, {
4579
+ acc: acc.value,
4580
+ item: value.value
4581
+ });
4582
+ if (!acc.ok) return acc;
4583
+ }
4584
+ return acc;
4585
+ };
4586
+ /** This function visits the rungs of the ladder of an attribute in their order, until one answers. */
4587
+ const climb = (key) => {
4588
+ const part = parts.find((item) => item.key === key);
4589
+ if (part !== void 0) return {
4590
+ result: part.evaluate({
4591
+ ...context,
4592
+ self: node
4593
+ }),
4594
+ by: "own"
4595
+ };
4596
+ const equation = entryOf(tree?.equations, key);
4597
+ if (equation !== void 0) return {
4598
+ result: state.equation(equation, NO_NAMES$1),
4599
+ by: "kind"
4600
+ };
4601
+ const down = up === void 0 ? void 0 : entryOf(up.tree?.down, key);
4602
+ if (up !== void 0 && down !== void 0) {
4603
+ const names = up.childNames(node);
4604
+ return {
4605
+ result: names.ok ? up.equation(down, names.value) : names,
4606
+ by: "parent"
4607
+ };
4608
+ }
4609
+ const declared = entryOf(tree?.attributes, key);
4610
+ if (declared?.copy === true && up !== void 0) {
4611
+ const copied = up.read(key);
4612
+ if (copied !== void 0) return {
4613
+ result: copied,
4614
+ by: "copy"
4615
+ };
4616
+ }
4617
+ if (declared?.fold !== void 0) return {
4618
+ result: fold(key, declared.fold),
4619
+ by: "default"
4620
+ };
4621
+ if (declared?.default !== void 0) return {
4622
+ result: state.equation(declared.default, NO_NAMES$1),
4623
+ by: "default"
4624
+ };
4625
+ };
4185
4626
  const read = (key) => {
4186
4627
  const cell = cells.get(key);
4187
4628
  if (cell !== void 0) return cell.busy ? cycleAt(cells, key, attributeText(key, type, place)) : cell.result;
4188
- const part = parts.find((item) => item.key === key);
4189
- if (part === void 0) return void 0;
4629
+ if (tree === void 0 && up?.tree === void 0 && !parts.some((item) => item.key === key)) return void 0;
4190
4630
  cells.set(key, BUSY);
4191
4631
  demands.push({
4192
4632
  cells,
4193
4633
  key,
4194
4634
  text: attributeText(key, type, place)
4195
4635
  });
4196
- let result;
4636
+ let answer;
4197
4637
  try {
4198
- result = part.evaluate({
4199
- ...context,
4200
- self: node
4201
- });
4638
+ answer = climb(key);
4202
4639
  } catch (error) {
4203
4640
  cells.delete(key);
4204
4641
  throw error;
@@ -4207,14 +4644,60 @@ function treeThing(parts, context, type, place, build) {
4207
4644
  }
4208
4645
  cells.set(key, {
4209
4646
  busy: false,
4210
- result
4647
+ result: answer?.result,
4648
+ by: answer?.by
4211
4649
  });
4212
- return result;
4650
+ return answer?.result;
4213
4651
  };
4214
4652
  const state = {
4215
4653
  build,
4216
4654
  type,
4217
4655
  place,
4656
+ tree,
4657
+ read,
4658
+ equation(term, names) {
4659
+ if (machine === void 0) return fail("#NOEVAL", "The evaluation of an equation needs the machine.");
4660
+ return equationPlan(machine, of, term).evaluate({
4661
+ ...context,
4662
+ names,
4663
+ caps: NO_CAPS$1,
4664
+ self: node
4665
+ });
4666
+ },
4667
+ childNames(child) {
4668
+ const children = read("children");
4669
+ if (children !== void 0 && !children.ok) return children;
4670
+ const list = children !== void 0 && Array.isArray(children.value) ? children.value : [];
4671
+ if (positions?.list !== list) {
4672
+ const at = /* @__PURE__ */ new Map();
4673
+ list.forEach((item, index) => {
4674
+ if (!at.has(item)) at.set(item, index);
4675
+ });
4676
+ positions = {
4677
+ list,
4678
+ at
4679
+ };
4680
+ }
4681
+ const index = positions.at.get(child);
4682
+ return ok({
4683
+ child,
4684
+ index: index ?? null,
4685
+ prev: index === void 0 || index === 0 ? null : list[index - 1]
4686
+ });
4687
+ },
4688
+ trace(key) {
4689
+ const cell = cells.get(key);
4690
+ if (cell === void 0 || cell.busy) return void 0;
4691
+ const rungs = cell.by === void 0 ? ATTRIBUTE_RUNGS : ATTRIBUTE_RUNGS.slice(0, ATTRIBUTE_RUNGS.indexOf(cell.by) + 1);
4692
+ return cell.by === void 0 ? {
4693
+ attribute: key,
4694
+ rungs
4695
+ } : {
4696
+ attribute: key,
4697
+ rungs,
4698
+ by: cell.by
4699
+ };
4700
+ },
4218
4701
  json(path) {
4219
4702
  path.add(node);
4220
4703
  try {
@@ -4246,7 +4729,9 @@ function treeThing(parts, context, type, place, build) {
4246
4729
  return result.value;
4247
4730
  },
4248
4731
  has(key) {
4249
- return key === "parent" || key === "type" || parts.some((part) => part.key === String(key));
4732
+ if (key === "parent" || key === "type" || parts.some((part) => part.key === String(key))) return true;
4733
+ const cell = cells.get(String(key));
4734
+ return cell !== void 0 && !cell.busy && cell.result !== void 0;
4250
4735
  },
4251
4736
  toJson() {
4252
4737
  const result = state.json(/* @__PURE__ */ new Set());
@@ -4257,14 +4742,25 @@ function treeThing(parts, context, type, place, build) {
4257
4742
  return node;
4258
4743
  }
4259
4744
  /**
4745
+ * This function gives the record of the demand of an attribute of a node of the decorated tree (TREE.RUNGS). The
4746
+ * record holds the rungs that the demand visited, and the rung that answered. An explorer draws the ladder with it.
4747
+ *
4748
+ * @param node - The thing of a node.
4749
+ * @param attribute - The name of the attribute.
4750
+ * @returns The record, or `undefined` for a thing that is not a node or an attribute that no demand reached.
4751
+ */
4752
+ function attributeTrace(node, attribute) {
4753
+ return stateOf(node)?.trace(attribute);
4754
+ }
4755
+ /**
4260
4756
  * This function evaluates a node of the decorated tree. Inside an attribute of an open tree, the node gives its host
4261
4757
  * thing, and no attribute evaluates. Else the node is the root of a new tree, and it gives the JSON of the tree.
4262
4758
  */
4263
- function treeNode({ parts, context, kind, place }) {
4264
- const above = stateOf(context.self);
4265
- if (above !== void 0 && above.build.open) return ok(treeThing(parts, context, kind, place, above.build));
4759
+ function treeNode(input) {
4760
+ const above = stateOf(input.context.self);
4761
+ if (above !== void 0 && above.build.open) return ok(treeThing(input, above.build));
4266
4762
  const build = { open: true };
4267
- const root = treeThing(parts, context, kind, place, build);
4763
+ const root = treeThing(input, build);
4268
4764
  try {
4269
4765
  return stateOf(root).json(/* @__PURE__ */ new Set());
4270
4766
  } finally {
@@ -5007,96 +5503,27 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
5007
5503
  }
5008
5504
  //#endregion
5009
5505
  //#region src/static.ts
5010
- function valueAt(value, path) {
5011
- let here = value;
5012
- for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
5013
- else if (isRecord(here) && Object.hasOwn(here, String(key))) here = here[String(key)];
5014
- else return void 0;
5015
- return here;
5016
- }
5017
- function headerName(item) {
5018
- return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
5506
+ /** The names of a walk without names. A walk does not change a set at any time: it makes a new set to add names. */
5507
+ const NO_NAMES = /* @__PURE__ */ new Set();
5508
+ /** This function gives the options of a walk without the names of the host. */
5509
+ function withoutNames(options) {
5510
+ const { names: _host, ...rest } = options;
5511
+ return rest;
5019
5512
  }
5020
- function namesOf(source, value, covered) {
5021
- if ("fixed" in source) return source.fixed;
5022
- if ("keysAt" in source) {
5023
- const at = valueAt(value, source.keysAt);
5024
- return isRecord(at) ? Object.keys(at) : [];
5025
- }
5026
- if ("listAt" in source) {
5027
- const at = valueAt(value, source.listAt);
5028
- return Array.isArray(at) ? at.filter((item) => typeof item === "string") : [];
5029
- }
5030
- if ("textAt" in source) {
5031
- const at = valueAt(value, source.textAt);
5032
- if (typeof at === "string") return [at];
5033
- return source.otherwise === void 0 ? [] : [source.otherwise];
5513
+ /** This function gives the keys of a trail, from its start. It keeps the result in the trail. */
5514
+ function keysOf(trail) {
5515
+ if (trail === void 0) return [];
5516
+ if (trail.full !== void 0) return trail.full;
5517
+ const steps = [];
5518
+ let here = trail;
5519
+ while (here !== void 0 && here.full === void 0) {
5520
+ steps.push(here);
5521
+ here = here.up;
5034
5522
  }
5035
- return covered.map((slot) => headerName(slot.item)).filter((name) => name !== void 0);
5036
- }
5037
- /**
5038
- * This function gives the names that the scope rules of a kind give each part, and the names that only later parts
5039
- * see. `check` and `conforms` read the scope rules with it.
5040
- *
5041
- * @param rules - The scope rules of the kind.
5042
- * @param value - The value of the document.
5043
- * @param slots - The parts of the value, in order.
5044
- * @returns The names that each part sees, and the names that only the later parts see, by the index of the part.
5045
- */
5046
- function scopesOf(rules, value, slots) {
5047
- const sees = slots.map(() => []);
5048
- const later = slots.map(() => []);
5049
- for (const rule of rules ?? []) {
5050
- const covered = slots.map((slot, index) => ({
5051
- slot,
5052
- index
5053
- })).filter(({ slot }) => rule.in.some((pattern) => pathMatches(slot.path, pattern)));
5054
- if (rule.sequential !== true) {
5055
- const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
5056
- for (const { index } of covered) sees[index]?.push(...names);
5057
- continue;
5058
- }
5059
- if ("headers" in rule.names) {
5060
- covered.forEach(({ index }, position) => {
5061
- const before = covered.slice(0, position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
5062
- const after = covered.slice(position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
5063
- sees[index]?.push(...before);
5064
- later[index]?.push(...after);
5065
- });
5066
- continue;
5067
- }
5068
- const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
5069
- covered.forEach(({ index }, position) => {
5070
- if (position > 0) sees[index]?.push(...names);
5071
- else later[index]?.push(...names);
5072
- });
5073
- }
5074
- return {
5075
- sees,
5076
- later
5077
- };
5078
- }
5079
- /** The names of a walk without names. A walk does not change a set at any time: it makes a new set to add names. */
5080
- const NO_NAMES = /* @__PURE__ */ new Set();
5081
- /** This function gives the options of a walk without the names of the host. */
5082
- function withoutNames(options) {
5083
- const { names: _host, ...rest } = options;
5084
- return rest;
5085
- }
5086
- /** This function gives the keys of a trail, from its start. It keeps the result in the trail. */
5087
- function keysOf(trail) {
5088
- if (trail === void 0) return [];
5089
- if (trail.full !== void 0) return trail.full;
5090
- const steps = [];
5091
- let here = trail;
5092
- while (here !== void 0 && here.full === void 0) {
5093
- steps.push(here);
5094
- here = here.up;
5095
- }
5096
- const keys = here?.full === void 0 ? [] : [...here.full];
5097
- for (let index = steps.length - 1; index >= 0; index -= 1) for (const key of steps[index].keys) keys.push(key);
5098
- trail.full = keys;
5099
- return keys;
5523
+ const keys = here?.full === void 0 ? [] : [...here.full];
5524
+ for (let index = steps.length - 1; index >= 0; index -= 1) for (const key of steps[index].keys) keys.push(key);
5525
+ trail.full = keys;
5526
+ return keys;
5100
5527
  }
5101
5528
  /** A visit with its paths as trails. It makes the keys of a path only when a reader asks for them. */
5102
5529
  var Visit = class {
@@ -5420,11 +5847,81 @@ function typeCheck(machine, doc, options = {}) {
5420
5847
  places: pass.places
5421
5848
  };
5422
5849
  }
5850
+ /** The names that an equation of `down` sees (TREE.DOWN). */
5851
+ const DOWN_NAMES = /* @__PURE__ */ Object.freeze([
5852
+ "child",
5853
+ "index",
5854
+ "prev"
5855
+ ]);
5856
+ /** The names that the term `combine` of a fold sees (TREE.FOLD). */
5857
+ const FOLD_NAMES = /* @__PURE__ */ Object.freeze(["acc", "item"]);
5858
+ /**
5859
+ * This function gives each equation of the tree contract of a kind, with the names that it sees (D42). An equation of
5860
+ * `equations`, a `unit` and a `default` see no names.
5861
+ */
5862
+ function equationsOf(kind) {
5863
+ const tree = kind.tree;
5864
+ if (tree === void 0) return [];
5865
+ const out = [];
5866
+ for (const [name, term] of Object.entries(tree.equations ?? {})) out.push({
5867
+ label: `tree.equations.${name}`,
5868
+ term,
5869
+ names: []
5870
+ });
5871
+ for (const [name, term] of Object.entries(tree.down ?? {})) out.push({
5872
+ label: `tree.down.${name}`,
5873
+ term,
5874
+ names: DOWN_NAMES
5875
+ });
5876
+ for (const [name, declared] of Object.entries(tree.attributes ?? {})) {
5877
+ if (declared.fold !== void 0) {
5878
+ out.push({
5879
+ label: `tree.attributes.${name}.fold.unit`,
5880
+ term: declared.fold.unit,
5881
+ names: []
5882
+ });
5883
+ out.push({
5884
+ label: `tree.attributes.${name}.fold.combine`,
5885
+ term: declared.fold.combine,
5886
+ names: FOLD_NAMES
5887
+ });
5888
+ }
5889
+ if (declared.default !== void 0) out.push({
5890
+ label: `tree.attributes.${name}.default`,
5891
+ term: declared.default,
5892
+ names: []
5893
+ });
5894
+ }
5895
+ return out;
5896
+ }
5897
+ /**
5898
+ * This function checks the equations of the tree contract of a kind, each with the names of its rung (TREE.DOWN-NAMES).
5899
+ * An equation evaluates without capabilities, thus a check with capabilities gives it none. Each issue gets the place
5900
+ * of the document of the kind, and its reason names the equation.
5901
+ */
5902
+ function equationIssues(machine, kind, kindText, options, seen) {
5903
+ const of = equationType(kind);
5904
+ const out = [];
5905
+ for (const { label, term, names } of equationsOf(kind)) {
5906
+ const inner = {
5907
+ names,
5908
+ ...of === void 0 ? {} : { declaredType: of },
5909
+ ...options.caps === void 0 ? {} : { caps: [] }
5910
+ };
5911
+ for (const issue of checkAll(machine, term, inner, void 0, seen)) out.push({
5912
+ code: issue.code,
5913
+ place: [],
5914
+ reason: `In the equation ${label} of the kind ${kindText}: ${issue.reason}`
5915
+ });
5916
+ }
5917
+ return out;
5918
+ }
5423
5919
  /**
5424
5920
  * This function finds the issues of `check`. With a list of nodes, it also records each document that it visits for
5425
- * the pass of types. It marks each document with an issue.
5921
+ * the pass of types. It marks each document with an issue. The set `seen` holds the kinds whose equations the check
5922
+ * walked, thus it walks the equations of each kind one time.
5426
5923
  */
5427
- function checkAll(machine, doc, options, nodes) {
5924
+ function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()) {
5428
5925
  const issues = [];
5429
5926
  const verb = options.verb ?? "eval";
5430
5927
  const indices = nodes === void 0 ? void 0 : /* @__PURE__ */ new Map();
@@ -5476,6 +5973,14 @@ function checkAll(machine, doc, options, nodes) {
5476
5973
  });
5477
5974
  return "skip";
5478
5975
  }
5976
+ if (v.kind?.tree !== void 0 && !seen.has(v.kind)) {
5977
+ seen.add(v.kind);
5978
+ for (const issue of equationIssues(machine, v.kind, typeName(v.doc.type), options, seen)) push({
5979
+ ...issue,
5980
+ place: v.place,
5981
+ at: v.at
5982
+ });
5983
+ }
5479
5984
  const name = answer.evaluator;
5480
5985
  if (current !== void 0) current.evaluator = name;
5481
5986
  const runner = name !== void 0 && has(machine.runners, name);
@@ -5873,6 +6378,178 @@ function checkLatent(machine, declared, body, options = {}) {
5873
6378
  return issues;
5874
6379
  }
5875
6380
  //#endregion
6381
+ //#region src/codec.ts
6382
+ /** This function gives the codec of a domain, or `undefined` when the domain has no codec. */
6383
+ function codecOf(domain) {
6384
+ const codec = domain.codec;
6385
+ if (typeof codec !== "object" || codec === null) return void 0;
6386
+ const { encode, decode } = codec;
6387
+ return typeof encode === "function" && typeof decode === "function" ? codec : void 0;
6388
+ }
6389
+ /**
6390
+ * This function reads the value of an extension `ext.domain` (EXT.DOMAIN). The value is a record with only the text
6391
+ * `domain` and the JSON `data`. The codec of the named domain reads the data, and the result must be a member of the
6392
+ * domain.
6393
+ *
6394
+ * @param data - The value of the extension document.
6395
+ * @param domains - The domains of the machine.
6396
+ * @returns The member, `#NAME?` for a domain without a codec, or `#VALUE!` for data that the codec cannot read.
6397
+ */
6398
+ function decodeDomain(data, domains) {
6399
+ if (!isRecord(data) || typeof data["domain"] !== "string" || !Object.hasOwn(data, "data") || Object.keys(data).length !== 2) return fail("#VALUE!", "The value of ext.domain is a record with only the text domain and the data.");
6400
+ const name = data["domain"];
6401
+ const domain = domainOf(name, domains);
6402
+ if (domain === void 0) return fail("#NAME?", `The machine has no domain ${name}.`);
6403
+ const codec = codecOf(domain);
6404
+ if (codec === void 0) return fail("#NAME?", `The domain ${name} has no codec.`);
6405
+ let value;
6406
+ try {
6407
+ value = codec.decode(data["data"]);
6408
+ } catch (error) {
6409
+ return fail("#VALUE!", `The codec of the domain ${name} cannot read the data: ${describe(error)}`, { cause: error });
6410
+ }
6411
+ if (!member(value, name, domains)) return fail("#VALUE!", `The codec of the domain ${name} gives a value that is not a member of the domain.`);
6412
+ return ok(value);
6413
+ }
6414
+ /**
6415
+ * This function gives the static type of an extension `ext.domain`: the name of its domain when that domain has a
6416
+ * codec. A run then gives a member of the domain or an error, because `decodeDomain` tests the membership.
6417
+ *
6418
+ * @param data - The value of the extension document.
6419
+ * @param domains - The domains of the machine.
6420
+ * @returns The name of the domain, or `unknown`.
6421
+ */
6422
+ function domainTypeOf(data, domains) {
6423
+ if (!isRecord(data) || typeof data["domain"] !== "string") return "unknown";
6424
+ const domain = domainOf(data["domain"], domains);
6425
+ return domain !== void 0 && codecOf(domain) !== void 0 ? data["domain"] : "unknown";
6426
+ }
6427
+ /** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
6428
+ function setOwn$2(target, key, value) {
6429
+ if (key === "__proto__") Object.defineProperty(target, key, {
6430
+ value,
6431
+ enumerable: true,
6432
+ writable: true,
6433
+ configurable: true
6434
+ });
6435
+ else target[key] = value;
6436
+ }
6437
+ /**
6438
+ * This function tells if JSON writes a value exactly. Such a value is a finite number other than `-0`, a text, a truth
6439
+ * value, `null`, or a container of such values.
6440
+ */
6441
+ function isJson(value, encoder) {
6442
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
6443
+ if (typeof value === "number") return Number.isFinite(value) && !Object.is(value, -0);
6444
+ const list = Array.isArray(value);
6445
+ if (!list && !isRecord(value)) return false;
6446
+ const container = value;
6447
+ const known = encoder.json.get(container);
6448
+ if (known !== void 0) return known;
6449
+ encoder.json.set(container, false);
6450
+ let all = true;
6451
+ if (list) {
6452
+ const items = value;
6453
+ for (let index = 0; index < items.length && all; index += 1) all = isJson(items[index], encoder);
6454
+ } else {
6455
+ const record = value;
6456
+ for (const key of Object.keys(record)) if (!isJson(record[key], encoder)) {
6457
+ all = false;
6458
+ break;
6459
+ }
6460
+ }
6461
+ encoder.json.set(container, all);
6462
+ return all;
6463
+ }
6464
+ /** This function gives the text of a number that JSON cannot write, for `ext.number`. */
6465
+ function numberText(value) {
6466
+ if (Number.isNaN(value)) return "NaN";
6467
+ if (value === Number.POSITIVE_INFINITY) return "Infinity";
6468
+ if (value === Number.NEGATIVE_INFINITY) return "-Infinity";
6469
+ return "-0";
6470
+ }
6471
+ /** This function gives the term document of a value in one call of `encodeValue`. */
6472
+ function encodeTerm(value, encoder) {
6473
+ if (isJson(value, encoder)) return isEnvelope(value) ? {
6474
+ type: "lit",
6475
+ value
6476
+ } : value;
6477
+ if (value === void 0) return {
6478
+ type: ["ext", "undefined"],
6479
+ value: null
6480
+ };
6481
+ if (typeof value === "number") return {
6482
+ type: ["ext", "number"],
6483
+ value: numberText(value)
6484
+ };
6485
+ for (const [name, codec] of encoder.codecs) if (member(value, name, encoder.domains)) return {
6486
+ type: ["ext", "domain"],
6487
+ value: {
6488
+ domain: name,
6489
+ data: codec.encode(value)
6490
+ }
6491
+ };
6492
+ if (!Array.isArray(value) && !isRecord(value)) throw new TypeError(`encodeValue cannot write the value ${describe(value)}: no domain of the machine with a codec holds it.`);
6493
+ if (encoder.open.has(value)) throw new TypeError("encodeValue cannot write a value with a cycle.");
6494
+ encoder.open.add(value);
6495
+ let out;
6496
+ if (Array.isArray(value)) out = {
6497
+ type: "list",
6498
+ value: Array.from(value, (item) => encodeTerm(item, encoder))
6499
+ };
6500
+ else {
6501
+ const fields = {};
6502
+ const record = value;
6503
+ for (const key of Object.keys(record)) setOwn$2(fields, key, encodeTerm(record[key], encoder));
6504
+ out = {
6505
+ type: "record",
6506
+ value: fields
6507
+ };
6508
+ }
6509
+ encoder.open.delete(value);
6510
+ return out;
6511
+ }
6512
+ /**
6513
+ * This function writes a host value as a term document of the formula kit (EXT.ENCODE, D40). Thus the same value has
6514
+ * the same document in each language (D12).
6515
+ *
6516
+ * - A value that JSON writes exactly stays as it is. A literal with the shape of an envelope goes into `lit`.
6517
+ * - `NaN`, an infinity and `-0` become `ext.number`, and `undefined` becomes `ext.undefined`.
6518
+ * - A member of a domain with a codec becomes `ext.domain`. The domains go in the order of their names.
6519
+ * - A list or a plain record with such a value becomes the construct `list` or `record`.
6520
+ *
6521
+ * @param machine - The machine, or only its domains.
6522
+ * @param value - The host value.
6523
+ * @returns The document. `decodeValue` gives the value again (EXT.ROUNDTRIP).
6524
+ * @throws {TypeError} The value has a cycle, or it is not JSON and no domain with a codec holds it.
6525
+ */
6526
+ function encodeValue(machine, value) {
6527
+ const domains = machine.domains;
6528
+ const codecs = [];
6529
+ if (domains !== void 0) for (const name of Object.keys(domains).sort()) {
6530
+ const domain = domainOf(name, domains);
6531
+ const codec = domain === void 0 ? void 0 : codecOf(domain);
6532
+ if (codec !== void 0) codecs.push([name, codec]);
6533
+ }
6534
+ return encodeTerm(value, {
6535
+ domains,
6536
+ codecs,
6537
+ json: /* @__PURE__ */ new WeakMap(),
6538
+ open: /* @__PURE__ */ new Set()
6539
+ });
6540
+ }
6541
+ /**
6542
+ * This function reads a document of `encodeValue` again: it evaluates the document as a term, in an empty context.
6543
+ * A bare root value is a literal.
6544
+ *
6545
+ * @param machine - A machine of the formula kit, with the domains of the document.
6546
+ * @param doc - The document.
6547
+ * @returns The value, or the error of the evaluation.
6548
+ */
6549
+ function decodeValue(machine, doc) {
6550
+ return prepare(machine, doc, { declaredType: "lit" }).evaluate(makeContext());
6551
+ }
6552
+ //#endregion
5876
6553
  //#region src/formula.ts
5877
6554
  /** The mark of a field that the profile leaves out of a record. */
5878
6555
  const SKIPPED = /* @__PURE__ */ Symbol("skipped");
@@ -5893,7 +6570,10 @@ const CLOSURE$2 = /* @__PURE__ */ Symbol.for("coeval.closure");
5893
6570
  function isClosure(value) {
5894
6571
  return typeof value === "function" && value[CLOSURE$2] !== void 0;
5895
6572
  }
5896
- /** The standard extensions: the values that JSON cannot write. */
6573
+ /**
6574
+ * The standard extensions: the values that JSON cannot write. `ext.domain` reads a member of a domain through the
6575
+ * codec of the domain (EXT.DOMAIN, D40).
6576
+ */
5897
6577
  const STD_EXT = {
5898
6578
  undefined: () => ok(void 0),
5899
6579
  number: (data) => {
@@ -5902,7 +6582,8 @@ const STD_EXT = {
5902
6582
  if (data === "-Infinity") return ok(Number.NEGATIVE_INFINITY);
5903
6583
  if (data === "-0") return ok(-0);
5904
6584
  return fail("#VALUE!", "The value of ext.number is NaN, Infinity, -Infinity or -0.");
5905
- }
6585
+ },
6586
+ domain: (data, _context, domains) => decodeDomain(data, domains)
5906
6587
  };
5907
6588
  /** The truth of a value in the rules of JavaScript: `0`, `""`, `null`, `undefined` and `NaN` are false. */
5908
6589
  function jsTruthy(value) {
@@ -6369,8 +7050,9 @@ function formulaTypes(profile) {
6369
7050
  },
6370
7051
  "formula.ext": { synth: (input) => {
6371
7052
  const name = nameOf(input);
6372
- const own = profile.ext !== void 0 && Object.hasOwn(profile.ext, name);
6373
- return name === "number" && !own ? "number" : "unknown";
7053
+ if (profile.ext !== void 0 && Object.hasOwn(profile.ext, name)) return "unknown";
7054
+ if (name === "number") return "number";
7055
+ return name === "domain" ? domainTypeOf(input.doc.value, input.machine.domains) : "unknown";
6374
7056
  } }
6375
7057
  };
6376
7058
  }
@@ -6688,7 +7370,7 @@ function formulaCode(profile) {
6688
7370
  }
6689
7371
  };
6690
7372
  }),
6691
- "formula.ext": compiled(({ typePath, doc }) => {
7373
+ "formula.ext": compiled(({ typePath, doc, machine }) => {
6692
7374
  const name = typePath.slice(1).join(".");
6693
7375
  const handler = (profile.ext !== void 0 && Object.hasOwn(profile.ext, name) ? profile.ext[name] : void 0) ?? (Object.hasOwn(STD_EXT, name) ? STD_EXT[name] : void 0);
6694
7376
  if (handler === void 0) {
@@ -6697,7 +7379,7 @@ function formulaCode(profile) {
6697
7379
  }
6698
7380
  return (ctx) => {
6699
7381
  try {
6700
- return handler(doc.value, ctx);
7382
+ return handler(doc.value, ctx, machine.domains);
6701
7383
  } catch (error) {
6702
7384
  return thrown(error, `the extension ${name}`);
6703
7385
  }
@@ -6798,6 +7480,835 @@ function formulaMachine(profile = {}, more = {}) {
6798
7480
  }, more);
6799
7481
  }
6800
7482
  //#endregion
7483
+ //#region src/syntax.ts
7484
+ /**
7485
+ * The standard syntax of the formula kit. It gives the site and the playground a text form. The operators are
7486
+ * `or`, `and`, `not`, the comparisons, `+ - * / %`, a minus sign and `^`, from the loosest to the tightest. A call
7487
+ * `name(args)` applies the operation `ops.name`. `if(test, then, else)` and `list(items)` make the constructs.
7488
+ */
7489
+ const STD_SYNTAX = /* @__PURE__ */ Object.freeze({
7490
+ operators: [
7491
+ {
7492
+ symbol: "or",
7493
+ fixity: "infix",
7494
+ prec: 1,
7495
+ assoc: "flat",
7496
+ kind: "or"
7497
+ },
7498
+ {
7499
+ symbol: "and",
7500
+ fixity: "infix",
7501
+ prec: 2,
7502
+ assoc: "flat",
7503
+ kind: "and"
7504
+ },
7505
+ {
7506
+ symbol: "not",
7507
+ fixity: "prefix",
7508
+ prec: 3,
7509
+ kind: "ops.not"
7510
+ },
7511
+ {
7512
+ symbol: "==",
7513
+ fixity: "infix",
7514
+ prec: 4,
7515
+ assoc: "none",
7516
+ kind: "ops.eq"
7517
+ },
7518
+ {
7519
+ symbol: "!=",
7520
+ fixity: "infix",
7521
+ prec: 4,
7522
+ assoc: "none",
7523
+ kind: "ops.ne"
7524
+ },
7525
+ {
7526
+ symbol: "<",
7527
+ fixity: "infix",
7528
+ prec: 4,
7529
+ assoc: "none",
7530
+ kind: "ops.lt"
7531
+ },
7532
+ {
7533
+ symbol: "<=",
7534
+ fixity: "infix",
7535
+ prec: 4,
7536
+ assoc: "none",
7537
+ kind: "ops.le"
7538
+ },
7539
+ {
7540
+ symbol: ">",
7541
+ fixity: "infix",
7542
+ prec: 4,
7543
+ assoc: "none",
7544
+ kind: "ops.gt"
7545
+ },
7546
+ {
7547
+ symbol: ">=",
7548
+ fixity: "infix",
7549
+ prec: 4,
7550
+ assoc: "none",
7551
+ kind: "ops.ge"
7552
+ },
7553
+ {
7554
+ symbol: "+",
7555
+ fixity: "infix",
7556
+ prec: 5,
7557
+ kind: "ops.add"
7558
+ },
7559
+ {
7560
+ symbol: "-",
7561
+ fixity: "infix",
7562
+ prec: 5,
7563
+ kind: "ops.sub"
7564
+ },
7565
+ {
7566
+ symbol: "*",
7567
+ fixity: "infix",
7568
+ prec: 6,
7569
+ kind: "ops.mul"
7570
+ },
7571
+ {
7572
+ symbol: "/",
7573
+ fixity: "infix",
7574
+ prec: 6,
7575
+ kind: "ops.div"
7576
+ },
7577
+ {
7578
+ symbol: "%",
7579
+ fixity: "infix",
7580
+ prec: 6,
7581
+ kind: "ops.mod"
7582
+ },
7583
+ {
7584
+ symbol: "-",
7585
+ fixity: "prefix",
7586
+ prec: 7,
7587
+ kind: "ops.neg"
7588
+ },
7589
+ {
7590
+ symbol: "^",
7591
+ fixity: "infix",
7592
+ prec: 8,
7593
+ assoc: "right",
7594
+ kind: "ops.pow"
7595
+ }
7596
+ ],
7597
+ literals: { words: {
7598
+ true: true,
7599
+ false: false,
7600
+ null: null,
7601
+ undefined: void 0,
7602
+ NaN: NaN,
7603
+ Infinity: Infinity
7604
+ } },
7605
+ calls: { forms: [{
7606
+ name: "if",
7607
+ kind: "if",
7608
+ fields: [
7609
+ "test",
7610
+ "then",
7611
+ "else"
7612
+ ],
7613
+ min: 2
7614
+ }, {
7615
+ name: "list",
7616
+ kind: "list"
7617
+ }] }
7618
+ });
7619
+ const NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
7620
+ const NAME_AT = /[A-Za-z_][A-Za-z0-9_]*/y;
7621
+ const DIGITS_AT = /[0-9]+/y;
7622
+ const NUMBER_AT = /(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
7623
+ const SYMBOL = /^[^\sA-Za-z0-9_"'`()$.]+$/;
7624
+ const DEFAULT_WORDS = {
7625
+ true: true,
7626
+ false: false,
7627
+ null: null
7628
+ };
7629
+ const DEFAULT_ROOTS = [
7630
+ "self",
7631
+ "world",
7632
+ "event",
7633
+ "caps"
7634
+ ];
7635
+ const compiledProfiles = /* @__PURE__ */ new WeakMap();
7636
+ function typeOfKind(kind) {
7637
+ const keys = kind.split(".");
7638
+ if (kind === "" || keys.some((key) => key === "")) throw new TypeError(`The kind "${kind}" of a syntax profile has an empty key.`);
7639
+ return {
7640
+ type: keys.length === 1 ? keys[0] : keys,
7641
+ key: JSON.stringify(keys)
7642
+ };
7643
+ }
7644
+ function addTo(map, key, value) {
7645
+ const list = map.get(key);
7646
+ if (list === void 0) map.set(key, [value]);
7647
+ else list.push(value);
7648
+ }
7649
+ function compileOps(profile, separator) {
7650
+ const prefix = /* @__PURE__ */ new Map();
7651
+ const binary = /* @__PURE__ */ new Map();
7652
+ const byKind = /* @__PURE__ */ new Map();
7653
+ const assocAt = /* @__PURE__ */ new Map();
7654
+ const opWords = /* @__PURE__ */ new Set();
7655
+ for (const given of profile.operators ?? []) {
7656
+ const word = NAME.test(given.symbol);
7657
+ if (!word && (!SYMBOL.test(given.symbol) || given.symbol.includes(separator))) throw new TypeError(`The operator "${given.symbol}" is not a plain name or a group of symbols.`);
7658
+ if (!Number.isFinite(given.prec)) throw new TypeError(`The operator "${given.symbol}" has no finite precedence.`);
7659
+ const { type, key } = typeOfKind(given.kind);
7660
+ const op = {
7661
+ symbol: given.symbol,
7662
+ fixity: given.fixity,
7663
+ prec: given.prec,
7664
+ assoc: given.assoc ?? "left",
7665
+ type,
7666
+ kindKey: key,
7667
+ word
7668
+ };
7669
+ const table = op.fixity === "prefix" ? prefix : binary;
7670
+ if (table.has(op.symbol)) throw new TypeError(`The operator "${op.symbol}" has two entries of the same place.`);
7671
+ table.set(op.symbol, op);
7672
+ if (op.fixity === "infix") {
7673
+ const assoc = assocAt.get(op.prec);
7674
+ if (assoc !== void 0 && assoc !== op.assoc) throw new TypeError(`The infix operators of the precedence ${String(op.prec)} have different groupings.`);
7675
+ assocAt.set(op.prec, op.assoc);
7676
+ }
7677
+ if (word) opWords.add(op.symbol);
7678
+ addTo(byKind, key, op);
7679
+ }
7680
+ const longestFirst = (table) => [...table.keys()].filter((symbol) => !NAME.test(symbol)).sort((a, b) => b.length - a.length);
7681
+ return {
7682
+ prefix,
7683
+ binary,
7684
+ prefixSymbols: longestFirst(prefix),
7685
+ binarySymbols: longestFirst(binary),
7686
+ byKind,
7687
+ opWords
7688
+ };
7689
+ }
7690
+ function compileProfile(profile) {
7691
+ const cached = compiledProfiles.get(profile);
7692
+ if (cached !== void 0) return cached;
7693
+ const calls = profile.calls ?? {};
7694
+ const separator = calls.separator ?? ",";
7695
+ const ops = compileOps(profile, separator);
7696
+ const literals = profile.literals ?? {};
7697
+ const strings = literals.strings === false ? void 0 : literals.strings ?? {};
7698
+ const words = new Map(Object.entries(literals.words ?? DEFAULT_WORDS));
7699
+ const refs = profile.refs ?? {};
7700
+ const roots = new Set(refs.roots ?? DEFAULT_ROOTS);
7701
+ const forms = /* @__PURE__ */ new Map();
7702
+ const formsByKind = /* @__PURE__ */ new Map();
7703
+ for (const given of calls.forms ?? []) {
7704
+ if (!NAME.test(given.name)) throw new TypeError(`The call form "${given.name}" is not a plain name.`);
7705
+ const { type, key } = typeOfKind(given.kind);
7706
+ const form = {
7707
+ name: given.name,
7708
+ type,
7709
+ fields: given.fields,
7710
+ min: given.min ?? given.fields?.length ?? 0
7711
+ };
7712
+ forms.set(form.name, form);
7713
+ addTo(formsByKind, key, form);
7714
+ }
7715
+ const compiled = {
7716
+ ...ops,
7717
+ numbers: literals.numbers ?? true,
7718
+ signed: literals.signed ?? true,
7719
+ quote: strings === void 0 ? void 0 : strings.quote ?? "\"",
7720
+ doubled: strings !== void 0 && strings.escape === "double",
7721
+ words,
7722
+ bare: refs.bare ?? "names",
7723
+ roots,
7724
+ fields: refs.fields ?? true,
7725
+ patterns: (refs.patterns ?? []).map((p) => {
7726
+ const flags = p.pattern.flags.replace(/[gy]/g, "");
7727
+ return {
7728
+ sticky: new RegExp(p.pattern.source, `${flags}y`),
7729
+ whole: new RegExp(`^(?:${p.pattern.source})$`, flags),
7730
+ read: p.read,
7731
+ write: p.write
7732
+ };
7733
+ }),
7734
+ ops: calls.ops === void 0 || calls.ops === true ? true : new Set(calls.ops === false ? [] : calls.ops),
7735
+ forms,
7736
+ formsByKind,
7737
+ separator,
7738
+ reserved: /* @__PURE__ */ new Set([
7739
+ ...words.keys(),
7740
+ ...ops.opWords,
7741
+ ...roots
7742
+ ]),
7743
+ maxDepth: profile.maxDepth ?? 256
7744
+ };
7745
+ compiledProfiles.set(profile, compiled);
7746
+ return compiled;
7747
+ }
7748
+ /** The stop of a parse. The parser throws it, and `parse` gives its issue. */
7749
+ var Stop = class {
7750
+ issue;
7751
+ constructor(issue) {
7752
+ this.issue = issue;
7753
+ }
7754
+ };
7755
+ function literalDoc(value) {
7756
+ return encodeValue({}, value);
7757
+ }
7758
+ function opDoc(op, value) {
7759
+ return {
7760
+ type: op.type,
7761
+ value
7762
+ };
7763
+ }
7764
+ const ESCAPES = {
7765
+ "\"": "\"",
7766
+ "'": "'",
7767
+ "\\": "\\",
7768
+ "/": "/",
7769
+ b: "\b",
7770
+ f: "\f",
7771
+ n: "\n",
7772
+ r: "\r",
7773
+ t: " "
7774
+ };
7775
+ var Parser = class {
7776
+ syn;
7777
+ text;
7778
+ pos = 0;
7779
+ depth = 0;
7780
+ constructor(syn, text) {
7781
+ this.syn = syn;
7782
+ this.text = text;
7783
+ }
7784
+ parse() {
7785
+ this.skip();
7786
+ if (this.pos >= this.text.length) this.stop("The text is empty.", 0, 0);
7787
+ const doc = this.expr(0);
7788
+ this.skip();
7789
+ if (this.pos < this.text.length) this.stop("The text continues after the expression.", this.pos, this.tokenLength());
7790
+ return doc;
7791
+ }
7792
+ position() {
7793
+ return this.pos;
7794
+ }
7795
+ stop(message, offset, length) {
7796
+ throw new Stop({
7797
+ offset,
7798
+ length,
7799
+ message
7800
+ });
7801
+ }
7802
+ skip() {
7803
+ while (this.pos < this.text.length && /\s/.test(this.text[this.pos])) this.pos += 1;
7804
+ }
7805
+ at(pattern, pos = this.pos) {
7806
+ pattern.lastIndex = pos;
7807
+ return pattern.exec(this.text)?.[0];
7808
+ }
7809
+ tokenLength() {
7810
+ return (this.at(NAME_AT) ?? this.at(DIGITS_AT) ?? "x").length;
7811
+ }
7812
+ /** This method reads an expression by precedence climbing. It stops at an operator below `min`. */
7813
+ expr(min) {
7814
+ const start = this.pos;
7815
+ this.depth += 1;
7816
+ if (this.depth > this.syn.maxDepth) this.stop(`The text is deeper than ${String(this.syn.maxDepth)} levels.`, start, 0);
7817
+ let left = this.operand();
7818
+ for (;;) {
7819
+ this.skip();
7820
+ const found = this.operatorAt();
7821
+ if (found === void 0 || found.op.prec < min) break;
7822
+ const op = found.op;
7823
+ this.pos += found.length;
7824
+ if (op.fixity === "postfix") {
7825
+ left = opDoc(op, [left]);
7826
+ continue;
7827
+ }
7828
+ if (op.assoc === "flat") {
7829
+ const terms = [left, this.expr(op.prec + 1)];
7830
+ for (;;) {
7831
+ this.skip();
7832
+ const next = this.operatorAt();
7833
+ if (next === void 0 || next.op.fixity !== "infix" || next.op.kindKey !== op.kindKey) break;
7834
+ this.pos += next.length;
7835
+ terms.push(this.expr(op.prec + 1));
7836
+ }
7837
+ left = opDoc(op, terms);
7838
+ continue;
7839
+ }
7840
+ left = opDoc(op, [left, this.expr(op.assoc === "right" ? op.prec : op.prec + 1)]);
7841
+ if (op.assoc === "none") {
7842
+ this.skip();
7843
+ const next = this.operatorAt();
7844
+ if (next !== void 0 && next.op.fixity === "infix" && next.op.prec === op.prec) this.stop(`The operator ${next.op.symbol} does not chain after ${op.symbol}. Add parentheses.`, this.pos, next.length);
7845
+ }
7846
+ }
7847
+ this.depth -= 1;
7848
+ return left;
7849
+ }
7850
+ /** This method finds an infix or a postfix operator at the position. */
7851
+ operatorAt() {
7852
+ const name = this.at(NAME_AT);
7853
+ if (name !== void 0) {
7854
+ const op = this.syn.binary.get(name);
7855
+ return op !== void 0 && op.word ? {
7856
+ op,
7857
+ length: name.length
7858
+ } : void 0;
7859
+ }
7860
+ for (const symbol of this.syn.binarySymbols) if (this.text.startsWith(symbol, this.pos)) return {
7861
+ op: this.syn.binary.get(symbol),
7862
+ length: symbol.length
7863
+ };
7864
+ }
7865
+ operand() {
7866
+ this.skip();
7867
+ const start = this.pos;
7868
+ const c = this.text[start];
7869
+ if (c === void 0) return this.stop("A term is missing at the end of the text.", start, 0);
7870
+ for (const pattern of this.syn.patterns) {
7871
+ const match = this.at(pattern.sticky);
7872
+ if (match !== void 0 && match !== "" && !/[A-Za-z0-9_$(]/.test(this.text[start + match.length] ?? "")) {
7873
+ this.pos += match.length;
7874
+ return {
7875
+ type: "ref",
7876
+ value: pattern.read(match)
7877
+ };
7878
+ }
7879
+ }
7880
+ if (/[0-9]/.test(c)) return this.number(false);
7881
+ if (c === "-" && this.syn.signed && /[0-9]/.test(this.text[start + 1] ?? "")) return this.number(true);
7882
+ if (c === this.syn.quote) return this.string();
7883
+ if (c === "(") return this.group();
7884
+ if (c === "`" || /[A-Za-z_]/.test(c)) return this.named();
7885
+ for (const symbol of this.syn.prefixSymbols) if (this.text.startsWith(symbol, start)) {
7886
+ this.pos += symbol.length;
7887
+ const op = this.syn.prefix.get(symbol);
7888
+ return opDoc(op, [this.expr(op.prec + 1)]);
7889
+ }
7890
+ if (c === ")" || this.text.startsWith(this.syn.separator, start)) return this.stop("A term is missing.", start, 0);
7891
+ return this.stop(`The text "${c}" cannot start a term.`, start, 1);
7892
+ }
7893
+ number(negative) {
7894
+ const start = this.pos;
7895
+ if (!this.syn.numbers) this.stop("This syntax has no numbers.", start, this.tokenLength());
7896
+ if (negative) this.pos += 1;
7897
+ const digits = this.at(NUMBER_AT);
7898
+ this.pos += digits.length;
7899
+ const value = Number(digits);
7900
+ return literalDoc(negative ? -value : value);
7901
+ }
7902
+ string() {
7903
+ const start = this.pos;
7904
+ const quote = this.syn.quote;
7905
+ let out = "";
7906
+ this.pos += 1;
7907
+ for (;;) {
7908
+ const c = this.text[this.pos];
7909
+ if (c === void 0) return this.stop("A closing quote is missing.", start, this.text.length - start);
7910
+ if (c === quote) {
7911
+ if (this.syn.doubled && this.text[this.pos + 1] === quote) {
7912
+ out += quote;
7913
+ this.pos += 2;
7914
+ continue;
7915
+ }
7916
+ this.pos += 1;
7917
+ return literalDoc(out);
7918
+ }
7919
+ if (c === "\\" && !this.syn.doubled) {
7920
+ out += this.escape();
7921
+ continue;
7922
+ }
7923
+ out += c;
7924
+ this.pos += 1;
7925
+ }
7926
+ }
7927
+ escape() {
7928
+ const start = this.pos;
7929
+ const c = this.text[start + 1] ?? "";
7930
+ if (c === "u") {
7931
+ const hex = this.text.slice(start + 2, start + 6);
7932
+ if (!/^[0-9A-Fa-f]{4}$/.test(hex)) return this.stop("The escape \\u needs four hex digits.", start, 2);
7933
+ this.pos += 6;
7934
+ return String.fromCharCode(Number.parseInt(hex, 16));
7935
+ }
7936
+ const out = Object.hasOwn(ESCAPES, c) ? ESCAPES[c] : void 0;
7937
+ if (out === void 0) return this.stop(`The escape \\${c} is not valid.`, start, 2);
7938
+ this.pos += 2;
7939
+ return out;
7940
+ }
7941
+ group() {
7942
+ const open = this.pos;
7943
+ this.pos += 1;
7944
+ const inner = this.expr(0);
7945
+ this.skip();
7946
+ if (this.text[this.pos] !== ")") {
7947
+ if (this.pos >= this.text.length) this.stop("A closing parenthesis is missing.", open, 1);
7948
+ this.stop("A closing parenthesis is missing.", this.pos, this.tokenLength());
7949
+ }
7950
+ this.pos += 1;
7951
+ return inner;
7952
+ }
7953
+ /** This method reads a name in backticks. Two backticks in the name are one backtick. */
7954
+ quoted() {
7955
+ const start = this.pos;
7956
+ let out = "";
7957
+ this.pos += 1;
7958
+ for (;;) {
7959
+ const c = this.text[this.pos];
7960
+ if (c === void 0) return this.stop("A closing backtick is missing.", start, this.text.length - start);
7961
+ if (c === "`") {
7962
+ if (this.text[this.pos + 1] !== "`") {
7963
+ this.pos += 1;
7964
+ return out;
7965
+ }
7966
+ this.pos += 1;
7967
+ }
7968
+ out += c;
7969
+ this.pos += 1;
7970
+ }
7971
+ }
7972
+ /** This method reads a name: a word operator, a call, a literal word or a reference. */
7973
+ named() {
7974
+ const start = this.pos;
7975
+ const plain = this.text[start] !== "`";
7976
+ const first = plain ? this.at(NAME_AT) : this.quoted();
7977
+ if (plain) {
7978
+ this.pos += first.length;
7979
+ const prefix = this.syn.prefix.get(first);
7980
+ if (prefix !== void 0 && prefix.word) return opDoc(prefix, [this.expr(prefix.prec + 1)]);
7981
+ if (this.syn.binary.get(first)?.word === true) this.stop(`A term is missing before ${first}.`, start, first.length);
7982
+ }
7983
+ const path = [first];
7984
+ let allPlain = plain;
7985
+ for (;;) {
7986
+ const back = this.pos;
7987
+ this.skip();
7988
+ if (!this.syn.fields || this.text[this.pos] !== ".") {
7989
+ this.pos = back;
7990
+ break;
7991
+ }
7992
+ this.pos += 1;
7993
+ this.skip();
7994
+ if (this.text[this.pos] === "`") {
7995
+ path.push(this.quoted());
7996
+ allPlain = false;
7997
+ continue;
7998
+ }
7999
+ const name = this.at(NAME_AT);
8000
+ const digits = name === void 0 ? this.at(DIGITS_AT) : void 0;
8001
+ if (name === void 0 && digits === void 0) this.stop("A name is missing after the dot.", this.pos, 0);
8002
+ this.pos += (name ?? digits).length;
8003
+ path.push(name ?? Number(digits));
8004
+ if (name === void 0) allPlain = false;
8005
+ }
8006
+ const back = this.pos;
8007
+ this.skip();
8008
+ if (this.text[this.pos] === "(") {
8009
+ if (!allPlain) this.stop("The name of a call is a plain name.", start, back - start);
8010
+ return this.call(path.join("."), start, back - start);
8011
+ }
8012
+ this.pos = back;
8013
+ if (plain && path.length === 1 && this.syn.words.has(first)) return literalDoc(this.syn.words.get(first));
8014
+ return {
8015
+ type: "ref",
8016
+ value: plain && this.syn.roots.has(first) ? path : [this.syn.bare, ...path]
8017
+ };
8018
+ }
8019
+ call(name, start, nameLength) {
8020
+ const open = this.pos;
8021
+ const args = [];
8022
+ this.pos += 1;
8023
+ this.skip();
8024
+ if (this.text[this.pos] === ")") this.pos += 1;
8025
+ else for (;;) {
8026
+ args.push(this.expr(0));
8027
+ this.skip();
8028
+ if (this.text.startsWith(this.syn.separator, this.pos)) {
8029
+ this.pos += this.syn.separator.length;
8030
+ continue;
8031
+ }
8032
+ if (this.text[this.pos] === ")") {
8033
+ this.pos += 1;
8034
+ break;
8035
+ }
8036
+ if (this.pos >= this.text.length) this.stop("A closing parenthesis is missing.", open, 1);
8037
+ this.stop(`A "${this.syn.separator}" or a closing parenthesis is missing.`, this.pos, this.tokenLength());
8038
+ }
8039
+ const form = this.syn.forms.get(name);
8040
+ if (form !== void 0) {
8041
+ const most = form.fields?.length ?? Number.POSITIVE_INFINITY;
8042
+ if (args.length < form.min || args.length > most) {
8043
+ const range = most === form.min ? String(most) : most === Number.POSITIVE_INFINITY ? `${String(form.min)} or more` : `${String(form.min)} to ${String(most)}`;
8044
+ this.stop(`The form ${name} takes ${range} arguments.`, start, this.pos - start);
8045
+ }
8046
+ if (form.fields === void 0) return opDoc(form, args);
8047
+ const value = {};
8048
+ args.forEach((arg, index) => {
8049
+ value[form.fields?.[index]] = arg;
8050
+ });
8051
+ return opDoc(form, value);
8052
+ }
8053
+ if (this.syn.ops !== true && !this.syn.ops.has(name)) this.stop(`This syntax has no function ${name}.`, start, nameLength);
8054
+ return {
8055
+ type: ["ops", ...name.split(".")],
8056
+ value: args
8057
+ };
8058
+ }
8059
+ };
8060
+ /**
8061
+ * This function reads a text into a document with the rules of a profile (SYNTAX.PARSE). It does not throw for a
8062
+ * bad text. The issue gives the offset, the length and a message (SYNTAX.SPAN).
8063
+ *
8064
+ * @param profile - The syntax profile.
8065
+ * @param text - The text.
8066
+ * @returns The document, or the issues of the text.
8067
+ * @throws {TypeError} The profile is not valid, for example an operator has two entries of the same place.
8068
+ */
8069
+ function parse(profile, text) {
8070
+ const parser = new Parser(compileProfile(profile), text);
8071
+ try {
8072
+ return {
8073
+ ok: true,
8074
+ doc: parser.parse()
8075
+ };
8076
+ } catch (error) {
8077
+ if (error instanceof Stop) return {
8078
+ ok: false,
8079
+ issues: [error.issue]
8080
+ };
8081
+ if (isStackOverflow(error)) return {
8082
+ ok: false,
8083
+ issues: [{
8084
+ offset: parser.position(),
8085
+ length: 0,
8086
+ message: "The text is too deep for the stack of the host."
8087
+ }]
8088
+ };
8089
+ throw error;
8090
+ }
8091
+ }
8092
+ function none(reason) {
8093
+ return {
8094
+ tag: "none",
8095
+ reason
8096
+ };
8097
+ }
8098
+ function quoteName(name) {
8099
+ return `\`${name.replaceAll("`", "``")}\``;
8100
+ }
8101
+ function wordFor(syn, value) {
8102
+ for (const [word, held] of syn.words) if (Object.is(held, value)) return word;
8103
+ }
8104
+ function textOfString(syn, value) {
8105
+ const quote = syn.quote;
8106
+ if (quote === void 0) return void 0;
8107
+ if (syn.doubled) return `${quote}${value.replaceAll(quote, quote + quote)}${quote}`;
8108
+ const json = JSON.stringify(value);
8109
+ return quote === "\"" ? json : `'${json.slice(1, -1).replaceAll("\\\"", "\"").replaceAll("'", "\\'")}'`;
8110
+ }
8111
+ function textOfNumber(syn, value) {
8112
+ if (!syn.numbers) return wordFor(syn, value);
8113
+ const negative = value < 0 || Object.is(value, -0);
8114
+ if (negative && !syn.signed) return wordFor(syn, value);
8115
+ if (Number.isFinite(value)) return negative ? `-${String(-value)}` : String(value);
8116
+ return wordFor(syn, value) ?? (Number.isNaN(value) ? void 0 : negative ? "-1e999" : "1e999");
8117
+ }
8118
+ function literalShape(syn, value) {
8119
+ const text = typeof value === "string" ? textOfString(syn, value) : typeof value === "number" ? textOfNumber(syn, value) : wordFor(syn, value);
8120
+ return text === void 0 ? none(`This syntax has no text for the literal ${describe(value)}.`) : {
8121
+ tag: "text",
8122
+ text
8123
+ };
8124
+ }
8125
+ function plainSegment(syn, name) {
8126
+ return NAME.test(name) && !syn.reserved.has(name) && !syn.patterns.some((p) => p.whole.test(name));
8127
+ }
8128
+ function laterSegment(step) {
8129
+ if (typeof step === "string") return NAME.test(step) ? step : quoteName(step);
8130
+ return typeof step === "number" && Number.isSafeInteger(step) && step >= 0 ? String(step) : void 0;
8131
+ }
8132
+ function refShape(syn, value) {
8133
+ if (!Array.isArray(value) || value.length === 0) return none("The path of the reference is empty.");
8134
+ for (const pattern of syn.patterns) {
8135
+ const text = pattern.write(value);
8136
+ if (text !== void 0) return {
8137
+ tag: "text",
8138
+ text
8139
+ };
8140
+ }
8141
+ const [root, ...rest] = value;
8142
+ if ((rest.length > 1 || root !== syn.bare && rest.length > 0) && !syn.fields) return none("This syntax has no field steps.");
8143
+ const later = rest.slice(1).map(laterSegment);
8144
+ let first;
8145
+ let tail = later;
8146
+ if (root === syn.bare && typeof rest[0] === "string") first = plainSegment(syn, rest[0]) ? rest[0] : quoteName(rest[0]);
8147
+ else if (typeof root === "string" && syn.roots.has(root) && !syn.patterns.some((p) => p.whole.test(root))) {
8148
+ first = root;
8149
+ tail = rest.map(laterSegment);
8150
+ }
8151
+ if (first === void 0 || tail.includes(void 0)) return none("This syntax has no text for the path of the reference.");
8152
+ return {
8153
+ tag: "text",
8154
+ text: [first, ...tail].join(".")
8155
+ };
8156
+ }
8157
+ function callName(syn, keys) {
8158
+ if (keys.length === 0 || !keys.every((key) => typeof key === "string" && NAME.test(key))) return void 0;
8159
+ const name = keys.join(".");
8160
+ if (syn.forms.has(name) || syn.opWords.has(keys[0])) return void 0;
8161
+ return syn.ops === true || syn.ops.has(name) ? name : void 0;
8162
+ }
8163
+ function formShape(form, value) {
8164
+ if (form.fields === void 0) {
8165
+ if (!Array.isArray(value) || value.length < form.min) return void 0;
8166
+ return {
8167
+ tag: "call",
8168
+ name: form.name,
8169
+ args: value.map((item, index) => [index, item])
8170
+ };
8171
+ }
8172
+ if (!isRecord(value)) return void 0;
8173
+ const count = Object.keys(value).length;
8174
+ const present = form.fields.slice(0, count);
8175
+ if (count < form.min || present.length < count || !present.every((key) => Object.hasOwn(value, key))) return void 0;
8176
+ return {
8177
+ tag: "call",
8178
+ name: form.name,
8179
+ args: present.map((key) => [key, value[key]])
8180
+ };
8181
+ }
8182
+ function opShape(syn, key, terms) {
8183
+ for (const op of syn.byKind.get(key) ?? []) if (op.fixity === "infix" ? terms.length === 2 || op.assoc === "flat" && terms.length > 2 : terms.length === 1) return {
8184
+ tag: "op",
8185
+ op,
8186
+ terms
8187
+ };
8188
+ }
8189
+ /** This function gives the shape of a document: a literal or a reference, an operator, a call, or no text. */
8190
+ function shapeOf(syn, doc) {
8191
+ if (!isEnvelope(doc)) return Array.isArray(doc) || isRecord(doc) ? none("This syntax has no text for a list or a record literal.") : literalShape(syn, doc);
8192
+ if (doc.name !== void 0 || doc.own !== void 0) return none("This syntax has no text for the header of a document.");
8193
+ const path = typePath(doc.type);
8194
+ if (path === void 0) return none("This syntax has no text for a computed type.");
8195
+ const value = doc.value;
8196
+ const name = path.join(".");
8197
+ if (name === "lit") return isEnvelope(value) || Array.isArray(value) || isRecord(value) ? none("This syntax has no text for a list or a record literal.") : literalShape(syn, value);
8198
+ if (name === "ext.undefined") return literalShape(syn, void 0);
8199
+ if (name === "ext.number") {
8200
+ const numbers = {
8201
+ NaN: NaN,
8202
+ Infinity: Number.POSITIVE_INFINITY,
8203
+ "-Infinity": Number.NEGATIVE_INFINITY,
8204
+ "-0": -0
8205
+ };
8206
+ return typeof value === "string" && Object.hasOwn(numbers, value) ? literalShape(syn, numbers[value]) : none("The value of ext.number is not valid.");
8207
+ }
8208
+ if (name === "ref") return refShape(syn, value);
8209
+ const key = JSON.stringify(path);
8210
+ const op = Array.isArray(value) ? opShape(syn, key, value) : void 0;
8211
+ if (op !== void 0) return op;
8212
+ for (const form of syn.formsByKind.get(key) ?? []) {
8213
+ const shape = formShape(form, value);
8214
+ if (shape !== void 0) return shape;
8215
+ }
8216
+ const called = path[0] === "ops" && Array.isArray(value) ? callName(syn, path.slice(1)) : void 0;
8217
+ if (called !== void 0) return {
8218
+ tag: "call",
8219
+ name: called,
8220
+ args: value.map((item, index) => [index, item])
8221
+ };
8222
+ return none(`This syntax has no text for the kind ${name}.`);
8223
+ }
8224
+ function levelOf(syn, doc) {
8225
+ const shape = shapeOf(syn, doc);
8226
+ return shape.tag === "op" ? shape.op.prec : Number.POSITIVE_INFINITY;
8227
+ }
8228
+ /** This function tells if a term needs parentheses in its position, so that `parse` reads the same tree. */
8229
+ function needsGroup(op, index, level) {
8230
+ if (op.fixity === "postfix") return level < op.prec;
8231
+ if (op.fixity === "prefix" || op.assoc === "none" || op.assoc === "flat") return level <= op.prec;
8232
+ return (op.assoc === "left" ? index === 0 : index !== 0) ? level < op.prec : level <= op.prec;
8233
+ }
8234
+ function opText(syn, op, terms, sub) {
8235
+ const texts = [];
8236
+ for (let index = 0; index < terms.length; index += 1) {
8237
+ const term = terms[index];
8238
+ const result = sub(term, [index]);
8239
+ if (!result.ok) return result;
8240
+ let text = result.value;
8241
+ const signedDigit = op.fixity === "prefix" && op.symbol === "-" && syn.signed && /^[0-9]/.test(text);
8242
+ if (needsGroup(op, index, levelOf(syn, term)) || signedDigit) text = `(${text})`;
8243
+ texts.push(text);
8244
+ }
8245
+ const [only = ""] = texts;
8246
+ if (op.fixity === "prefix") return ok(op.word || /^[^A-Za-z0-9_("'`$]/.test(only) ? `${op.symbol} ${only}` : `${op.symbol}${only}`);
8247
+ if (op.fixity === "postfix") return ok(op.word ? `${only} ${op.symbol}` : `${only}${op.symbol}`);
8248
+ return ok(texts.join(` ${op.symbol} `));
8249
+ }
8250
+ /** This function writes one document. `sub` gives the text of each part. */
8251
+ function printNode(syn, doc, sub) {
8252
+ const shape = shapeOf(syn, doc);
8253
+ if (shape.tag === "text") return ok(shape.text);
8254
+ if (shape.tag === "none") return fail("#VALUE!", shape.reason);
8255
+ if (shape.tag === "op") return opText(syn, shape.op, shape.terms, sub);
8256
+ const texts = [];
8257
+ for (const [key, arg] of shape.args) {
8258
+ const result = sub(arg, [key]);
8259
+ if (!result.ok) return result;
8260
+ texts.push(result.value);
8261
+ }
8262
+ return ok(`${shape.name}(${texts.join(`${syn.separator} `)})`);
8263
+ }
8264
+ function printTree(syn, doc, place) {
8265
+ const result = printNode(syn, doc, (child, path) => printTree(syn, child, [...place, ...path]));
8266
+ return result.ok || result.error.place !== void 0 ? result : fail(result.error.code, result.error.reason, { place });
8267
+ }
8268
+ /**
8269
+ * This function writes a document as text with the rules of a profile (SYNTAX.PRINT). It writes the fewest
8270
+ * parentheses that keep the tree. `parse` reads the text back to the same document (SYNTAX.ROUNDTRIP).
8271
+ *
8272
+ * @param profile - The syntax profile.
8273
+ * @param doc - The document.
8274
+ * @returns The text, or `#VALUE!` at the place of a document that the profile cannot write.
8275
+ * @throws {TypeError} The profile is not valid.
8276
+ */
8277
+ function print(profile, doc) {
8278
+ const syn = compileProfile(profile);
8279
+ try {
8280
+ return printTree(syn, doc, []);
8281
+ } catch (error) {
8282
+ if (isStackOverflow(error)) return fail("#DEPTH!", "The document is too deep for the stack of the host.", { cause: error });
8283
+ throw error;
8284
+ }
8285
+ }
8286
+ /**
8287
+ * This function makes the part of a merge that adds the verb `format` to a machine (D23, D41). Its default writes
8288
+ * each document with the printer of the profile. A part gives its own text through the ladder, thus an own entry or
8289
+ * a kind entry of `format` still wins.
8290
+ *
8291
+ * @param profile - The syntax profile.
8292
+ * @returns The part for `mergeMachines`.
8293
+ */
8294
+ function syntaxFormat(profile) {
8295
+ const syn = compileProfile(profile);
8296
+ const code = ({ doc, parts, place }) => {
8297
+ const byPath = new Map(parts.map((part) => [JSON.stringify(part.path), part]));
8298
+ return printNode(syn, doc, (child, path) => {
8299
+ const part = byPath.get(JSON.stringify(path));
8300
+ if (part === void 0) return printTree(syn, child, [...place, ...path]);
8301
+ const result = part.evaluate();
8302
+ if (!result.ok) return result;
8303
+ return typeof result.value === "string" ? ok(result.value) : fail("#VALUE!", `The verb format of a part gave ${describe(result.value)}, not a text.`, { place: [...place, ...path] });
8304
+ });
8305
+ };
8306
+ return {
8307
+ world: { defaults: { format: "syntax.format" } },
8308
+ evaluators: { "syntax.format": code }
8309
+ };
8310
+ }
8311
+ //#endregion
6801
8312
  //#region src/reference.ts
6802
8313
  function own$1(table, name) {
6803
8314
  return table !== void 0 && Object.hasOwn(table, name) ? table[name] : void 0;
@@ -6849,13 +8360,22 @@ function examine$1(env, at) {
6849
8360
  split
6850
8361
  };
6851
8362
  }
8363
+ /**
8364
+ * This function gives the effects that two lists of capabilities both permit (CAP.ONLY). The reference reads the rule
8365
+ * from SPEC directly, and not from the intersection of the plan. Thus `agree` finds a bug in either one (D15).
8366
+ */
8367
+ function bothPermit(a, b) {
8368
+ const out = [];
8369
+ for (const cap of [...a, ...b]) if (permits(a, cap) && permits(b, cap) && !permits(out, cap)) out.push(cap);
8370
+ return out;
8371
+ }
6852
8372
  /** This function gives the capabilities that the rules of a kind give one part (D14, CAP.CONTRACT, CAP.ONLY). */
6853
8373
  function capsOfPart(rules, path, caps) {
6854
8374
  let out = caps;
6855
8375
  for (const rule of rules ?? []) {
6856
8376
  if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(path, pattern))) continue;
6857
8377
  if (rule.rule === "mask") return [];
6858
- if (rule.rule === "only") out = intersectCaps(out, rule.caps);
8378
+ if (rule.rule === "only") out = bothPermit(out, rule.caps);
6859
8379
  }
6860
8380
  return out;
6861
8381
  }
@@ -7008,6 +8528,7 @@ function evalInput(env, seen, at) {
7008
8528
  parts,
7009
8529
  context: at.ctx,
7010
8530
  place: at.place,
8531
+ machine: env.machine,
7011
8532
  ...at.address ? { address: true } : {},
7012
8533
  resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
7013
8534
  effect: (kind, payload) => cause(env, at.ctx, kind, payload, at.place),
@@ -7035,6 +8556,7 @@ function runInput(env, seen, at) {
7035
8556
  parts,
7036
8557
  context: at.ctx,
7037
8558
  place: at.place,
8559
+ machine: env.machine,
7038
8560
  resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
7039
8561
  effect: function* (kind, payload) {
7040
8562
  return cause(env, at.ctx, kind, payload, at.place);
@@ -7125,6 +8647,7 @@ function reference(machine, doc, context = makeContext(), options = {}) {
7125
8647
  ...context,
7126
8648
  world: worldThing(machine.world)
7127
8649
  } : context;
8650
+ activeEnvs.push(env);
7128
8651
  try {
7129
8652
  return evaluateAt(env, {
7130
8653
  value: doc,
@@ -7136,8 +8659,12 @@ function reference(machine, doc, context = makeContext(), options = {}) {
7136
8659
  });
7137
8660
  } catch (error) {
7138
8661
  return placed(thrown(error, "the reference"), []);
8662
+ } finally {
8663
+ activeEnvs.pop();
7139
8664
  }
7140
8665
  }
8666
+ /** The evaluations of the reference that run at this time, the innermost last. */
8667
+ const activeEnvs = [];
7141
8668
  const refNodes = /* @__PURE__ */ new WeakMap();
7142
8669
  /** The attributes in evaluation in the reference, in the order of their demands (TREE.CYCLE). */
7143
8670
  const inEvaluation = [];
@@ -7147,28 +8674,109 @@ function nameOfAttribute(node, name) {
7147
8674
  function refNodeOf(thing) {
7148
8675
  return typeof thing === "object" && thing !== null ? refNodes.get(thing) : void 0;
7149
8676
  }
7150
- /** TREE.ONCE, TREE.MEMO and TREE.CYCLE: the result of one attribute, or `undefined` when the node has no such part. */
7151
- function attributeOf(node, self, name) {
8677
+ /**
8678
+ * TREE.LADDER: an equation of the kind of a node evaluates in the reference. It gets the node as `self`, the names of
8679
+ * its rung and no capabilities. A bare equation gets the type `of` of the parts of the kind.
8680
+ */
8681
+ function equationOf(node, term, names) {
8682
+ const env = node.env;
8683
+ if (env === void 0) return fail("#NOEVAL", "The evaluation of an equation needs the machine.");
8684
+ const ctx = {
8685
+ ...node.ctx,
8686
+ names,
8687
+ caps: [],
8688
+ self: node.thing
8689
+ };
8690
+ return reference(env.machine, term, ctx, {
8691
+ definitions: env.definitions,
8692
+ ...node.of === void 0 ? {} : { declaredType: node.of }
8693
+ });
8694
+ }
8695
+ function termIn(table, name) {
8696
+ return table === void 0 || !Object.hasOwn(table, name) ? void 0 : table[name];
8697
+ }
8698
+ /** TREE.DOWN: the names of a child for an equation of `down` of its parent: `child`, `index` and `prev`. */
8699
+ function namesOfChild(up, child) {
8700
+ const children = attributeOf(up, "children");
8701
+ if (children !== void 0 && !children.ok) return children;
8702
+ const list = children !== void 0 && Array.isArray(children.value) ? children.value : [];
8703
+ const index = list.indexOf(child.thing);
8704
+ return ok({
8705
+ child: child.thing,
8706
+ index: index < 0 ? null : index,
8707
+ prev: index > 0 ? list[index - 1] : null
8708
+ });
8709
+ }
8710
+ /** TREE.FOLD: the unit, then `combine` with the attribute of each node of this tree in the list `children`. */
8711
+ function foldOf(node, name, fold) {
8712
+ let acc = equationOf(node, fold.unit, {});
8713
+ if (!acc.ok) return acc;
8714
+ const children = attributeOf(node, "children");
8715
+ if (children === void 0) return acc;
8716
+ if (!children.ok) return children;
8717
+ if (!Array.isArray(children.value)) return fail("#VALUE!", `The fold of ${name} needs a list in children.`);
8718
+ for (const item of children.value) {
8719
+ const child = refNodeOf(item);
8720
+ if (child === void 0 || child.tree !== node.tree) continue;
8721
+ const value = attributeOf(child, name);
8722
+ if (value === void 0) return fail("#N/A", `No rung gives ${nameOfAttribute(child, name)}.`);
8723
+ if (!value.ok) return value;
8724
+ acc = equationOf(node, fold.combine, {
8725
+ acc: acc.value,
8726
+ item: value.value
8727
+ });
8728
+ if (!acc.ok) return acc;
8729
+ }
8730
+ return acc;
8731
+ }
8732
+ /**
8733
+ * TREE.LADDER: the rungs of the ladder of an attribute, in their order. A rung gives `undefined` when it does not
8734
+ * answer, and the next rung then tries.
8735
+ */
8736
+ const REF_RUNGS = [
8737
+ ["own", (node, name) => node.parts.find((item) => item.key === name)?.evaluate({
8738
+ ...node.ctx,
8739
+ self: node.thing
8740
+ })],
8741
+ ["kind", (node, name) => {
8742
+ const term = termIn(node.contract?.equations, name);
8743
+ return term === void 0 ? void 0 : equationOf(node, term, {});
8744
+ }],
8745
+ ["parent", (node, name) => {
8746
+ const up = node.up;
8747
+ const term = up === void 0 ? void 0 : termIn(up.contract?.down, name);
8748
+ if (up === void 0 || term === void 0) return void 0;
8749
+ const names = namesOfChild(up, node);
8750
+ return names.ok ? equationOf(up, term, names.value) : names;
8751
+ }],
8752
+ ["copy", (node, name) => node.up !== void 0 && termIn(node.contract?.attributes, name)?.copy === true ? attributeOf(node.up, name) : void 0],
8753
+ ["default", (node, name) => {
8754
+ const declared = termIn(node.contract?.attributes, name);
8755
+ if (declared?.fold !== void 0) return foldOf(node, name, declared.fold);
8756
+ return declared?.default === void 0 ? void 0 : equationOf(node, declared.default, {});
8757
+ }]
8758
+ ];
8759
+ /** TREE.ONCE, TREE.MEMO and TREE.CYCLE: the result of one attribute, or `undefined` when no rung of its ladder answers. */
8760
+ function attributeOf(node, name) {
7152
8761
  const done = node.values.get(name);
7153
8762
  if (done !== void 0) return done;
7154
8763
  if (node.pending.has(name)) {
7155
8764
  const from = inEvaluation.findIndex((entry) => entry.node === node && entry.name === name);
7156
8765
  return fail("#CYCLE!", `The attributes form a cycle: ${[...from < 0 ? [nameOfAttribute(node, name)] : inEvaluation.slice(from).map((entry) => nameOfAttribute(entry.node, entry.name)), nameOfAttribute(node, name)].join(" -> ")}.`);
7157
8766
  }
7158
- const part = node.parts.find((item) => item.key === name);
7159
- if (part === void 0) return void 0;
7160
8767
  node.pending.add(name);
7161
8768
  inEvaluation.push({
7162
8769
  node,
7163
8770
  name
7164
8771
  });
7165
8772
  try {
7166
- const result = part.evaluate({
7167
- ...node.ctx,
7168
- self
7169
- });
7170
- node.values.set(name, result);
7171
- return result;
8773
+ for (const [, rung] of REF_RUNGS) {
8774
+ const result = rung(node, name);
8775
+ if (result === void 0) continue;
8776
+ node.values.set(name, result);
8777
+ return result;
8778
+ }
8779
+ return;
7172
8780
  } finally {
7173
8781
  node.pending.delete(name);
7174
8782
  inEvaluation.pop();
@@ -7178,7 +8786,7 @@ function attributeOf(node, self, name) {
7178
8786
  function jsonOfNode(node, self, open) {
7179
8787
  const record = {};
7180
8788
  for (const part of node.parts) {
7181
- const result = attributeOf(node, self, part.key);
8789
+ const result = attributeOf(node, part.key);
7182
8790
  if (!result.ok) return result;
7183
8791
  const value = plainValue(result.value, [...open, self]);
7184
8792
  if (!value.ok) return value;
@@ -7216,15 +8824,23 @@ function plainValue(value, open) {
7216
8824
  * TREE.LAZY, TREE.PARENT, TREE.SIBLING and TREE.ERROR: a node of an open tree gives its thing, and the root of a new
7217
8825
  * tree gives its JSON. A step on the thing reads an attribute, and a failed attribute throws its own error.
7218
8826
  */
7219
- const treeDefinition = ({ parts, context, kind, place }) => {
8827
+ const treeDefinition = ({ parts, context, kind, place, machine, typePath }) => {
7220
8828
  const outer = refNodeOf(context.self);
7221
8829
  const nested = outer !== void 0 && outer.tree.open;
8830
+ const found = machine === void 0 || typePath.length === 0 ? void 0 : lookupKind(machine.world, typePath);
8831
+ const contract = found?.ok === true ? found.kind.tree : void 0;
8832
+ const of = contract === void 0 || found?.ok !== true ? void 0 : equationType(found.kind);
7222
8833
  const node = {
7223
8834
  tree: nested ? outer.tree : { open: true },
7224
8835
  kind,
7225
8836
  place,
7226
8837
  parts,
7227
8838
  ctx: context,
8839
+ contract,
8840
+ of,
8841
+ up: nested ? outer : void 0,
8842
+ env: activeEnvs[activeEnvs.length - 1],
8843
+ thing: null,
7228
8844
  values: /* @__PURE__ */ new Map(),
7229
8845
  pending: /* @__PURE__ */ new Set()
7230
8846
  };
@@ -7235,17 +8851,18 @@ const treeDefinition = ({ parts, context, kind, place }) => {
7235
8851
  deref: (key) => {
7236
8852
  if (key === "parent") return context.self;
7237
8853
  if (key === "type") return kind;
7238
- const result = attributeOf(node, self, String(key));
8854
+ const result = attributeOf(node, String(key));
7239
8855
  if (result === void 0 || result.ok) return result?.ok === true ? result.value : void 0;
7240
8856
  throw new Failure(result.error);
7241
8857
  },
7242
- has: (key) => key === "parent" || key === "type" || parts.some((part) => part.key === String(key)),
8858
+ has: (key) => key === "parent" || key === "type" || parts.some((part) => part.key === String(key)) || node.values.has(String(key)),
7243
8859
  toJson: () => {
7244
8860
  const result = jsonOfNode(node, self, []);
7245
8861
  if (result.ok) return result.value;
7246
8862
  throw new Failure(result.error);
7247
8863
  }
7248
8864
  };
8865
+ node.thing = self;
7249
8866
  refNodes.set(self, node);
7250
8867
  if (nested) return ok(self);
7251
8868
  try {
@@ -7437,12 +9054,12 @@ function formulaDefinitions(profile = {}) {
7437
9054
  return thrown(error, `the operation ${name}`);
7438
9055
  }
7439
9056
  };
7440
- const ext = ({ typePath, doc, context }) => {
9057
+ const ext = ({ typePath, doc, context, machine }) => {
7441
9058
  const name = typePath.slice(1).join(".");
7442
9059
  const handler = own$1(profile.ext, name) ?? own$1(STD_EXT, name);
7443
9060
  if (handler === void 0) return fail("#NAME?", `The language has no extension ${name}.`);
7444
9061
  try {
7445
- return handler(doc.value, context);
9062
+ return handler(doc.value, context, machine?.domains);
7446
9063
  } catch (error) {
7447
9064
  return thrown(error, `the extension ${name}`);
7448
9065
  }
@@ -7477,6 +9094,13 @@ function valuesOfStrict(parts) {
7477
9094
  }
7478
9095
  //#endregion
7479
9096
  //#region src/agree.ts
9097
+ /** The tiers that `agree` compares when its options name none. */
9098
+ const DEFAULT_TIERS = /* @__PURE__ */ Object.freeze([
9099
+ "reference",
9100
+ "traced",
9101
+ "again",
9102
+ "folds"
9103
+ ]);
7480
9104
  /**
7481
9105
  * This function tells if two values are the same for `agree`. Lists and plain records compare item by item and field
7482
9106
  * by field, and the order of the fields does not matter. Each other leaf compares with `Object.is`, thus `-0` is not
@@ -7566,7 +9190,11 @@ function agree(machine, doc, context = makeContext(), options = {}) {
7566
9190
  };
7567
9191
  const observe = options.observe;
7568
9192
  observe?.();
7569
- const plan = prepare(machine, doc, declared);
9193
+ const folds = observe === void 0;
9194
+ const plan = prepare(machine, doc, {
9195
+ ...declared,
9196
+ fold: folds
9197
+ });
7570
9198
  const effects = [];
7571
9199
  const result = plan.evaluate(context, {
7572
9200
  effects,
@@ -7579,11 +9207,7 @@ function agree(machine, doc, context = makeContext(), options = {}) {
7579
9207
  if (why !== void 0 || observe === void 0) return why;
7580
9208
  return sameValue(saw, observe(), options.equal) ? void 0 : "The host saw other calls in the tier.";
7581
9209
  };
7582
- for (const tier of options.tiers ?? [
7583
- "reference",
7584
- "traced",
7585
- "again"
7586
- ]) {
9210
+ for (const tier of options.tiers ?? DEFAULT_TIERS) {
7587
9211
  let other;
7588
9212
  let otherEffects = [];
7589
9213
  if (tier === "reference") other = reference(machine, doc, context, {
@@ -7599,6 +9223,27 @@ function agree(machine, doc, context = makeContext(), options = {}) {
7599
9223
  });
7600
9224
  other = traced.result;
7601
9225
  otherEffects = [...traced.effects];
9226
+ } else if (tier === "folds") {
9227
+ other = prepare(machine, doc, {
9228
+ ...declared,
9229
+ fold: !folds
9230
+ }).evaluate(context, {
9231
+ effects: otherEffects,
9232
+ ...mock
9233
+ });
9234
+ if (observe !== void 0) {
9235
+ observe();
9236
+ if (overflowed(result) || overflowed(other)) continue;
9237
+ const why = resultDiffers(result, other, options) ?? effectsDiffer(effects, otherEffects, options);
9238
+ if (why !== void 0) return {
9239
+ ok: false,
9240
+ tier,
9241
+ plan: result,
9242
+ other,
9243
+ reason: why
9244
+ };
9245
+ continue;
9246
+ }
7602
9247
  } else other = plan.evaluate(context, {
7603
9248
  effects: otherEffects,
7604
9249
  ...mock
@@ -8633,6 +10278,7 @@ function instanceOf(env, under, doc, split, sample) {
8633
10278
  doc,
8634
10279
  data: split.data,
8635
10280
  place: PLACE,
10281
+ machine: env.machine,
8636
10282
  fill
8637
10283
  };
8638
10284
  const who = `the ${env.runner ? "runner" : "evaluator"} ${env.name}`;
@@ -10244,6 +11890,6 @@ function typeFromSamples(values, options = {}) {
10244
11890
  return samplesAt(values, options.closed === true, 0);
10245
11891
  }
10246
11892
  //#endregion
10247
- export { CAPS_TYPE, CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, JOURNAL, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, agree, ask, capKeys, check, checkLatent, checkSteps, classify, components, conforms, context, cycles, dataEdges, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, entriesAsJson, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, partCaps, partsOf, pathMatches, permits, placed, planner, prepare, random, recorder, ref, reference, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stored, tag, thrown, toJson, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
11893
+ export { ATTRIBUTE_RUNGS, CAPS_TYPE, CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, JOURNAL, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, agree, ask, attributeTrace, capKeys, check, checkLatent, checkSteps, classify, components, conforms, context, cycles, dataEdges, decodeDomain, decodeValue, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partsOf, pathMatches, permits, placed, planner, prepare, print, random, recorder, ref, reference, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stored, syntaxFormat, tag, thrown, toJson, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
10248
11894
 
10249
11895
  //# sourceMappingURL=index.js.map