@mark1russell7/coeval 0.18.0 → 0.19.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
@@ -415,6 +415,52 @@ function isAlias(entry) {
415
415
  function isNamespace(entry) {
416
416
  return entry !== void 0 && !isKind(entry) && !isAlias(entry) && Object.hasOwn(entry, "kinds");
417
417
  }
418
+ /**
419
+ * This function visits each kind of a world. These are the kinds of each namespace, at each depth, and the fallback
420
+ * kind of each namespace and of the world. It does not follow an alias, because the kind of an alias has its own place. A
421
+ * fallback kind has the keys of its namespace. It comes after the entries of that namespace. `checkWorld` reads the
422
+ * kinds with this one function.
423
+ *
424
+ * @param world - The world.
425
+ * @param visit - The function that gets each kind, its keys from the root of the world, and `true` for a fallback kind.
426
+ */
427
+ function eachKind(world, visit) {
428
+ const way = /* @__PURE__ */ new Set();
429
+ const entries = (kinds, path) => {
430
+ for (const key of Object.keys(kinds)) {
431
+ const entry = kinds[key];
432
+ const here = [...path, key];
433
+ if (isKind(entry)) visit(entry, here, false);
434
+ else if (isNamespace(entry) && !way.has(entry)) {
435
+ way.add(entry);
436
+ entries(entry.kinds, here);
437
+ if (entry.fallback !== void 0) visit(entry.fallback, here, true);
438
+ way.delete(entry);
439
+ }
440
+ }
441
+ };
442
+ entries(world.kinds, []);
443
+ if (world.fallback !== void 0) visit(world.fallback, [], true);
444
+ }
445
+ /**
446
+ * This function gives the kind at a path of a world, without an alias and without a fallback kind. A namespace on the
447
+ * way gives its entries.
448
+ *
449
+ * @param world - The world.
450
+ * @param path - The keys from the root of the world.
451
+ * @returns The kind, or `undefined` when no kind is at the path.
452
+ */
453
+ function kindAt(world, path) {
454
+ let entries = world.kinds;
455
+ let entry;
456
+ for (let index = 0; index < path.length; index += 1) {
457
+ entry = entryAt(entries, path[index]);
458
+ if (index === path.length - 1) break;
459
+ if (!isNamespace(entry)) return void 0;
460
+ entries = entry.kinds;
461
+ }
462
+ return isKind(entry) ? entry : void 0;
463
+ }
418
464
  function entryAt(entries, key) {
419
465
  const name = String(key);
420
466
  return Object.hasOwn(entries, name) ? entries[name] : void 0;
@@ -679,7 +725,11 @@ function formOf(type, domains) {
679
725
  closed
680
726
  };
681
727
  }
682
- /** This function gives each base type that holds the members of a base type: the type itself and each parent, through each level. */
728
+ /**
729
+ * This function gives each base type that holds the members of a base type: the type itself and each parent, through
730
+ * each level. A cycle of parents ends at a name that the line has, and a parent that is not a domain ends its branch.
731
+ * The function is internal: `encodeValue` uses it too (D109).
732
+ */
683
733
  function lineOf(name, domains) {
684
734
  const seen = /* @__PURE__ */ new Set([name]);
685
735
  const queue = [name];
@@ -3580,7 +3630,7 @@ function selfLabel(self) {
3580
3630
  return describe(self).slice(0, 40);
3581
3631
  }
3582
3632
  }
3583
- const NO_ANSWER = {
3633
+ const NO_ANSWER$1 = {
3584
3634
  verb: "eval",
3585
3635
  error: "no-answer",
3586
3636
  steps: []
@@ -4065,7 +4115,7 @@ function holderNode() {
4065
4115
  value: null
4066
4116
  },
4067
4117
  declared: false,
4068
- answer: NO_ANSWER,
4118
+ answer: NO_ANSWER$1,
4069
4119
  side: "derive",
4070
4120
  names: [],
4071
4121
  scope: {},
@@ -4219,7 +4269,7 @@ const NO_META = /* @__PURE__ */ Object.freeze({
4219
4269
  value: null
4220
4270
  },
4221
4271
  declared: false,
4222
- answer: NO_ANSWER,
4272
+ answer: NO_ANSWER$1,
4223
4273
  side: "derive"
4224
4274
  });
4225
4275
  function compileNode(c, value, place, declared, depth, address = false) {
@@ -4879,7 +4929,7 @@ function rootContext(machine, ctx) {
4879
4929
  */
4880
4930
  function prepare(machine, doc, options = {}) {
4881
4931
  const verb = options.verb ?? "eval";
4882
- const noAnswer = verb === "eval" ? NO_ANSWER : {
4932
+ const noAnswer = verb === "eval" ? NO_ANSWER$1 : {
4883
4933
  verb,
4884
4934
  error: "no-answer",
4885
4935
  steps: []
@@ -5500,10 +5550,10 @@ const STD_EVALUATORS = {
5500
5550
  const found = resolve(data);
5501
5551
  return found.ok ? ok(valueOfThing(found.thing)) : fail(found.code, found.reason);
5502
5552
  },
5503
- "tree.node": (input) => treeNode(input)
5553
+ "tree.node": (input) => treeNode(input, void 0)
5504
5554
  };
5505
5555
  /** The brand of a node of the decorated tree. Its value is the state that the kit reads. */
5506
- const TREE_NODE = /* @__PURE__ */ Symbol.for("coeval.tree.node");
5556
+ const TREE_NODE$1 = /* @__PURE__ */ Symbol.for("coeval.tree.node");
5507
5557
  /** The rungs of the ladder of an attribute, in their order (TREE.LADDER, D42). */
5508
5558
  const ATTRIBUTE_RUNGS = /* @__PURE__ */ Object.freeze([
5509
5559
  "own",
@@ -5512,6 +5562,17 @@ const ATTRIBUTE_RUNGS = /* @__PURE__ */ Object.freeze([
5512
5562
  "copy",
5513
5563
  "default"
5514
5564
  ]);
5565
+ /**
5566
+ * This function gives the code of the kind of a node of the decorated tree, with the options of the host. A host puts
5567
+ * the code at the name `tree.node` of its machine. Without a cell, the code is the standard code.
5568
+ *
5569
+ * @param options - The options, for example the memo cells of the host.
5570
+ * @returns The code.
5571
+ */
5572
+ function treeNodeEvaluator(options = {}) {
5573
+ const host = options.cell;
5574
+ return host === void 0 ? STD_EVALUATORS["tree.node"] : (input) => treeNode(input, host);
5575
+ }
5515
5576
  /** The capabilities of an equation: none (CAP.PURE). */
5516
5577
  const NO_CAPS$1 = /* @__PURE__ */ Object.freeze([]);
5517
5578
  /** The names of an equation of `equations`, of a `unit` and of a `default`. */
@@ -5555,6 +5616,29 @@ function contractOf$1(machine, typePath) {
5555
5616
  };
5556
5617
  }
5557
5618
  const BUSY = /* @__PURE__ */ Object.freeze({ busy: true });
5619
+ /** The answer of the ladder when no rung answers. */
5620
+ const NO_ANSWER = /* @__PURE__ */ Object.freeze({
5621
+ result: void 0,
5622
+ by: void 0
5623
+ });
5624
+ /**
5625
+ * The marks of the attributes in evaluation, for each place of a plan, with the cells of a host (TREE.CELL). Nodes of
5626
+ * two evaluations share their place and their kept cells, thus they share their marks.
5627
+ */
5628
+ const marksByPlace = /* @__PURE__ */ new WeakMap();
5629
+ /** The trees of the cells of a host, for each place of a root in a plan. Nodes of two evaluations stay in one tree. */
5630
+ const buildsByPlace = /* @__PURE__ */ new WeakMap();
5631
+ /** This function gives the value of a weak map, or puts a new value in it. */
5632
+ function keptAt(map, place, make) {
5633
+ let value = map.get(place);
5634
+ if (value === void 0) {
5635
+ value = make();
5636
+ map.set(place, value);
5637
+ }
5638
+ return value;
5639
+ }
5640
+ /** A value that no exception has. */
5641
+ const NOT_THROWN = /* @__PURE__ */ Symbol("coeval.tree.not-thrown");
5558
5642
  /** The attributes in evaluation, in the order of their demands. An evaluation does not wait, thus one list serves. */
5559
5643
  const demands = [];
5560
5644
  function attributeText(key, type, place) {
@@ -5568,7 +5652,7 @@ function cycleAt(cells, key, text) {
5568
5652
  return fail("#CYCLE!", `The attributes form a cycle: ${chain.join(" -> ")}.`);
5569
5653
  }
5570
5654
  function stateOf(thing) {
5571
- return typeof thing === "object" && thing !== null ? thing[TREE_NODE] : void 0;
5655
+ return typeof thing === "object" && thing !== null ? thing[TREE_NODE$1] : void 0;
5572
5656
  }
5573
5657
  /** This function sets an own field, also the field `__proto__` (SHAPE.PROTO). */
5574
5658
  function putField(target, key, value) {
@@ -5625,14 +5709,17 @@ function plainOf(value, path) {
5625
5709
  * the node, an equation of its kind and an equation `down` of the kind of its parent. A copy from the parent, then a
5626
5710
  * fold or a default, come last. A failed attribute throws `Failure` with its own error, thus a reference to it gives that error.
5627
5711
  * The argument `outer` is the self of the context, that `treeNode` resolved. The node reads no root of the context directly (C4).
5712
+ *
5713
+ * The argument `host` gives the memo cells of the host (TREE.CELL), or `undefined` for the plain memo of the node.
5628
5714
  */
5629
- function treeThing(input, build, outer) {
5715
+ function treeThing(input, build, outer, host) {
5630
5716
  const { parts, context, kind: type, place, machine } = input;
5631
5717
  const runtime = input[RUNTIME];
5632
5718
  const { tree, of } = contractOf$1(machine, input.typePath);
5633
5719
  const above = stateOf(outer);
5634
5720
  const up = above !== void 0 && above.build === build ? above : void 0;
5635
5721
  const cells = /* @__PURE__ */ new Map();
5722
+ const marks = host === void 0 ? cells : keptAt(marksByPlace, place, () => /* @__PURE__ */ new Map());
5636
5723
  /** The positions of the items of the list `children`, for the names of the children. */
5637
5724
  let positions;
5638
5725
  const fold = (key, declared) => {
@@ -5696,7 +5783,50 @@ function treeThing(input, build, outer) {
5696
5783
  by: "default"
5697
5784
  };
5698
5785
  };
5786
+ /**
5787
+ * This function gives an attribute through the cell of the host (TREE.CELL). The cell is the memo. The node keeps
5788
+ * the last answer only for `has` and `trace`.
5789
+ */
5790
+ const through = host === void 0 ? void 0 : (key) => {
5791
+ const text = attributeText(key, type, place);
5792
+ if (marks.has(key)) return cycleAt(marks, key, text);
5793
+ if (tree === void 0 && up?.tree === void 0 && !parts.some((item) => item.key === key)) return void 0;
5794
+ marks.set(key, BUSY);
5795
+ demands.push({
5796
+ cells: marks,
5797
+ key,
5798
+ text
5799
+ });
5800
+ let thrown = NOT_THROWN;
5801
+ let answer;
5802
+ try {
5803
+ answer = host(place, key, () => {
5804
+ try {
5805
+ return climb(key) ?? NO_ANSWER;
5806
+ } catch (error) {
5807
+ thrown = error;
5808
+ throw error;
5809
+ }
5810
+ });
5811
+ } catch (error) {
5812
+ if (error === thrown) throw error;
5813
+ answer = {
5814
+ result: fail("#CYCLE!", `The cells of the host found a cycle in the demands: ${demands.map((demand) => demand.text).join(" -> ")}.`, { cause: error }),
5815
+ by: void 0
5816
+ };
5817
+ } finally {
5818
+ demands.pop();
5819
+ marks.delete(key);
5820
+ }
5821
+ cells.set(key, {
5822
+ busy: false,
5823
+ result: answer.result,
5824
+ by: answer.by
5825
+ });
5826
+ return answer.result;
5827
+ };
5699
5828
  const read = (key) => {
5829
+ if (through !== void 0) return through(key);
5700
5830
  const cell = cells.get(key);
5701
5831
  if (cell !== void 0) return cell.busy ? cycleAt(cells, key, attributeText(key, type, place)) : cell.result;
5702
5832
  if (tree === void 0 && up?.tree === void 0 && !parts.some((item) => item.key === key)) return void 0;
@@ -5790,7 +5920,7 @@ function treeThing(input, build, outer) {
5790
5920
  };
5791
5921
  const node = {
5792
5922
  [THING]: true,
5793
- [TREE_NODE]: state,
5923
+ [TREE_NODE$1]: state,
5794
5924
  type,
5795
5925
  label: `node ${type}`,
5796
5926
  deref(key) {
@@ -5844,14 +5974,16 @@ const NO_HOPS = /* @__PURE__ */ Object.freeze({ hops: false });
5844
5974
  * This function evaluates a node of the decorated tree. Inside an attribute of an open tree, the node gives its host
5845
5975
  * thing, and no attribute evaluates. Else the node is the root of a new tree, and it gives the JSON of the tree. The
5846
5976
  * node reads `self` through `resolve` (C4, D44). A machine that closes the root `self` thus gives no nested trees.
5977
+ * The argument `host` gives the memo cells of the host (TREE.CELL), or `undefined` for the plain memo of each node.
5847
5978
  */
5848
- function treeNode(input) {
5979
+ function treeNode(input, host) {
5849
5980
  const found = input.resolve(SELF_PATH, NO_HOPS);
5850
5981
  const outer = found.ok ? found.thing : void 0;
5851
5982
  const above = stateOf(outer);
5852
- if (above !== void 0 && above.build.open) return ok(treeThing(input, above.build, outer));
5853
- const build = { open: true };
5854
- const root = treeThing(input, build, outer);
5983
+ if (above !== void 0 && above.build.open) return ok(treeThing(input, above.build, outer, host));
5984
+ const build = host === void 0 ? { open: true } : keptAt(buildsByPlace, input.place, () => ({ open: true }));
5985
+ build.open = true;
5986
+ const root = treeThing(input, build, outer, host);
5855
5987
  try {
5856
5988
  return stateOf(root).json(/* @__PURE__ */ new Set());
5857
5989
  } finally {
@@ -6593,501 +6725,1968 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
6593
6725
  places
6594
6726
  };
6595
6727
  }
6596
- // src/static.ts
6597
- /** 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. */
6598
- const NO_NAMES = /* @__PURE__ */ new Set();
6599
- /** This function gives the options of a walk without the names of the host. */
6600
- function withoutNames(options) {
6601
- const { names: _host, ...rest } = options;
6602
- return rest;
6603
- }
6604
- /** This function gives the keys of a trail, from its start. It keeps the result in the trail. */
6605
- function keysOf(trail) {
6606
- if (trail === void 0) return [];
6607
- if (trail.full !== void 0) return trail.full;
6608
- const steps = [];
6609
- let here = trail;
6610
- while (here !== void 0 && here.full === void 0) {
6611
- steps.push(here);
6612
- here = here.up;
6613
- }
6614
- const keys = here?.full === void 0 ? [] : [...here.full];
6615
- for (let index = steps.length - 1; index >= 0; index -= 1) for (const key of steps[index].keys) keys.push(key);
6616
- trail.full = keys;
6617
- return keys;
6618
- }
6619
- /** A visit with its paths as trails. It makes the keys of a path only when a reader asks for them. */
6620
- var Visit = class {
6621
- doc;
6622
- declared;
6623
- depth;
6624
- names;
6625
- later;
6626
- slot;
6627
- parent;
6628
- kind;
6629
- typePath;
6630
- address;
6631
- caps;
6632
- #place;
6633
- #at;
6634
- #bound;
6635
- #expect;
6636
- constructor(place, at, doc, declared, depth, names, later, slot, parent, kind, typePath, address, caps, bound, expect) {
6637
- this.doc = doc;
6638
- this.declared = declared;
6639
- this.depth = depth;
6640
- this.names = names;
6641
- this.later = later;
6642
- this.slot = slot;
6643
- this.parent = parent;
6644
- this.kind = kind;
6645
- this.typePath = typePath;
6646
- this.address = address;
6647
- this.caps = caps;
6648
- this.#place = place;
6649
- this.#at = at;
6650
- this.#bound = bound;
6651
- this.#expect = expect;
6652
- }
6653
- /** The names that the scope rules of the parent bind for this document. The check of types reads them. */
6654
- get bound() {
6655
- return this.#bound;
6656
- }
6657
- /** The type that the shape of the parent declares for this part. The check of types reads it. */
6658
- get expect() {
6659
- return this.#expect;
6660
- }
6661
- get place() {
6662
- return keysOf(this.#place);
6663
- }
6664
- get at() {
6665
- return keysOf(this.#at);
6666
- }
6667
- };
6668
6728
  /**
6669
- * This function visits each document of a document: the root and each part at each depth, by the contracts of the
6670
- * kinds. A part of a kind that the world does not have is not visited. With capabilities in the options, the walk
6671
- * narrows them for each part by the rules of its kind, as a run does. The walk uses no stack of the host for the
6672
- * depth, thus a deep document cannot overflow it. The time and the memory of a walk are linear in the size of the
6673
- * document. A visit makes the keys of its place and of its path only when a reader asks for them.
6729
+ * This function examines each value type of a machine before a document exists (TYPE.WORLD, D110). It reads the
6730
+ * `result` and each `expect` of each kind, the parents and the steps of each domain, and the declarations of each type
6731
+ * rule. Each problem of `typeIssues` gives one issue with the keys of the bad term.
6674
6732
  *
6675
- * @param world - The world of the kinds.
6676
- * @param doc - The document, as JSON.
6677
- * @param visit - The function that gets each document. It gives `"skip"` to not visit the parts of a document.
6678
- * @param options - The type of a bare root value, the names, the capabilities and a function for the problems.
6733
+ * A term shape with `kinds` and `expect` also gets an issue for each kind of its list whose `result` does not fit
6734
+ * `expect`. A check of types gives `#TYPE!` at each document of that kind there.
6735
+ *
6736
+ * @param machine - The machine.
6737
+ * @returns The issues: the kinds in the order of the world, then the domains, then the type rules.
6679
6738
  */
6680
- function walk(world, doc, visit, options = {}) {
6681
- const stack = [{
6682
- value: doc,
6683
- place: void 0,
6684
- at: void 0,
6685
- declared: options.declaredType,
6686
- depth: 0,
6687
- names: options.names === void 0 || options.names.length === 0 ? NO_NAMES : new Set(options.names),
6688
- later: NO_NAMES,
6689
- address: false,
6690
- slot: [],
6691
- parent: void 0,
6692
- caps: options.caps,
6693
- bound: [],
6694
- expect: void 0
6695
- }];
6696
- while (stack.length > 0) {
6697
- const item = stack.pop();
6698
- const read = partsOf(world, item.value, item.declared);
6699
- if (!read.ok) {
6700
- options.problem?.({
6701
- place: keysOf(item.place),
6702
- at: keysOf(item.at),
6703
- code: read.code,
6704
- reason: read.reason
6705
- });
6739
+ function machineTypeIssues(machine) {
6740
+ const domains = machine.domains;
6741
+ const world = machine.world;
6742
+ const out = [];
6743
+ const add = (owner, at, reason) => {
6744
+ out.push({
6745
+ code: "#TYPE!",
6746
+ ...owner,
6747
+ verb: "eval",
6748
+ at,
6749
+ reason
6750
+ });
6751
+ };
6752
+ /** This function examines one value type. It gives `true` when the type has no problem. */
6753
+ const examine = (owner, at, type, what) => {
6754
+ const problems = typeIssues(type, domains);
6755
+ for (const problem of problems) add(owner, [...at, ...problem.at], `The ${what} is not a correct value type. ${problem.reason}`);
6756
+ return problems.length === 0;
6757
+ };
6758
+ /**
6759
+ * This function finds each kind of the list `kinds` of a term whose result does not fit the `expect` of the term.
6760
+ * Only a kind at the path itself counts. A path through an alias or to a fallback kind gives no issue.
6761
+ */
6762
+ const results = (owner, kinds, at, expect) => {
6763
+ if (isUnknown(expect, domains)) return;
6764
+ kinds.forEach((path, index) => {
6765
+ const result = (Array.isArray(path) ? kindAt(world, path) : void 0)?.result;
6766
+ if (result === void 0 || typeIssues(result, domains).length > 0 || fits(result, expect, domains)) return;
6767
+ const text = path.join(".");
6768
+ add(owner, [
6769
+ ...at,
6770
+ "kinds",
6771
+ index
6772
+ ], `The kind ${text} has the result ${typeText(result)}, and the part needs the type ${typeText(expect)}. Each document of ${text} here gets #TYPE!.`);
6773
+ });
6774
+ };
6775
+ eachKind(world, (kind, path, fallback) => {
6776
+ const owner = fallback ? {
6777
+ kind: path,
6778
+ fallback: true
6779
+ } : { kind: path };
6780
+ const name = fallback ? path.length === 0 ? "fallback kind of the world" : `fallback kind of ${path.join(".")}` : `kind ${path.join(".")}`;
6781
+ if (kind.result !== void 0) examine(owner, ["result"], kind.result, `result of the ${name}`);
6782
+ const way = /* @__PURE__ */ new Set();
6783
+ const shape = (spec, at) => {
6784
+ if (typeof spec !== "object" || spec === null || way.has(spec)) return;
6785
+ way.add(spec);
6786
+ const expect = spec.expect;
6787
+ const where = [...at, "expect"];
6788
+ if (expect !== void 0 && examine(owner, where, expect, `expected type at ${where.join(".")} of the ${name}`) && spec.shape === "term" && Array.isArray(spec.kinds)) results(owner, spec.kinds, at, expect);
6789
+ if (spec.shape === "list" || spec.shape === "map") shape(spec.item, [...at, "item"]);
6790
+ if (spec.shape === "record") {
6791
+ const fields = spec.fields;
6792
+ if (typeof fields === "object" && fields !== null && !Array.isArray(fields)) for (const key of Object.keys(fields)) shape(fields[key], [
6793
+ ...at,
6794
+ "fields",
6795
+ key
6796
+ ]);
6797
+ shape(spec.rest, [...at, "rest"]);
6798
+ }
6799
+ way.delete(spec);
6800
+ };
6801
+ shape(kind.parts, ["parts"]);
6802
+ });
6803
+ const table = domains ?? {};
6804
+ for (const name of Object.keys(table)) {
6805
+ if (name === "unknown" || name === "never") continue;
6806
+ const owner = {
6807
+ kind: [],
6808
+ domain: name
6809
+ };
6810
+ const domain = domainOf(name, domains);
6811
+ if (domain === void 0) {
6812
+ add(owner, ["is"], `The domain ${name} has no test is. Each use of the name ${name} reads as unknown.`);
6706
6813
  continue;
6707
6814
  }
6708
- const { doc, kind, split } = read;
6709
- const here = new Visit(item.place, item.at, doc, read.declared, item.depth, item.names, item.later, item.slot, item.parent, kind, read.typePath, item.address ? true : void 0, item.caps, item.bound, item.expect);
6710
- if (visit(here) === "skip" || kind === void 0) continue;
6711
- const base = read.declared ? item.at : {
6712
- up: item.at,
6713
- keys: ["value"]
6815
+ const under = domain.under;
6816
+ if (Array.isArray(under)) under.forEach((parent, index) => {
6817
+ if (parent === "unknown" || parent === "never") return;
6818
+ if (typeof parent !== "string" || domainOf(parent, domains) === void 0) add(owner, ["under", index], `The parent ${String(parent)} of the domain ${name} is not a domain of the machine.`);
6819
+ });
6820
+ const steps = domain.steps;
6821
+ if (typeof steps === "object" && steps !== null) for (const key of Object.keys(steps)) examine(owner, ["steps", key], steps[key], `type of the step ${key} of the domain ${name}`);
6822
+ }
6823
+ for (const name of Object.keys(machine.evaluators)) {
6824
+ const declared = ruleOf(machine, name)?.declared;
6825
+ if (typeof declared !== "function") continue;
6826
+ const owner = {
6827
+ kind: [],
6828
+ evaluator: name
6714
6829
  };
6715
- if (!split.ok) {
6716
- options.problem?.({
6717
- place: keysOf(item.place),
6718
- at: keysOf({
6719
- up: base,
6720
- keys: split.at
6721
- }),
6722
- code: "#VALUE!",
6723
- reason: split.reason
6724
- });
6830
+ let list;
6831
+ try {
6832
+ list = declared();
6833
+ } catch (error) {
6834
+ add(owner, [], `The type rule of ${name} fails: ${message(error)}`);
6725
6835
  continue;
6726
6836
  }
6727
- const { sees, later } = scopesOf(kind.scope, doc.value, split.parts);
6728
- for (let index = split.parts.length - 1; index >= 0; index -= 1) {
6729
- const slot = split.parts[index];
6730
- const extra = sees[index] ?? [];
6731
- const hidden = later[index] ?? [];
6732
- stack.push({
6733
- value: slot.item,
6734
- place: slot.path.length === 0 ? item.place : {
6735
- up: item.place,
6736
- keys: slot.path
6737
- },
6738
- at: slot.path.length === 0 ? base : {
6739
- up: base,
6740
- keys: slot.path
6741
- },
6742
- declared: slot.of,
6743
- depth: item.depth + 1,
6744
- names: extra.length === 0 ? item.names : /* @__PURE__ */ new Set([...item.names, ...extra]),
6745
- later: hidden.length === 0 ? item.later : /* @__PURE__ */ new Set([...item.later, ...hidden]),
6746
- address: slot.address === true,
6747
- slot: slot.path,
6748
- parent: here,
6749
- caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : partCaps(kind.caps, slot.path, item.caps),
6750
- bound: extra,
6751
- expect: slot.expect
6752
- });
6753
- }
6837
+ for (const item of list) if ("problem" in item) add(owner, item.at, item.problem);
6838
+ else examine(owner, item.at, item.type, item.what);
6754
6839
  }
6840
+ return out;
6755
6841
  }
6842
+ // src/facts.ts
6843
+ /** The lazy rules that cover each part: the rules of a document whose evaluator the contract does not describe. */
6844
+ const EACH$2 = "each";
6845
+ /** An empty list. One frozen list serves each empty list of the facts, thus a store of many facts keeps less (PLAN.LEAN). */
6846
+ const NONE = /* @__PURE__ */ Object.freeze([]);
6756
6847
  /**
6757
- * This function finds each reference of a document: each document of the type `ref` that a walk reaches. A
6758
- * reference to a name that a kind around it binds is not free. The others are what the document reads from
6759
- * outside: its dependencies. When the kind `ref` has parts, the walk also finds the references in its step documents.
6760
- *
6761
- * @param world - The world of the kinds.
6762
- * @param doc - The document, as JSON.
6763
- * @param options - The type of a bare root value. The names of the host do not change the result.
6764
- * @returns The references, in the order of the document.
6765
- */
6766
- function refsOf(world, doc, options = {}) {
6767
- const out = [];
6768
- walk(world, doc, (v) => {
6769
- if (!isRef(v.doc)) return void 0;
6770
- const path = v.doc.value;
6771
- const root = typeof path[0] === "string" ? path[0] : "";
6772
- const first = path[1];
6773
- const use = {
6774
- path,
6775
- root,
6776
- free: !(root === "names" && isKey(first) && v.names.has(String(first))),
6777
- address: v.address === true
6778
- };
6779
- Object.defineProperty(use, "place", {
6780
- enumerable: true,
6781
- get: () => v.place
6782
- });
6783
- Object.defineProperty(use, "at", {
6784
- enumerable: true,
6785
- get: () => v.at
6786
- });
6787
- Object.defineProperty(use, "visit", {
6788
- enumerable: false,
6789
- value: v
6790
- });
6791
- out.push(use);
6792
- }, options.names === void 0 ? options : withoutNames(options));
6793
- return out;
6794
- }
6795
- function setAt(value, path, next) {
6796
- if (path.length === 0) return next;
6797
- const [key, ...rest] = path;
6798
- if (Array.isArray(value)) {
6799
- const copy = [...value];
6800
- copy[Number(key)] = setAt(value[Number(key)], rest, next);
6801
- return copy;
6802
- }
6803
- const record = isRecord(value) ? value : {};
6804
- const copy = {};
6805
- for (const name of Object.keys(record)) Object.defineProperty(copy, name, {
6806
- value: record[name],
6807
- enumerable: true,
6808
- writable: true,
6809
- configurable: true
6810
- });
6811
- Object.defineProperty(copy, String(key), {
6812
- value: setAt(record[String(key)], rest, next),
6813
- enumerable: true,
6814
- writable: true,
6815
- configurable: true
6816
- });
6817
- return copy;
6818
- }
6819
- /**
6820
- * This function changes the free references of a document. The document is not changed: the function gives a new
6821
- * document that shares each part without a change.
6822
- *
6823
- * @param world - The world of the kinds.
6824
- * @param doc - The document, as JSON.
6825
- * @param change - The function that gives the new document of a reference, or `undefined` to keep it.
6826
- * @param options - The type of a bare root value, and the names that the host binds at the root.
6827
- * @returns The new document.
6828
- */
6829
- function mapRefs(world, doc, change, options = {}) {
6830
- let out = doc;
6831
- for (const use of refsOf(world, doc, options)) {
6832
- if (!use.free) continue;
6833
- const next = change(use);
6834
- if (next !== void 0) out = setAt(out, use.at, next);
6835
- }
6836
- return out;
6837
- }
6838
- /** The least authority: the capability `[]` permits each effect (CAP.KEYS). */
6839
- const EACH$2 = /* @__PURE__ */ Object.freeze([[]]);
6840
- /** No declared effect. One list serves each visit without effects. */
6841
- const NO_EFFECTS = /* @__PURE__ */ Object.freeze([]);
6842
- /**
6843
- * This function gives the effects that the contract of the kind of a visit declares for a verb, as keys
6844
- * (FACTS.EFFECTS, VERB.EFFECTS). The text `"type"` gives the type of the document after each alias. A visit without a
6845
- * kind declares no effect. `check`, `factsOf` and `effectsOf` read the declarations with this one function (D27).
6846
- *
6847
- * @param v - The visit.
6848
- * @param verb - The verb. The default is `eval`. A kind without a declaration for the verb gives no effect.
6849
- * @returns The keys of each declared effect, in the order of the contract.
6848
+ * This function gives a list of the facts with no free room. A list that grows by `push` keeps room for more items,
6849
+ * thus a copy of a short list is smaller.
6850
6850
  */
6851
- function declaredEffects(v, verb = "eval") {
6852
- return verbDeclared(v, verb) ?? NO_EFFECTS;
6851
+ function tight(list) {
6852
+ return list.length === 0 ? NONE : list.slice();
6853
6853
  }
6854
6854
  /**
6855
- * This function gives the effects that the contract of the kind of a visit declares for a verb, as keys. The result
6856
- * is `undefined` when the contract has no declaration for the verb (D49). A visit without a kind declares no effect
6857
- * for `eval` and no declaration for another verb.
6855
+ * This function gives the name of the evaluator that the ladder finds for a verb (VERB.LADDER). It also tells if
6856
+ * the contract of the kind describes that code. The contract describes the code of its kind for its verb `contract`.
6857
+ * An own entry for another evaluator has code that the contract does not describe.
6858
6858
  */
6859
- function verbDeclared(v, verb) {
6860
- if (v.kind === void 0) return verb === "eval" ? NO_EFFECTS : void 0;
6861
- const effects = effectsOfVerb(v.kind, verb);
6862
- if (effects === void 0) return void 0;
6863
- if (effects.length === 0) return NO_EFFECTS;
6864
- return effects === "type" ? [v.typePath ?? []] : effects.map((kind) => kind.split("."));
6859
+ function codeOf(world, own, kind, verb, contract) {
6860
+ const found = answerOf(world, own, kind, verb);
6861
+ if (verb !== contract) return {
6862
+ name: found?.name,
6863
+ described: false
6864
+ };
6865
+ if (found?.rung !== "own") return {
6866
+ name: found?.name,
6867
+ described: true
6868
+ };
6869
+ return {
6870
+ name: found.name,
6871
+ described: found.name === answerOf(world, void 0, kind, verb)?.name
6872
+ };
6865
6873
  }
6866
- /**
6867
- * This function gives the rule of a machine for an effect, for the static kit (CAP.PERMITS). The rule is the hook
6868
- * `permits` of the machine, as in a run, or else the function `permits`. A check has no values, thus the hook gets a
6869
- * context with the capabilities of the document and the world of the machine. Its names, its self and its event are
6870
- * empty.
6871
- *
6872
- * @param machine - The machine.
6873
- * @returns The rule. It gets the capabilities of a document and the keys of an effect.
6874
- */
6875
- function permitsOf(machine) {
6876
- const hook = machine.permits;
6877
- if (hook === void 0) return permits;
6878
- let base;
6879
- return (caps, kind) => hook(caps, kind, {
6880
- ...base ??= context({ world: worldThing(machine.world) }),
6881
- caps
6882
- });
6874
+ /** This function gives the position of a part among the parts that a rule covers, by the split of its document. */
6875
+ function positionOf(above, parent, rule, slot) {
6876
+ const positions = above.positions ??= /* @__PURE__ */ new Map();
6877
+ let table = positions.get(rule);
6878
+ if (table === void 0) {
6879
+ table = /* @__PURE__ */ new Map();
6880
+ const split = splitParts(parent.kind?.parts, parent.doc.value);
6881
+ let count = 0;
6882
+ for (const part of split.ok ? split.parts : []) {
6883
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
6884
+ table.set(JSON.stringify(part.path), count);
6885
+ count += 1;
6886
+ }
6887
+ positions.set(rule, table);
6888
+ }
6889
+ return table.get(JSON.stringify(slot)) ?? 0;
6883
6890
  }
6884
- /**
6885
- * This function gives the reason of a `#CAP!`. When a kind around the document narrowed the capabilities, the
6886
- * reason names the nearest such kind.
6887
- */
6888
- function capReason(v, kind, allowed) {
6889
- const text = kind.join(".");
6890
- for (let up = v.parent; up !== void 0; up = up.parent) if (up.caps !== void 0 && allowed(up.caps, kind)) return `The capabilities do not permit the effect ${text} here. The kind ${typeName(up.doc.type)} around it narrows them for its parts.`;
6891
- return `The capabilities do not permit the effect ${text}.`;
6891
+ /** This function tells if the lazy rules of a document cover one of its parts. */
6892
+ function partLazy(above, parent, slot) {
6893
+ const rules = above.rules;
6894
+ if (rules === void 0) return false;
6895
+ if (rules === EACH$2) return true;
6896
+ for (const rule of rules) {
6897
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
6898
+ const after = rule.after ?? 0;
6899
+ if (after <= 0 || positionOf(above, parent, rule, slot) >= after) return true;
6900
+ }
6901
+ return false;
6892
6902
  }
6893
6903
  /**
6894
- * This function checks a document before an evaluation, by the contracts of its kinds. It finds the problems
6895
- * that an evaluation finds when it reaches them:
6896
- *
6897
- * - `#KIND?`: a kind that the world does not have.
6898
- * - `#NOEVAL`: no evaluator.
6899
- * - `#VALUE!`: a value without the shape of its kind.
6900
- * - `#PART?`: a value without a type.
6901
- * - `#DEPTH!`: too much nesting.
6902
- * - `#REF!` and `#STEP?`: a bad path.
6903
- * - `#NAME?`: a name that nothing binds. With the hook `known` of the machine, also a name that the language does not
6904
- * have, for example an operation.
6905
- * - `#CAP!`: an effect that the capabilities of its document do not permit. A kind around the document can narrow them.
6906
- * The hook `permits` of the machine decides, as in a run (CAP.PERMITS).
6907
- * - `#CALC!`: with the option `run`, a runner under a parent without a runner, when an effect of its runners can reach
6908
- * the host. Also a kind that declares effects and has no runner (RUN.CAN-WAIT). The issue has the place and the
6909
- * reason of the run.
6910
- * - `#TYPE!`: with the option `types`, a part whose type does not fit the type that its position needs (TYPE.CHECK).
6911
- * A run does not always fail there, thus a type issue is a static finding, not an error of a run.
6904
+ * This function gives the code of a document of a kind for the facts (FACTS.LAZY). `factsOf` and the graph of
6905
+ * attribute instances read the lazy rules with this one function (D107).
6912
6906
  *
6913
- * The check asks the ladder for the verb of the options, `eval` by default (VERB.CHECK). The shapes, the paths and the
6914
- * names follow the contracts, thus they are the same for each verb. The check tests the effects that each contract
6915
- * declares for the verb: `effects` for `eval`, and the entry of `verbEffects` for another verb (VERB.EFFECTS). A kind
6916
- * without a declaration for the verb gives no `#CAP!` and no `#CALC!` for an effect.
6917
- *
6918
- * @param machine - The world and the code of the evaluators.
6919
- * @param doc - The document, as JSON.
6920
- * @param options - The type of a bare root value, the names of the host, the capabilities, the verb, the types and the run.
6921
- * @returns The problems, in the order of the document. The type issues come after the other issues.
6922
- */
6923
- function check(machine, doc, options = {}) {
6924
- return options.types === true ? typeCheck(machine, doc, options).issues : checkAll(machine, doc, options, void 0);
6907
+ * @param machine - The world and the hook `facts`.
6908
+ * @param v - The visit of the document.
6909
+ * @param kind - The kind of the document.
6910
+ * @param verb - The verb whose code the facts describe.
6911
+ * @returns The answer of the hook and the lazy rules.
6912
+ */
6913
+ function codeFactsOf(machine, v, kind, verb) {
6914
+ const code = codeOf(machine.world, v.declared ? void 0 : v.doc.own, kind, verb, "eval");
6915
+ const answer = code.name === void 0 ? void 0 : machine.facts?.(v.typePath ?? [], code.name);
6916
+ return {
6917
+ described: code.described,
6918
+ answer,
6919
+ rules: code.described ? answer?.lazy ?? kind.lazy : answer?.lazy ?? EACH$2
6920
+ };
6925
6921
  }
6926
6922
  /**
6927
- * This function checks a document, and it also checks the value types (TYPE.CHECK, D25). It finds each issue of
6928
- * `check`. Then it synthesizes the type of each document from the types of its parts. It also checks each part
6929
- * against the type that its position needs. The type rule of the parent, the signature of an operation or the shape
6930
- * of the contract gives that type. A part with an issue gets the type `unknown`, thus one
6931
- * problem does not give a chain of issues.
6923
+ * This function gives the static facts of a document, for a schedule (R4 P2, D24). It walks the document one time,
6924
+ * by the contracts of its kinds:
6932
6925
  *
6933
- * A type issue has the code `#TYPE!`, the type that the position needs (`expected`) and the type that the check found
6934
- * (`found`). It is a static finding: the evaluation of the document does not change.
6926
+ * - `reads`: each free reference, with the root and the keys of its path. A read under a lazy part has the mark
6927
+ * `lazy`, for example a read in a branch of `if`. A read after a step document has `exact: false`. A kind that
6928
+ * declares `reads` adds a read of each of its roots at each document of the kind. The first document of a tree
6929
+ * kind also gets the lazy reads of the equations of its kind (FACTS.EQUATIONS). A read from `self` or from a name
6930
+ * of a rung is not one of them, because it is not free (READS.EQUATION).
6931
+ * - `side` and `effects`: from the contract of each kind, for the verb of the facts.
6932
+ * - `pure`: each kind declares `pure`, also in an equation, and the document has no effect and is not volatile.
6933
+ * - `volatile`: a kind, an operation or a step document declares `volatile`, or the host marks a read.
6935
6934
  *
6936
- * The option `rootTypes` gives the types of the roots and of the names of the host (TYPE.ROOTS). A reference then gets
6937
- * the type that its path reaches, and a field that a closed record does not have is a type issue (TYPE.CLOSED).
6935
+ * The hook `facts` of the machine answers for a name that a fallback kind covers, for example an operation. Its
6936
+ * answer wins over the contract of the kind. The contract of a kind does not describe the evaluator of an own
6937
+ * entry. Thus a document with an own entry for another evaluator is not pure, and each of its parts is lazy. The
6938
+ * hook can still answer for that evaluator.
6938
6939
  *
6939
- * @param machine - The world and the code of the evaluators, with their type rules.
6940
- * @param doc - The document, as JSON.
6941
- * @param options - The options of `check`, the type that the root must have and the types of the roots.
6942
- * @returns The type of the root, each issue, and the type of each document.
6943
- */
6944
- function typeCheck(machine, doc, options = {}) {
6945
- const nodes = [];
6946
- const issues = checkAll(machine, doc, options, nodes);
6947
- const pass = typePass(machine, nodes, options.verb ?? "eval", options.expect, options.rootTypes);
6948
- return {
6949
- type: pass.type,
6950
- issues: pass.issues.length === 0 ? issues : [...issues, ...pass.issues],
6951
- places: pass.places
6952
- };
6953
- }
6954
- /** This function tells if a table of verbs has an entry for a verb. */
6955
- function hasVerb(table, verb) {
6956
- return table !== void 0 && Object.hasOwn(table, verb);
6957
- }
6958
- /**
6959
- * This function checks the world of a machine before a document exists. It finds each kind that has no entry for a
6960
- * verb of the list, when the world has no default for that verb (STATIC.COVERAGE). A document of such a kind gets no
6961
- * evaluator for the verb, thus the check gives the same proof of coverage as a type system.
6940
+ * The option `verb` names the verb whose code the facts describe (FACTS.VERB). The marks of a contract describe the
6941
+ * code of `eval`, thus the rule of an own entry applies to each document for another verb. For another verb, the
6942
+ * effects are the effects that the entry of the verb in `verbEffects` declares (FACTS.VERB-EFFECTS, D111). A kind is
6943
+ * on the run side for that verb when its entry declares an effect (FACTS.VERB-SIDE). A kind without an entry for the
6944
+ * verb adds no effect, as in `check` (FACTS.VERB-UNDECLARED). Its code is still not pure without an answer of the hook.
6962
6945
  *
6963
- * The check visits each kind of each namespace, at each depth, and the fallback kind of each namespace and of the
6964
- * world. It does not follow an alias, because the kind of an alias has its own place. The check reads only the world.
6946
+ * A read is one resolution of its path. A reference that the resolution reaches and follows is a part of that read
6947
+ * (DEREF.COLLAPSE), not a separate read. The facts depend only on the document and the machine. Thus a host computes
6948
+ * them again only after an edit of the document or of the machine.
6965
6949
  *
6966
- * @param machine - The machine, for its world.
6967
- * @param verbs - The verbs that each kind of the language must answer, for example `eval`, `view` and `type`.
6968
- * @returns One issue for each kind and verb without an evaluator. The order is the order of the world, then the
6969
- * order of the verbs. The fallback kind of a namespace comes after the entries of that namespace.
6950
+ * @param machine - The world, the code and the hook `facts`.
6951
+ * @param doc - The document, as JSON.
6952
+ * @param options - The type of a bare root value, the verb and the volatile reads of the host.
6953
+ * @returns The facts.
6970
6954
  */
6971
- function checkWorld(machine, verbs) {
6955
+ function factsOf(machine, doc, options = {}) {
6972
6956
  const world = machine.world;
6973
- const open = verbs.filter((verb) => !hasVerb(world.defaults, verb));
6974
- const out = [];
6975
- if (open.length === 0) return out;
6976
- const visit = (kind, path, fallback) => {
6977
- const text = path.join(".");
6978
- const name = fallback ? path.length === 0 ? "the fallback kind of the world" : `the fallback kind of ${text}` : `the kind ${text}`;
6979
- for (const verb of open) {
6980
- if (hasVerb(kind.verbs, verb)) continue;
6981
- const reason = `${name.charAt(0).toUpperCase()}${name.slice(1)} has no entry for the verb ${verb}, and the world has no default for it.`;
6982
- out.push(fallback ? {
6983
- code: "#NOEVAL",
6984
- kind: path,
6985
- fallback: true,
6986
- verb,
6987
- reason
6988
- } : {
6989
- code: "#NOEVAL",
6990
- kind: path,
6991
- verb,
6992
- reason
6993
- });
6994
- }
6957
+ const hook = machine.facts;
6958
+ const reads = [];
6959
+ const effects = [];
6960
+ const above = /* @__PURE__ */ new Map();
6961
+ let side = "derive";
6962
+ let pure = true;
6963
+ let volatile = false;
6964
+ let size = 0;
6965
+ let seen;
6966
+ const note = (isPure, isVolatile) => {
6967
+ if (isPure !== true) pure = false;
6968
+ if (isVolatile === true) volatile = true;
6995
6969
  };
6996
- const way = /* @__PURE__ */ new Set();
6997
- const entries = (kinds, path) => {
6998
- for (const key of Object.keys(kinds)) {
6999
- const entry = kinds[key];
7000
- const here = [...path, key];
7001
- if (isKind(entry)) visit(entry, here, false);
7002
- else if (isNamespace(entry) && !way.has(entry)) {
7003
- way.add(entry);
7004
- entries(entry.kinds, here);
7005
- if (entry.fallback !== void 0) visit(entry.fallback, here, true);
7006
- way.delete(entry);
6970
+ const add = (read) => {
6971
+ reads.push(read);
6972
+ if (options.volatile?.(read) === true) volatile = true;
6973
+ };
6974
+ /**
6975
+ * This function walks a document. Without `node`, it walks the document of the facts. With `node`, it walks an
6976
+ * equation of a tree kind, and each read gets the place of that node: the first document of the kind.
6977
+ */
6978
+ const scan = (term, walkOptions, verb, node) => {
6979
+ walk(world, term, (v) => {
6980
+ if (node === void 0) size += 1;
6981
+ const up = v.parent === void 0 ? void 0 : above.get(v.parent);
6982
+ const lazy = node !== void 0 || up !== void 0 && v.parent !== void 0 && (up.lazy || partLazy(up, v.parent, v.slot));
6983
+ const place = node ?? v;
6984
+ const kind = v.kind;
6985
+ if (kind === void 0) {
6986
+ pure = false;
6987
+ above.set(v, {
6988
+ lazy,
6989
+ rules: void 0
6990
+ });
6991
+ return;
7007
6992
  }
7008
- }
6993
+ const { described, answer, rules } = codeFactsOf(machine, v, kind, verb);
6994
+ above.set(v, {
6995
+ lazy,
6996
+ rules
6997
+ });
6998
+ let roots;
6999
+ if (described) {
7000
+ note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
7001
+ roots = answer?.reads ?? kind.reads;
7002
+ } else {
7003
+ note(answer?.pure, answer?.volatile);
7004
+ roots = answer?.reads;
7005
+ }
7006
+ for (const root of roots ?? NONE) {
7007
+ if (node !== void 0 && root === "self") continue;
7008
+ add({
7009
+ root,
7010
+ keys: NONE,
7011
+ exact: true,
7012
+ lazy,
7013
+ address: false,
7014
+ path: [root],
7015
+ place: tight(place.place),
7016
+ at: tight(place.at)
7017
+ });
7018
+ }
7019
+ const declared = declaredEffects(v, verb);
7020
+ if (verb === "eval" ? kind.side === "run" : declared.length > 0) {
7021
+ if (node === void 0) side = "run";
7022
+ else pure = false;
7023
+ }
7024
+ for (const keys of declared) {
7025
+ if (node !== void 0) {
7026
+ pure = false;
7027
+ continue;
7028
+ }
7029
+ const text = keys.join(".");
7030
+ if (!effects.includes(text)) effects.push(text);
7031
+ }
7032
+ if (kind.tree !== void 0 && !(seen ??= /* @__PURE__ */ new Set()).has(kind)) {
7033
+ seen.add(kind);
7034
+ const of = equationType(kind);
7035
+ for (const { term: equation, names } of equationsOf(kind)) scan(equation, of === void 0 ? { names } : {
7036
+ names,
7037
+ declaredType: of
7038
+ }, "eval", place);
7039
+ }
7040
+ if (!isRef(v.doc)) return void 0;
7041
+ const path = v.doc.value;
7042
+ const root = path[0];
7043
+ if (typeof root !== "string" || !ROOTS.includes(root)) return void 0;
7044
+ if (node !== void 0 && root === "self") return void 0;
7045
+ let exact = true;
7046
+ const keys = [];
7047
+ for (let index = 1; index < path.length; index += 1) {
7048
+ const step = path[index];
7049
+ if (exact && isKey(step)) {
7050
+ keys.push(step);
7051
+ continue;
7052
+ }
7053
+ exact = false;
7054
+ const found = isEnvelope(step) ? lookupKind(world, step.type) : void 0;
7055
+ if (found?.ok !== true) {
7056
+ pure = false;
7057
+ continue;
7058
+ }
7059
+ const walker = codeOf(world, step.own, found.kind, "step", "step");
7060
+ const stepAnswer = walker.name === void 0 ? void 0 : hook?.(found.path, walker.name);
7061
+ if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
7062
+ else note(stepAnswer?.pure, stepAnswer?.volatile);
7063
+ }
7064
+ const first = path[1];
7065
+ if (root === "names" && isKey(first) && v.names.has(String(first))) return void 0;
7066
+ add({
7067
+ root,
7068
+ keys: tight(keys),
7069
+ exact,
7070
+ lazy,
7071
+ address: v.address === true,
7072
+ path,
7073
+ place: tight(place.place),
7074
+ at: tight(place.at)
7075
+ });
7076
+ }, walkOptions);
7077
+ };
7078
+ scan(doc, options.declaredType === void 0 ? {} : { declaredType: options.declaredType }, options.verb ?? "eval", void 0);
7079
+ return {
7080
+ reads: tight(reads),
7081
+ side,
7082
+ effects: tight(effects),
7083
+ pure: pure && !volatile && effects.length === 0 && side === "derive",
7084
+ volatile,
7085
+ size
7009
7086
  };
7010
- entries(world.kinds, []);
7011
- if (world.fallback !== void 0) visit(world.fallback, [], true);
7012
- return out;
7013
7087
  }
7014
- /** The names that an equation of `down` sees (TREE.DOWN). */
7015
- const DOWN_NAMES = /* @__PURE__ */ Object.freeze([
7016
- "child",
7017
- "index",
7018
- "prev"
7019
- ]);
7020
- /** The names that the term `combine` of a fold sees (TREE.FOLD). */
7021
- const FOLD_NAMES = /* @__PURE__ */ Object.freeze(["acc", "item"]);
7022
- /**
7023
- * This function gives each equation of the tree contract of a kind, with the names that it sees (D42). An equation of
7024
- * `equations`, a `unit` and a `default` see no names. `check` and `factsOf` read the equations with this one function.
7025
- */
7026
- function equationsOf(kind) {
7027
- const tree = kind.tree;
7028
- if (tree === void 0) return [];
7029
- const out = [];
7030
- for (const [name, term] of Object.entries(tree.equations ?? {})) out.push({
7031
- label: `tree.equations.${name}`,
7032
- term,
7033
- names: []
7034
- });
7035
- for (const [name, term] of Object.entries(tree.down ?? {})) out.push({
7036
- label: `tree.down.${name}`,
7037
- term,
7038
- names: DOWN_NAMES
7088
+ // src/graph.ts
7089
+ /** This function gives the indexed form of a graph, with the edges that the options keep. */
7090
+ function indexed(graph, options) {
7091
+ const eager = options.eager === true;
7092
+ const ids = [...graph.keys()];
7093
+ const count = ids.length;
7094
+ const numbers = /* @__PURE__ */ new Map();
7095
+ const sink = new Uint8Array(count);
7096
+ ids.forEach((id, index) => {
7097
+ numbers.set(id, index);
7098
+ if (graph.get(id)?.side === "run") sink[index] = 1;
7039
7099
  });
7040
- for (const [name, declared] of Object.entries(tree.attributes ?? {})) {
7041
- if (declared.fold !== void 0) {
7042
- out.push({
7043
- label: `tree.attributes.${name}.fold.unit`,
7044
- term: declared.fold.unit,
7045
- names: []
7046
- });
7047
- out.push({
7048
- label: `tree.attributes.${name}.fold.combine`,
7049
- term: declared.fold.combine,
7050
- names: FOLD_NAMES
7051
- });
7100
+ const start = new Int32Array(count + 2);
7101
+ const targets = [];
7102
+ let unknown = false;
7103
+ let from = 0;
7104
+ for (const node of graph.values()) {
7105
+ start[from] = targets.length;
7106
+ for (const edge of node.edges) {
7107
+ if (eager && edge.lazy) continue;
7108
+ if (edge.to === void 0) {
7109
+ if (eager) continue;
7110
+ unknown = true;
7111
+ targets.push(count);
7112
+ continue;
7113
+ }
7114
+ const to = numbers.get(edge.to);
7115
+ if (to !== void 0 && sink[to] === 0) targets.push(to);
7052
7116
  }
7053
- if (declared.default !== void 0) out.push({
7054
- label: `tree.attributes.${name}.default`,
7055
- term: declared.default,
7056
- names: []
7057
- });
7117
+ from += 1;
7058
7118
  }
7059
- return out;
7060
- }
7061
- /**
7062
- * This function checks the equations of the tree contract of a kind, each with the names of its rung (TREE.DOWN-NAMES).
7063
- * An equation evaluates without capabilities, thus a check with capabilities gives it none. Each issue gets the place
7064
- * of the document of the kind, and its reason names the equation.
7065
- */
7066
- function equationIssues(machine, kind, kindText, options, seen) {
7067
- const of = equationType(kind);
7068
- const out = [];
7069
- for (const { label, term, names } of equationsOf(kind)) {
7070
- const inner = {
7071
- names,
7072
- ...of === void 0 ? {} : { declaredType: of },
7073
- ...options.caps === void 0 ? {} : { caps: [] }
7074
- };
7075
- for (const issue of checkAll(machine, term, inner, void 0, seen)) out.push({
7076
- code: issue.code,
7077
- place: [],
7078
- reason: `In the equation ${label} of the kind ${kindText}: ${issue.reason}`
7079
- });
7119
+ start[count] = targets.length;
7120
+ if (unknown) {
7121
+ for (let to = 0; to < count; to += 1) if (sink[to] === 0) targets.push(to);
7080
7122
  }
7081
- return out;
7123
+ start[count + 1] = targets.length;
7124
+ return {
7125
+ ids,
7126
+ size: unknown ? count + 1 : count,
7127
+ start,
7128
+ targets: Int32Array.from(targets),
7129
+ all: unknown ? count : -1
7130
+ };
7082
7131
  }
7083
7132
  /**
7084
- * This function finds the issues of `check`. With a list of nodes, it also records each document that it visits for
7085
- * the pass of types. It marks each document with an issue. The set `seen` holds the kinds whose equations the check
7086
- * walked, thus it walks the equations of each kind one time.
7133
+ * This function finds the strongly connected components with the algorithm of Tarjan. It keeps its own stack of
7134
+ * calls in two arrays, thus a long chain does not overflow the stack of the host. Each component comes after each
7135
+ * component that its nodes reach: the deepest component comes first.
7087
7136
  */
7088
- function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()) {
7089
- const issues = [];
7090
- const verb = options.verb ?? "eval";
7137
+ function strong(graph) {
7138
+ const { size, start, targets } = graph;
7139
+ const order = new Int32Array(size).fill(-1);
7140
+ const low = new Int32Array(size);
7141
+ const of = new Int32Array(size).fill(-1);
7142
+ const open = new Int32Array(size);
7143
+ const onOpen = new Uint8Array(size);
7144
+ const calls = new Int32Array(size);
7145
+ const next = new Int32Array(size);
7146
+ const list = [];
7147
+ let top = 0;
7148
+ let count = 0;
7149
+ const enter = (node, depth) => {
7150
+ order[node] = count;
7151
+ low[node] = count;
7152
+ count += 1;
7153
+ open[top] = node;
7154
+ top += 1;
7155
+ onOpen[node] = 1;
7156
+ calls[depth] = node;
7157
+ next[depth] = start[node];
7158
+ };
7159
+ for (let root = 0; root < size; root += 1) {
7160
+ if (order[root] !== -1) continue;
7161
+ enter(root, 0);
7162
+ let depth = 1;
7163
+ while (depth > 0) {
7164
+ const node = calls[depth - 1];
7165
+ const edge = next[depth - 1];
7166
+ if (edge < start[node + 1]) {
7167
+ next[depth - 1] = edge + 1;
7168
+ const to = targets[edge];
7169
+ if (order[to] === -1) {
7170
+ enter(to, depth);
7171
+ depth += 1;
7172
+ } else if (onOpen[to] === 1 && order[to] < low[node]) low[node] = order[to];
7173
+ continue;
7174
+ }
7175
+ depth -= 1;
7176
+ if (low[node] === order[node]) {
7177
+ const members = [];
7178
+ let member;
7179
+ do {
7180
+ top -= 1;
7181
+ member = open[top];
7182
+ onOpen[member] = 0;
7183
+ of[member] = list.length;
7184
+ members.push(member);
7185
+ } while (member !== node);
7186
+ list.push(members.sort((a, b) => a - b));
7187
+ }
7188
+ if (depth > 0) {
7189
+ const reader = calls[depth - 1];
7190
+ if (low[node] < low[reader]) low[reader] = low[node];
7191
+ }
7192
+ }
7193
+ }
7194
+ return {
7195
+ of,
7196
+ list
7197
+ };
7198
+ }
7199
+ /** This function tells if a component has a cycle: two or more nodes, or one node with an edge to itself. */
7200
+ function cyclic(graph, members) {
7201
+ if (members.length > 1) return true;
7202
+ const node = members[0];
7203
+ for (let edge = graph.start[node]; edge < graph.start[node + 1]; edge += 1) if (graph.targets[edge] === node) return true;
7204
+ return false;
7205
+ }
7206
+ /** This function gives the names of the nodes of a component, without the node `all`. */
7207
+ function named$1(graph, members) {
7208
+ const out = [];
7209
+ for (const member of members) if (member !== graph.all) out.push(graph.ids[member]);
7210
+ return out;
7211
+ }
7212
+ /** This function gives the height of each component, in the order of `strong`. The node `all` adds no height. */
7213
+ function heightsOf(graph, found) {
7214
+ const { start, targets } = graph;
7215
+ const heights = new Int32Array(found.list.length);
7216
+ found.list.forEach((members, component) => {
7217
+ let highest = -1;
7218
+ let real = false;
7219
+ for (const node of members) {
7220
+ if (node !== graph.all) real = true;
7221
+ for (let edge = start[node]; edge < start[node + 1]; edge += 1) {
7222
+ const other = found.of[targets[edge]];
7223
+ if (other !== component && heights[other] > highest) highest = heights[other];
7224
+ }
7225
+ }
7226
+ heights[component] = real ? highest + 1 : highest;
7227
+ });
7228
+ return heights;
7229
+ }
7230
+ /**
7231
+ * This function gives the strongly connected components of a graph of nodes (GRAPH.SCC), with the algorithm of
7232
+ * Tarjan. It keeps its own stack, thus a chain of 100000 nodes does not overflow the stack of the host.
7233
+ *
7234
+ * - Each component comes after each component that it reads: the deepest component comes first.
7235
+ * - A node that is on no cycle is a component of one node.
7236
+ * - The nodes of a component are in the order of the graph.
7237
+ *
7238
+ * @param graph - The nodes, each with its edges.
7239
+ * @param options - The option `eager` keeps only the eager edges with a target node.
7240
+ * @returns The components, deepest first.
7241
+ */
7242
+ function components(graph, options = {}) {
7243
+ const index = indexed(graph, options);
7244
+ const out = [];
7245
+ for (const members of strong(index).list) {
7246
+ const names = named$1(index, members);
7247
+ if (names.length > 0) out.push(names);
7248
+ }
7249
+ return out;
7250
+ }
7251
+ /**
7252
+ * This function gives the height of each node: the order of a push schedule (GRAPH.ORDER). A schedule that evaluates
7253
+ * the nodes from the lowest height up evaluates each node after each node that it reads, except on a cycle.
7254
+ *
7255
+ * - A node that reads no node outside its component has the height 0.
7256
+ * - Each other node is one higher than the highest node that it reads outside its component.
7257
+ * - The nodes of one component have one height.
7258
+ * - An edge without a target reads each node that is not a sink (GRAPH.UNKNOWN).
7259
+ *
7260
+ * @param graph - The nodes, each with its edges.
7261
+ * @param options - The option `eager` keeps only the eager edges with a target node.
7262
+ * @returns The height of each node, in the order of the graph.
7263
+ */
7264
+ function heights(graph, options = {}) {
7265
+ const index = indexed(graph, options);
7266
+ const found = strong(index);
7267
+ const levels = heightsOf(index, found);
7268
+ const out = /* @__PURE__ */ new Map();
7269
+ index.ids.forEach((id, node) => out.set(id, levels[found.of[node]]));
7270
+ return out;
7271
+ }
7272
+ /**
7273
+ * This function puts the nodes in layers by their heights, in linear time (GRAPH.LAYERS). The first layer has the
7274
+ * height 0. Two nodes of one layer read each other only inside one component. Thus a push schedule can evaluate the
7275
+ * components of one layer at the same time.
7276
+ *
7277
+ * @param graph - The nodes, each with its edges.
7278
+ * @param options - The option `eager` keeps only the eager edges with a target node.
7279
+ * @returns The layers, from the height 0 up. Each layer keeps the order of the graph.
7280
+ */
7281
+ function nodeLayers(graph, options = {}) {
7282
+ const out = [];
7283
+ for (const [id, height] of heights(graph, options)) {
7284
+ while (out.length <= height) out.push([]);
7285
+ out[height]?.push(id);
7286
+ }
7287
+ return out;
7288
+ }
7289
+ /**
7290
+ * This function gives the nodes that a set of observed nodes needs (GRAPH.NECESSARY). These are the observed nodes,
7291
+ * and each node with a path of edges from them. A push schedule evaluates only these nodes. An observed name that is
7292
+ * not a node of the graph adds nothing.
7293
+ *
7294
+ * @param graph - The nodes, each with its edges.
7295
+ * @param observed - The nodes that the host shows or reads.
7296
+ * @param options - The option `eager` keeps only the eager edges with a target node.
7297
+ * @returns The necessary nodes, in the order of the graph.
7298
+ */
7299
+ function necessary(graph, observed, options = {}) {
7300
+ const index = indexed(graph, options);
7301
+ const numbers = /* @__PURE__ */ new Map();
7302
+ index.ids.forEach((id, node) => numbers.set(id, node));
7303
+ const seen = new Uint8Array(index.size);
7304
+ const work = [];
7305
+ for (const id of observed) {
7306
+ const node = numbers.get(id);
7307
+ if (node === void 0 || seen[node] === 1) continue;
7308
+ seen[node] = 1;
7309
+ work.push(node);
7310
+ }
7311
+ while (work.length > 0) {
7312
+ const node = work.pop();
7313
+ for (let edge = index.start[node]; edge < index.start[node + 1]; edge += 1) {
7314
+ const to = index.targets[edge];
7315
+ if (seen[to] === 1) continue;
7316
+ seen[to] = 1;
7317
+ work.push(to);
7318
+ }
7319
+ }
7320
+ const out = /* @__PURE__ */ new Set();
7321
+ index.ids.forEach((id, node) => {
7322
+ if (seen[node] === 1) out.add(id);
7323
+ });
7324
+ return out;
7325
+ }
7326
+ /**
7327
+ * This function gives the static cycles of a graph (GRAPH.CYCLE): each component with two or more nodes, and each
7328
+ * node with an edge to itself. A cycle of the eager edges with a target is certain, and `check` or a host can report
7329
+ * it before a run. Another cycle is possible: an evaluation can skip a lazy read.
7330
+ *
7331
+ * - A component of all the edges that is also a component of the eager edges is one certain cycle.
7332
+ * - Each other component of all the edges is one possible cycle, and each certain cycle in it comes after it.
7333
+ * - A read can still fail before it occurs. Thus the demand of D31, not a static cycle, gives the value of each node.
7334
+ *
7335
+ * @param graph - The nodes, each with its edges.
7336
+ * @returns The cycles, deepest first.
7337
+ */
7338
+ function cycles(graph) {
7339
+ const every = indexed(graph, {});
7340
+ const found = strong(every);
7341
+ const eager = indexed(graph, { eager: true });
7342
+ const inside = /* @__PURE__ */ new Map();
7343
+ for (const members of strong(eager).list) {
7344
+ if (!cyclic(eager, members)) continue;
7345
+ const component = found.of[members[0]];
7346
+ const list = inside.get(component);
7347
+ if (list === void 0) inside.set(component, [members]);
7348
+ else list.push(members);
7349
+ }
7350
+ const out = [];
7351
+ found.list.forEach((members, component) => {
7352
+ if (!cyclic(every, members)) return;
7353
+ const nodes = named$1(every, members);
7354
+ const certain = inside.get(component) ?? [];
7355
+ if (certain.length === 1 && certain[0]?.length === nodes.length) {
7356
+ out.push({
7357
+ nodes,
7358
+ certain: true
7359
+ });
7360
+ return;
7361
+ }
7362
+ out.push({
7363
+ nodes,
7364
+ certain: false
7365
+ });
7366
+ for (const part of certain) out.push({
7367
+ nodes: named$1(eager, part),
7368
+ certain: true
7369
+ });
7370
+ });
7371
+ return out;
7372
+ }
7373
+ /**
7374
+ * This function gives the nodes that a demand of a node needs first, deepest first (SCHED.LONG-CHAIN). It follows the
7375
+ * eager edges with a target from the node, with its own stack. Each node comes after each node that it reads, except
7376
+ * on a cycle, as in an order by heights. The walk costs only the nodes that it enters.
7377
+ *
7378
+ * @param from - The node of the demand. It is not in the answer.
7379
+ * @param edgesOf - This function gives the edges of a node, or `undefined` for a node that the walk does not enter.
7380
+ * @returns The nodes, deepest first.
7381
+ */
7382
+ function deepestFirst(from, edgesOf) {
7383
+ const out = [];
7384
+ const first = edgesOf(from);
7385
+ if (first === void 0) return out;
7386
+ const seen = /* @__PURE__ */ new Set([from]);
7387
+ const nodes = [from];
7388
+ const lists = [first];
7389
+ const positions = [0];
7390
+ while (nodes.length > 0) {
7391
+ const top = nodes.length - 1;
7392
+ const edges = lists[top];
7393
+ let position = positions[top];
7394
+ let entered = false;
7395
+ while (position < edges.length) {
7396
+ const edge = edges[position];
7397
+ position += 1;
7398
+ const to = edge.to;
7399
+ if (edge.lazy || to === void 0 || seen.has(to)) continue;
7400
+ seen.add(to);
7401
+ const more = edgesOf(to);
7402
+ if (more === void 0) continue;
7403
+ positions[top] = position;
7404
+ nodes.push(to);
7405
+ lists.push(more);
7406
+ positions.push(0);
7407
+ entered = true;
7408
+ break;
7409
+ }
7410
+ if (entered) continue;
7411
+ const done = nodes.pop();
7412
+ lists.pop();
7413
+ positions.pop();
7414
+ if (nodes.length > 0) out.push(done);
7415
+ }
7416
+ return out;
7417
+ }
7418
+ // src/instances.ts
7419
+ /**
7420
+ * This function gives the name of a vertex of the graph of attribute instances. The name is the JSON text of the
7421
+ * place of the node, with the name of the attribute after it.
7422
+ *
7423
+ * @param place - The place of the document of the node.
7424
+ * @param attribute - The name of the attribute.
7425
+ * @returns The name of the vertex.
7426
+ */
7427
+ function attributeVertexId(place, attribute) {
7428
+ return JSON.stringify([...place, attribute]);
7429
+ }
7430
+ /** The standard code whose value is the plain data of its document. */
7431
+ const DATA$1 = /* @__PURE__ */ new Set([
7432
+ "data.number",
7433
+ "data.text",
7434
+ "data.bool"
7435
+ ]);
7436
+ /** The standard code of a list. Its value holds the value of each item, in the order of the items. */
7437
+ const LIST$1 = "list.all";
7438
+ /** The self of the root of a walk: the self of the context, outside each tree of the document. */
7439
+ const OUTSIDE = {
7440
+ kind: { verbs: {} },
7441
+ text: "",
7442
+ own: void 0,
7443
+ parent: void 0
7444
+ };
7445
+ /** The self of an equation, for the references of the equation. */
7446
+ const EQUATION_SELF = {
7447
+ kind: { verbs: {} },
7448
+ text: "",
7449
+ own: void 0,
7450
+ parent: void 0
7451
+ };
7452
+ const NO_BOUND = /* @__PURE__ */ new Set();
7453
+ /** This function gives the name of an own part from the slot of its document. */
7454
+ function slotKey(slot) {
7455
+ return slot.map(String).join(".");
7456
+ }
7457
+ /** This function gives the value of a document before the run. */
7458
+ function valueOf$1(info) {
7459
+ if (info === void 0) return "unknown";
7460
+ if (info.node !== void 0) return { node: info.node };
7461
+ if (info.evaluator === LIST$1) return { list: info };
7462
+ return info.evaluator !== void 0 && DATA$1.has(info.evaluator) ? "data" : "unknown";
7463
+ }
7464
+ /** This function tells if a table of a tree contract has its own entry for a name. */
7465
+ function hasOwnEntry(table, name) {
7466
+ return table !== void 0 && Object.hasOwn(table, name);
7467
+ }
7468
+ /** This function gives the vertex of an attribute of a node. A new vertex goes on the work list for its rungs. */
7469
+ function vertexOf(b, node, attribute) {
7470
+ const id = attributeVertexId(node.visit.place, attribute);
7471
+ if (!b.vertices.has(id)) {
7472
+ b.vertices.set(id, {
7473
+ id,
7474
+ place: node.visit.place,
7475
+ attribute,
7476
+ type: node.text
7477
+ });
7478
+ b.nodes.set(id, node);
7479
+ if (!node.parts.has(attribute)) b.work.push(id);
7480
+ }
7481
+ return id;
7482
+ }
7483
+ function edge(b, from, r, lazy = false) {
7484
+ b.edges.push({
7485
+ from,
7486
+ to: r.to,
7487
+ lazy: r.lazy || lazy,
7488
+ place: r.place
7489
+ });
7490
+ b.ats.push(r.at);
7491
+ }
7492
+ /** This function gives the items of a list document, in the order of their indices. */
7493
+ function itemsOf(list) {
7494
+ return [...list.items].sort(([x], [y]) => x - y).map(([, item]) => item);
7495
+ }
7496
+ /**
7497
+ * This function gives the attributes that the JSON of a value reads, in their order (TREE.RESULT). A node reads each
7498
+ * own part, with the JSON of each node in its value after it. A list gives the JSON of each item.
7499
+ */
7500
+ function jsonOrder(value, out, done) {
7501
+ if (typeof value !== "object") return;
7502
+ if ("list" in value) {
7503
+ for (const item of itemsOf(value.list)) jsonOrder(valueOf$1(item), out, done);
7504
+ return;
7505
+ }
7506
+ const node = value.node;
7507
+ if (done.has(node)) return;
7508
+ done.add(node);
7509
+ for (const key of node.own) {
7510
+ out.push([node, key]);
7511
+ jsonOrder(valueOf$1(node.parts.get(key)), out, done);
7512
+ }
7513
+ }
7514
+ /** This function adds the reads of the JSON of a value. */
7515
+ function jsonReads(b, value, r) {
7516
+ const order = [];
7517
+ jsonOrder(value, order, /* @__PURE__ */ new Set());
7518
+ for (const [node, key] of order) edge(b, vertexOf(b, node, key), r);
7519
+ }
7520
+ /** This function gives the node that a walker `nearest` with the key `parent` reaches before the run. */
7521
+ function nearestOf(start, data) {
7522
+ if ((isRecord(data) && typeof field(data, "follow") === "string" ? String(field(data, "follow")) : "parent") !== "parent") return "unknown";
7523
+ const wanted = isRecord(data) ? field(data, "type") : void 0;
7524
+ let at = isRecord(data) && field(data, "self") === true ? start : start.up;
7525
+ while (at !== null && at !== void 0) {
7526
+ if (at.text === wanted) return { node: at };
7527
+ at = at.up;
7528
+ }
7529
+ return at === null ? "outside" : "unknown";
7530
+ }
7531
+ /**
7532
+ * This function follows the steps of a path from a value, and it adds each read on the way (TREE.GRAPH). A step
7533
+ * `parent` goes to the parent node, and a step `type` gives data. Another key reads an attribute. A walker `nearest`
7534
+ * with the key `parent` depends only on the structure. A step after a value that only the run knows gives an edge with
7535
+ * an unknown source. A path that ends at a node reads the JSON of the node.
7536
+ */
7537
+ function follow(b, start, path, from, r) {
7538
+ let here = start;
7539
+ for (let index = from; index < path.length; index += 1) {
7540
+ const step = path[index];
7541
+ if (here === "unknown") {
7542
+ edge(b, void 0, r);
7543
+ return;
7544
+ }
7545
+ if (here === "data" || here === "outside") return;
7546
+ if ("list" in here) {
7547
+ if (!isKey(step)) {
7548
+ edge(b, void 0, r);
7549
+ return;
7550
+ }
7551
+ if (step === "length") {
7552
+ here = "data";
7553
+ continue;
7554
+ }
7555
+ const at = typeof step === "number" ? step : /^\d+$/.test(step) ? Number(step) : -1;
7556
+ const item = here.list.items.get(at);
7557
+ if (item === void 0) return;
7558
+ here = valueOf$1(item);
7559
+ continue;
7560
+ }
7561
+ const node = here.node;
7562
+ if (isKey(step)) {
7563
+ const key = String(step);
7564
+ if (key === "parent") here = node.up === null ? "outside" : node.up === void 0 ? "unknown" : { node: node.up };
7565
+ else if (isStructural(key)) here = "data";
7566
+ else {
7567
+ edge(b, vertexOf(b, node, key), r);
7568
+ here = valueOf$1(node.parts.get(key));
7569
+ }
7570
+ continue;
7571
+ }
7572
+ if (walkerOf(b.machine, step) !== STD_WALKERS["walk.nearest"]) {
7573
+ edge(b, void 0, r);
7574
+ return;
7575
+ }
7576
+ here = nearestOf(node, isRecord(step) ? field(step, "value") : void 0);
7577
+ }
7578
+ if (typeof here === "object" && "node" in here) jsonReads(b, here, r);
7579
+ }
7580
+ /**
7581
+ * This function gives the references of an equation of a kind, with the self and the lazy mark of each (D107). It walks
7582
+ * the equation with the rules of `check`, thus a reference keeps the self of the equation only through standard code.
7583
+ */
7584
+ function termRefs(b, kind, label, term) {
7585
+ let byLabel = b.terms.get(kind);
7586
+ if (byLabel === void 0) {
7587
+ byLabel = /* @__PURE__ */ new Map();
7588
+ b.terms.set(kind, byLabel);
7589
+ }
7590
+ const known = byLabel.get(label);
7591
+ if (known !== void 0) return known;
7592
+ const out = [];
7593
+ const of = equationType(kind);
7594
+ const selves = selvesOf(b.machine, "eval", EQUATION_SELF);
7595
+ const above = /* @__PURE__ */ new Map();
7596
+ walk(b.machine.world, term, (v) => {
7597
+ const answer = ask(b.machine.world, v.declared ? {} : v.doc, "eval", v.declared ? { declaredType: typeName(v.doc.type) } : {});
7598
+ if (answer.error === "unknown-kind") return "skip";
7599
+ const up = v.parent === void 0 ? void 0 : above.get(v.parent);
7600
+ const lazy = up !== void 0 && v.parent !== void 0 && (up.lazy || partLazy(up, v.parent, v.slot));
7601
+ above.set(v, {
7602
+ lazy,
7603
+ rules: v.kind === void 0 ? void 0 : codeFactsOf(b.machine, v, v.kind, "eval").rules
7604
+ });
7605
+ const { self } = selves.enter(v, answer.evaluator);
7606
+ const evaluator = answer.evaluator;
7607
+ if (evaluator === "ref.resolve" && isRef(v.doc)) {
7608
+ if (v.address !== true) out.push({
7609
+ path: v.doc.value,
7610
+ lazy,
7611
+ self: self === EQUATION_SELF,
7612
+ bound: v.names,
7613
+ opaque: false
7614
+ });
7615
+ } else if (self === EQUATION_SELF && evaluator !== "tree.node" && !keepsSelf(evaluator)) out.push({
7616
+ path: [],
7617
+ lazy,
7618
+ self: true,
7619
+ bound: NO_BOUND,
7620
+ opaque: true
7621
+ });
7622
+ }, of === void 0 ? {} : { declaredType: of });
7623
+ byLabel.set(label, out);
7624
+ return out;
7625
+ }
7626
+ /** This function adds the reads of an equation of a rung: self is a node, and the names of the rung have their values. */
7627
+ function termReads(b, refs, self, names, r) {
7628
+ for (const ref of refs) {
7629
+ const read = ref.lazy ? {
7630
+ ...r,
7631
+ lazy: true
7632
+ } : r;
7633
+ if (ref.opaque) {
7634
+ edge(b, void 0, read);
7635
+ continue;
7636
+ }
7637
+ const root = ref.path[0];
7638
+ if (root === "self") {
7639
+ if (ref.self) follow(b, { node: self }, ref.path, 1, read);
7640
+ else if (ref.path.length > 1) edge(b, void 0, read);
7641
+ continue;
7642
+ }
7643
+ if (root !== "names" || ref.path.length < 2) continue;
7644
+ const name = String(ref.path[1]);
7645
+ let start;
7646
+ if (ref.bound.has(name)) start = "unknown";
7647
+ else if (names?.child !== void 0 && name === "child") start = { node: names.child };
7648
+ else if (names?.prev !== void 0 && name === "prev") start = names.prev;
7649
+ else if (name === "index") start = "data";
7650
+ else if (name === "acc" || name === "item") start = "unknown";
7651
+ else continue;
7652
+ follow(b, start, ref.path, 2, read);
7653
+ }
7654
+ }
7655
+ /** This function gives the previous sibling of a node in the list `children` of its parent, before the run. */
7656
+ function prevOf(parent, child) {
7657
+ const list = parent.parts.get("children");
7658
+ if (list === void 0 || list.evaluator !== LIST$1) return "unknown";
7659
+ for (const [index, item] of list.items) {
7660
+ if (item.node !== child) continue;
7661
+ return index === 0 ? "data" : valueOf$1(list.items.get(index - 1));
7662
+ }
7663
+ return "data";
7664
+ }
7665
+ /**
7666
+ * This function adds the reads of the rungs of an attribute that is not an own part, in the order of the ladder
7667
+ * (TREE.LADDER). After a rung that can fail to answer, the reads of the later rungs are lazy.
7668
+ */
7669
+ function rungReads(b, id) {
7670
+ const node = b.nodes.get(id);
7671
+ const key = b.vertices.get(id).attribute;
7672
+ const tree = node.kind.tree;
7673
+ const r = {
7674
+ to: id,
7675
+ lazy: false,
7676
+ place: node.visit.place,
7677
+ at: node.visit.at
7678
+ };
7679
+ const equation = hasOwnEntry(tree?.equations, key) ? tree?.equations?.[key] : void 0;
7680
+ if (equation !== void 0) {
7681
+ termReads(b, termRefs(b, node.kind, `tree.equations.${key}`, equation), node, void 0, r);
7682
+ return;
7683
+ }
7684
+ let later = r;
7685
+ const up = node.up;
7686
+ if (up === void 0) {
7687
+ if (downNames(b.machine.world).has(key)) {
7688
+ edge(b, void 0, r);
7689
+ later = {
7690
+ ...r,
7691
+ lazy: true
7692
+ };
7693
+ }
7694
+ } else if (up !== null) {
7695
+ const down = hasOwnEntry(up.kind.tree?.down, key) ? up.kind.tree?.down?.[key] : void 0;
7696
+ if (down !== void 0) {
7697
+ edge(b, vertexOf(b, up, "children"), r);
7698
+ termReads(b, termRefs(b, up.kind, `tree.down.${key}`, down), up, {
7699
+ child: node,
7700
+ prev: prevOf(up, node)
7701
+ }, r);
7702
+ return;
7703
+ }
7704
+ }
7705
+ const declared = hasOwnEntry(tree?.attributes, key) ? tree?.attributes?.[key] : void 0;
7706
+ if (declared?.copy === true && up !== null) {
7707
+ edge(b, up === void 0 ? void 0 : vertexOf(b, up, key), later);
7708
+ later = {
7709
+ ...later,
7710
+ lazy: true
7711
+ };
7712
+ }
7713
+ const fold = declared?.fold;
7714
+ if (fold !== void 0) {
7715
+ termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.fold.unit`, fold.unit), node, void 0, later);
7716
+ edge(b, vertexOf(b, node, "children"), later);
7717
+ const children = valueOf$1(node.parts.get("children"));
7718
+ let combined = false;
7719
+ if (children === "unknown") edge(b, void 0, later);
7720
+ else if (typeof children === "object" && "list" in children) for (const item of itemsOf(children.list)) {
7721
+ const child = item.node;
7722
+ if (child === void 0) continue;
7723
+ edge(b, vertexOf(b, child, key), later);
7724
+ combined = true;
7725
+ }
7726
+ termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.fold.combine`, fold.combine), node, void 0, combined ? later : {
7727
+ ...later,
7728
+ lazy: true
7729
+ });
7730
+ return;
7731
+ }
7732
+ if (declared?.default !== void 0) termReads(b, termRefs(b, node.kind, `tree.attributes.${key}.default`, declared.default), node, void 0, later);
7733
+ }
7734
+ function build(machine, doc, declaredType) {
7735
+ const b = {
7736
+ machine,
7737
+ vertices: /* @__PURE__ */ new Map(),
7738
+ nodes: /* @__PURE__ */ new Map(),
7739
+ edges: [],
7740
+ ats: [],
7741
+ work: [],
7742
+ terms: /* @__PURE__ */ new Map()
7743
+ };
7744
+ const roots = [];
7745
+ const all = [];
7746
+ const reads = [];
7747
+ const states = /* @__PURE__ */ new Map();
7748
+ const nodes = /* @__PURE__ */ new Map();
7749
+ const selves = selvesOf(machine, "eval", OUTSIDE);
7750
+ walk(machine.world, doc, (v) => {
7751
+ const answer = ask(machine.world, v.declared ? {} : v.doc, "eval", v.declared ? { declaredType: typeName(v.doc.type) } : {});
7752
+ if (answer.error === "unknown-kind") return "skip";
7753
+ const evaluator = answer.evaluator;
7754
+ const parent = v.parent === void 0 ? void 0 : states.get(v.parent);
7755
+ const { self, node: seen } = selves.enter(v, evaluator);
7756
+ let owner;
7757
+ let lazy = false;
7758
+ if (parent?.info.node !== void 0) owner = {
7759
+ node: parent.info.node,
7760
+ key: slotKey(v.slot)
7761
+ };
7762
+ else if (parent !== void 0 && v.parent !== void 0) {
7763
+ owner = parent.owner;
7764
+ lazy = parent.lazy || partLazy(parent.above, v.parent, v.slot);
7765
+ }
7766
+ let node;
7767
+ if (seen !== void 0 && v.kind !== void 0) {
7768
+ const up = self === OUTSIDE ? null : self === void 0 ? void 0 : nodes.get(self);
7769
+ node = {
7770
+ visit: v,
7771
+ kind: v.kind,
7772
+ text: seen.text,
7773
+ own: [...seen.own ?? []],
7774
+ parts: /* @__PURE__ */ new Map(),
7775
+ up
7776
+ };
7777
+ nodes.set(seen, node);
7778
+ all.push(node);
7779
+ if (up === null && !lazy) roots.push(node);
7780
+ }
7781
+ const info = {
7782
+ visit: v,
7783
+ evaluator,
7784
+ node,
7785
+ items: /* @__PURE__ */ new Map()
7786
+ };
7787
+ if (parent?.info.node !== void 0) parent.info.node.parts.set(slotKey(v.slot), info);
7788
+ else if (parent?.info.evaluator === LIST$1 && v.slot.length === 1 && typeof v.slot[0] === "number") parent.info.items.set(v.slot[0], info);
7789
+ states.set(v, {
7790
+ info,
7791
+ owner,
7792
+ lazy,
7793
+ above: {
7794
+ lazy,
7795
+ rules: v.kind === void 0 ? void 0 : codeFactsOf(machine, v, v.kind, "eval").rules
7796
+ }
7797
+ });
7798
+ if (owner === void 0 || node !== void 0) return void 0;
7799
+ const value = self === OUTSIDE ? "outside" : self === void 0 ? "unknown" : { node: nodes.get(self) };
7800
+ if (evaluator === "ref.resolve" && isRef(v.doc)) {
7801
+ if (v.address !== true) reads.push({
7802
+ owner,
7803
+ v,
7804
+ lazy,
7805
+ self: value,
7806
+ opaque: false
7807
+ });
7808
+ } else if (value !== "unknown" && evaluator !== "ref.resolve" && !keepsSelf(evaluator)) reads.push({
7809
+ owner,
7810
+ v,
7811
+ lazy,
7812
+ self: value,
7813
+ opaque: true
7814
+ });
7815
+ }, declaredType === void 0 ? {} : { declaredType });
7816
+ for (const node of all) for (const key of node.own) vertexOf(b, node, key);
7817
+ for (const { owner, v, lazy, self, opaque } of reads) {
7818
+ const r = {
7819
+ to: vertexOf(b, owner.node, owner.key),
7820
+ lazy,
7821
+ place: v.place,
7822
+ at: v.at
7823
+ };
7824
+ if (opaque) {
7825
+ edge(b, void 0, r);
7826
+ continue;
7827
+ }
7828
+ const path = v.doc.value;
7829
+ const root = path[0];
7830
+ if (root === "self") {
7831
+ if (self === "unknown") edge(b, void 0, r);
7832
+ else follow(b, self, path, 1, r);
7833
+ } else if (root === "names" && path.length >= 2 && v.names.has(String(path[1]))) edge(b, void 0, r);
7834
+ }
7835
+ for (let next = b.work.shift(); next !== void 0; next = b.work.shift()) rungReads(b, next);
7836
+ return {
7837
+ b,
7838
+ roots
7839
+ };
7840
+ }
7841
+ /** This function gives the graph for `graph.ts`: each vertex with the vertices that it reads. */
7842
+ function nodeGraph(b) {
7843
+ const reads = /* @__PURE__ */ new Map();
7844
+ for (const id of b.vertices.keys()) reads.set(id, []);
7845
+ for (const e of b.edges) reads.get(e.to)?.push({
7846
+ to: e.from,
7847
+ lazy: e.lazy
7848
+ });
7849
+ return new Map([...reads].map(([id, edges]) => [id, { edges }]));
7850
+ }
7851
+ /**
7852
+ * This function gives the graph of attribute instances of a document (TREE.GRAPH, R3 P5, D107). It has one vertex for
7853
+ * each attribute of each node of the decorated tree. It has one edge for each read of the code of an attribute.
7854
+ *
7855
+ * - A path from `self` reads the attribute of the node. `self.parent` goes to the parent node.
7856
+ * - The step `nearest` with the key `parent` depends only on the structure, thus it goes to a node of the document.
7857
+ * - The rungs of the ladder read too: `names.prev` of `down` reads the previous sibling, and a fold reads each child.
7858
+ * - A read that depends on the value of an attribute gets an edge with an unknown source.
7859
+ *
7860
+ * The walk is the walk of `check`, with its rules for the self of each document (D106). The evaluator of the kernel
7861
+ * does not use the graph (D3).
7862
+ *
7863
+ * @param machine - The world and the code of the evaluators.
7864
+ * @param doc - The document, as JSON.
7865
+ * @param options - The type of a bare root value.
7866
+ * @returns The vertices, the edges, the graph for the analysis, the reads that only the run knows and the cycles.
7867
+ */
7868
+ function attributeGraph(machine, doc, options = {}) {
7869
+ const { b } = build(machine, doc, options.declaredType);
7870
+ const graph = nodeGraph(b);
7871
+ return {
7872
+ vertices: b.vertices,
7873
+ edges: b.edges,
7874
+ graph,
7875
+ unknown: b.edges.filter((e) => e.from === void 0),
7876
+ cycles: cycles(graph).map((cycle) => ({
7877
+ vertices: cycle.nodes,
7878
+ certain: cycle.certain
7879
+ }))
7880
+ };
7881
+ }
7882
+ function vertexText(vertex) {
7883
+ return `${vertex.attribute} of ${vertex.type} at [${vertex.place.join(", ")}]`;
7884
+ }
7885
+ /**
7886
+ * This function finds each certain cycle of the attributes of a document before a run (TREE.GRAPH-CYCLE, D107). A run
7887
+ * that gives a value reads each own part of each tree root, and each eager read of each attribute that it reads. Thus a
7888
+ * certain cycle that these reads reach always gives `#CYCLE!`. The issue gets the place of the read that closes the
7889
+ * cycle in the order of the run, and the reason of the run. A cycle through a lazy read or an unknown read is not an issue.
7890
+ *
7891
+ * @param machine - The world and the code of the evaluators.
7892
+ * @param doc - The document, as JSON.
7893
+ * @param options - The type of a bare root value.
7894
+ * @returns One issue for each certain cycle that the run reaches.
7895
+ */
7896
+ function cycleIssues(machine, doc, options) {
7897
+ const { b, roots } = build(machine, doc, options.declaredType);
7898
+ const graph = nodeGraph(b);
7899
+ const certain = /* @__PURE__ */ new Map();
7900
+ cycles(graph).forEach((cycle, index) => {
7901
+ if (cycle.certain) for (const id of cycle.nodes) certain.set(id, index);
7902
+ });
7903
+ if (certain.size === 0) return [];
7904
+ const eager = /* @__PURE__ */ new Map();
7905
+ b.edges.forEach((e, index) => {
7906
+ if (e.lazy || e.from === void 0) return;
7907
+ const list = eager.get(e.to);
7908
+ if (list === void 0) eager.set(e.to, [index]);
7909
+ else list.push(index);
7910
+ });
7911
+ const demands = [];
7912
+ const done = /* @__PURE__ */ new Set();
7913
+ for (const root of roots) jsonOrder({ node: root }, demands, done);
7914
+ const order = demands.map(([node, key]) => attributeVertexId(node.visit.place, key));
7915
+ const state = /* @__PURE__ */ new Map();
7916
+ const reported = /* @__PURE__ */ new Set();
7917
+ const out = [];
7918
+ for (const start of order) {
7919
+ if (state.has(start)) continue;
7920
+ const stack = [{
7921
+ id: start,
7922
+ next: 0
7923
+ }];
7924
+ state.set(start, "busy");
7925
+ while (stack.length > 0) {
7926
+ const top = stack[stack.length - 1];
7927
+ const list = eager.get(top.id) ?? [];
7928
+ if (top.next >= list.length) {
7929
+ state.set(top.id, "done");
7930
+ stack.pop();
7931
+ continue;
7932
+ }
7933
+ const index = list[top.next];
7934
+ top.next += 1;
7935
+ const e = b.edges[index];
7936
+ const from = e.from;
7937
+ const seen = state.get(from);
7938
+ if (seen === void 0) {
7939
+ state.set(from, "busy");
7940
+ stack.push({
7941
+ id: from,
7942
+ next: 0
7943
+ });
7944
+ continue;
7945
+ }
7946
+ if (seen === "done") continue;
7947
+ const cycle = certain.get(from);
7948
+ if (cycle === void 0 || reported.has(cycle)) continue;
7949
+ reported.add(cycle);
7950
+ const first = stack.findIndex((frame) => frame.id === from);
7951
+ const chain = [...stack.slice(first).map((frame) => frame.id), from].map((id) => vertexText(b.vertices.get(id)));
7952
+ out.push({
7953
+ code: "#CYCLE!",
7954
+ place: e.place,
7955
+ reason: `The attributes form a cycle: ${chain.join(" -> ")}.`,
7956
+ at: b.ats[index]
7957
+ });
7958
+ }
7959
+ }
7960
+ return out;
7961
+ }
7962
+ // src/static.ts
7963
+ /** 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. */
7964
+ const NO_NAMES = /* @__PURE__ */ new Set();
7965
+ /** This function gives the options of a walk without the names of the host. */
7966
+ function withoutNames(options) {
7967
+ const { names: _host, ...rest } = options;
7968
+ return rest;
7969
+ }
7970
+ /** This function gives the keys of a trail, from its start. It keeps the result in the trail. */
7971
+ function keysOf(trail) {
7972
+ if (trail === void 0) return [];
7973
+ if (trail.full !== void 0) return trail.full;
7974
+ const steps = [];
7975
+ let here = trail;
7976
+ while (here !== void 0 && here.full === void 0) {
7977
+ steps.push(here);
7978
+ here = here.up;
7979
+ }
7980
+ const keys = here?.full === void 0 ? [] : [...here.full];
7981
+ for (let index = steps.length - 1; index >= 0; index -= 1) for (const key of steps[index].keys) keys.push(key);
7982
+ trail.full = keys;
7983
+ return keys;
7984
+ }
7985
+ /** A visit with its paths as trails. It makes the keys of a path only when a reader asks for them. */
7986
+ var Visit = class {
7987
+ doc;
7988
+ declared;
7989
+ depth;
7990
+ names;
7991
+ later;
7992
+ slot;
7993
+ parent;
7994
+ kind;
7995
+ typePath;
7996
+ address;
7997
+ caps;
7998
+ #place;
7999
+ #at;
8000
+ #bound;
8001
+ #expect;
8002
+ constructor(place, at, doc, declared, depth, names, later, slot, parent, kind, typePath, address, caps, bound, expect) {
8003
+ this.doc = doc;
8004
+ this.declared = declared;
8005
+ this.depth = depth;
8006
+ this.names = names;
8007
+ this.later = later;
8008
+ this.slot = slot;
8009
+ this.parent = parent;
8010
+ this.kind = kind;
8011
+ this.typePath = typePath;
8012
+ this.address = address;
8013
+ this.caps = caps;
8014
+ this.#place = place;
8015
+ this.#at = at;
8016
+ this.#bound = bound;
8017
+ this.#expect = expect;
8018
+ }
8019
+ /** The names that the scope rules of the parent bind for this document. The check of types reads them. */
8020
+ get bound() {
8021
+ return this.#bound;
8022
+ }
8023
+ /** The type that the shape of the parent declares for this part. The check of types reads it. */
8024
+ get expect() {
8025
+ return this.#expect;
8026
+ }
8027
+ get place() {
8028
+ return keysOf(this.#place);
8029
+ }
8030
+ get at() {
8031
+ return keysOf(this.#at);
8032
+ }
8033
+ };
8034
+ /**
8035
+ * This function visits each document of a document: the root and each part at each depth, by the contracts of the
8036
+ * kinds. A part of a kind that the world does not have is not visited. With capabilities in the options, the walk
8037
+ * narrows them for each part by the rules of its kind, as a run does. The walk uses no stack of the host for the
8038
+ * depth, thus a deep document cannot overflow it. The time and the memory of a walk are linear in the size of the
8039
+ * document. A visit makes the keys of its place and of its path only when a reader asks for them.
8040
+ *
8041
+ * @param world - The world of the kinds.
8042
+ * @param doc - The document, as JSON.
8043
+ * @param visit - The function that gets each document. It gives `"skip"` to not visit the parts of a document.
8044
+ * @param options - The type of a bare root value, the names, the capabilities and a function for the problems.
8045
+ */
8046
+ function walk(world, doc, visit, options = {}) {
8047
+ const stack = [{
8048
+ value: doc,
8049
+ place: void 0,
8050
+ at: void 0,
8051
+ declared: options.declaredType,
8052
+ depth: 0,
8053
+ names: options.names === void 0 || options.names.length === 0 ? NO_NAMES : new Set(options.names),
8054
+ later: NO_NAMES,
8055
+ address: false,
8056
+ slot: [],
8057
+ parent: void 0,
8058
+ caps: options.caps,
8059
+ bound: [],
8060
+ expect: void 0
8061
+ }];
8062
+ while (stack.length > 0) {
8063
+ const item = stack.pop();
8064
+ const read = partsOf(world, item.value, item.declared);
8065
+ if (!read.ok) {
8066
+ options.problem?.({
8067
+ place: keysOf(item.place),
8068
+ at: keysOf(item.at),
8069
+ code: read.code,
8070
+ reason: read.reason
8071
+ });
8072
+ continue;
8073
+ }
8074
+ const { doc, kind, split } = read;
8075
+ const here = new Visit(item.place, item.at, doc, read.declared, item.depth, item.names, item.later, item.slot, item.parent, kind, read.typePath, item.address ? true : void 0, item.caps, item.bound, item.expect);
8076
+ if (visit(here) === "skip" || kind === void 0) continue;
8077
+ const base = read.declared ? item.at : {
8078
+ up: item.at,
8079
+ keys: ["value"]
8080
+ };
8081
+ if (!split.ok) {
8082
+ options.problem?.({
8083
+ place: keysOf(item.place),
8084
+ at: keysOf({
8085
+ up: base,
8086
+ keys: split.at
8087
+ }),
8088
+ code: "#VALUE!",
8089
+ reason: split.reason
8090
+ });
8091
+ continue;
8092
+ }
8093
+ const { sees, later } = scopesOf(kind.scope, doc.value, split.parts);
8094
+ for (let index = split.parts.length - 1; index >= 0; index -= 1) {
8095
+ const slot = split.parts[index];
8096
+ const extra = sees[index] ?? [];
8097
+ const hidden = later[index] ?? [];
8098
+ stack.push({
8099
+ value: slot.item,
8100
+ place: slot.path.length === 0 ? item.place : {
8101
+ up: item.place,
8102
+ keys: slot.path
8103
+ },
8104
+ at: slot.path.length === 0 ? base : {
8105
+ up: base,
8106
+ keys: slot.path
8107
+ },
8108
+ declared: slot.of,
8109
+ depth: item.depth + 1,
8110
+ names: extra.length === 0 ? item.names : /* @__PURE__ */ new Set([...item.names, ...extra]),
8111
+ later: hidden.length === 0 ? item.later : /* @__PURE__ */ new Set([...item.later, ...hidden]),
8112
+ address: slot.address === true,
8113
+ slot: slot.path,
8114
+ parent: here,
8115
+ caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : partCaps(kind.caps, slot.path, item.caps),
8116
+ bound: extra,
8117
+ expect: slot.expect
8118
+ });
8119
+ }
8120
+ }
8121
+ }
8122
+ /**
8123
+ * This function finds each reference of a document: each document of the type `ref` that a walk reaches. A
8124
+ * reference to a name that a kind around it binds is not free. The others are what the document reads from
8125
+ * outside: its dependencies. When the kind `ref` has parts, the walk also finds the references in its step documents.
8126
+ *
8127
+ * @param world - The world of the kinds.
8128
+ * @param doc - The document, as JSON.
8129
+ * @param options - The type of a bare root value. The names of the host do not change the result.
8130
+ * @returns The references, in the order of the document.
8131
+ */
8132
+ function refsOf(world, doc, options = {}) {
8133
+ const out = [];
8134
+ walk(world, doc, (v) => {
8135
+ if (!isRef(v.doc)) return void 0;
8136
+ const path = v.doc.value;
8137
+ const root = typeof path[0] === "string" ? path[0] : "";
8138
+ const first = path[1];
8139
+ const use = {
8140
+ path,
8141
+ root,
8142
+ free: !(root === "names" && isKey(first) && v.names.has(String(first))),
8143
+ address: v.address === true
8144
+ };
8145
+ Object.defineProperty(use, "place", {
8146
+ enumerable: true,
8147
+ get: () => v.place
8148
+ });
8149
+ Object.defineProperty(use, "at", {
8150
+ enumerable: true,
8151
+ get: () => v.at
8152
+ });
8153
+ Object.defineProperty(use, "visit", {
8154
+ enumerable: false,
8155
+ value: v
8156
+ });
8157
+ out.push(use);
8158
+ }, options.names === void 0 ? options : withoutNames(options));
8159
+ return out;
8160
+ }
8161
+ function setAt(value, path, next) {
8162
+ if (path.length === 0) return next;
8163
+ const [key, ...rest] = path;
8164
+ if (Array.isArray(value)) {
8165
+ const copy = [...value];
8166
+ copy[Number(key)] = setAt(value[Number(key)], rest, next);
8167
+ return copy;
8168
+ }
8169
+ const record = isRecord(value) ? value : {};
8170
+ const copy = {};
8171
+ for (const name of Object.keys(record)) Object.defineProperty(copy, name, {
8172
+ value: record[name],
8173
+ enumerable: true,
8174
+ writable: true,
8175
+ configurable: true
8176
+ });
8177
+ Object.defineProperty(copy, String(key), {
8178
+ value: setAt(record[String(key)], rest, next),
8179
+ enumerable: true,
8180
+ writable: true,
8181
+ configurable: true
8182
+ });
8183
+ return copy;
8184
+ }
8185
+ /**
8186
+ * This function changes the free references of a document. The document is not changed: the function gives a new
8187
+ * document that shares each part without a change.
8188
+ *
8189
+ * @param world - The world of the kinds.
8190
+ * @param doc - The document, as JSON.
8191
+ * @param change - The function that gives the new document of a reference, or `undefined` to keep it.
8192
+ * @param options - The type of a bare root value, and the names that the host binds at the root.
8193
+ * @returns The new document.
8194
+ */
8195
+ function mapRefs(world, doc, change, options = {}) {
8196
+ let out = doc;
8197
+ for (const use of refsOf(world, doc, options)) {
8198
+ if (!use.free) continue;
8199
+ const next = change(use);
8200
+ if (next !== void 0) out = setAt(out, use.at, next);
8201
+ }
8202
+ return out;
8203
+ }
8204
+ /** The least authority: the capability `[]` permits each effect (CAP.KEYS). */
8205
+ const EACH$1 = /* @__PURE__ */ Object.freeze([[]]);
8206
+ /** No declared effect. One list serves each visit without effects. */
8207
+ const NO_EFFECTS = /* @__PURE__ */ Object.freeze([]);
8208
+ /**
8209
+ * This function gives the effects that the contract of the kind of a visit declares for a verb, as keys
8210
+ * (FACTS.EFFECTS, VERB.EFFECTS). The text `"type"` gives the type of the document after each alias. A visit without a
8211
+ * kind declares no effect. `check`, `factsOf` and `effectsOf` read the declarations with this one function (D27).
8212
+ *
8213
+ * @param v - The visit.
8214
+ * @param verb - The verb. The default is `eval`. A kind without a declaration for the verb gives no effect.
8215
+ * @returns The keys of each declared effect, in the order of the contract.
8216
+ */
8217
+ function declaredEffects(v, verb = "eval") {
8218
+ return verbDeclared(v, verb) ?? NO_EFFECTS;
8219
+ }
8220
+ /**
8221
+ * This function gives the effects that the contract of the kind of a visit declares for a verb, as keys. The result
8222
+ * is `undefined` when the contract has no declaration for the verb (D49). A visit without a kind declares no effect
8223
+ * for `eval` and no declaration for another verb.
8224
+ */
8225
+ function verbDeclared(v, verb) {
8226
+ if (v.kind === void 0) return verb === "eval" ? NO_EFFECTS : void 0;
8227
+ const effects = effectsOfVerb(v.kind, verb);
8228
+ if (effects === void 0) return void 0;
8229
+ if (effects.length === 0) return NO_EFFECTS;
8230
+ return effects === "type" ? [v.typePath ?? []] : effects.map((kind) => kind.split("."));
8231
+ }
8232
+ /**
8233
+ * This function gives the rule of a machine for an effect, for the static kit (CAP.PERMITS). The rule is the hook
8234
+ * `permits` of the machine, as in a run, or else the function `permits`. A check has no values, thus the hook gets a
8235
+ * context with the capabilities of the document and the world of the machine. Its names, its self and its event are
8236
+ * empty.
8237
+ *
8238
+ * @param machine - The machine.
8239
+ * @returns The rule. It gets the capabilities of a document and the keys of an effect.
8240
+ */
8241
+ function permitsOf(machine) {
8242
+ const hook = machine.permits;
8243
+ if (hook === void 0) return permits;
8244
+ let base;
8245
+ return (caps, kind) => hook(caps, kind, {
8246
+ ...base ??= context({ world: worldThing(machine.world) }),
8247
+ caps
8248
+ });
8249
+ }
8250
+ /**
8251
+ * This function gives the reason of a `#CAP!`. When a kind around the document narrowed the capabilities, the
8252
+ * reason names the nearest such kind.
8253
+ */
8254
+ function capReason(v, kind, allowed) {
8255
+ const text = kind.join(".");
8256
+ for (let up = v.parent; up !== void 0; up = up.parent) if (up.caps !== void 0 && allowed(up.caps, kind)) return `The capabilities do not permit the effect ${text} here. The kind ${typeName(up.doc.type)} around it narrows them for its parts.`;
8257
+ return `The capabilities do not permit the effect ${text}.`;
8258
+ }
8259
+ /**
8260
+ * This function checks a document before an evaluation, by the contracts of its kinds. It finds the problems
8261
+ * that an evaluation finds when it reaches them:
8262
+ *
8263
+ * - `#KIND?`: a kind that the world does not have.
8264
+ * - `#NOEVAL`: no evaluator.
8265
+ * - `#VALUE!`: a value without the shape of its kind.
8266
+ * - `#PART?`: a value without a type.
8267
+ * - `#DEPTH!`: too much nesting.
8268
+ * - `#REF!` and `#STEP?`: a bad path.
8269
+ * - `#NAME?`: a name that nothing binds. With the hook `known` of the machine, also a name that the language does not
8270
+ * have, for example an operation.
8271
+ * - `#CAP!`: an effect that the capabilities of its document do not permit. A kind around the document can narrow them.
8272
+ * The hook `permits` of the machine decides, as in a run (CAP.PERMITS).
8273
+ * - `#CALC!`: with the option `run`, a runner under a parent without a runner, when an effect of its runners can reach
8274
+ * the host. Also a kind that declares effects and has no runner (RUN.CAN-WAIT). The issue has the place and the
8275
+ * reason of the run.
8276
+ * - `#TYPE!`: with the option `types`, a part whose type does not fit the type that its position needs (TYPE.CHECK).
8277
+ * A run does not always fail there, thus a type issue is a static finding, not an error of a run.
8278
+ *
8279
+ * The check asks the ladder for the verb of the options, `eval` by default (VERB.CHECK). The shapes, the paths and the
8280
+ * names follow the contracts, thus they are the same for each verb. The check tests the effects that each contract
8281
+ * declares for the verb: `effects` for `eval`, and the entry of `verbEffects` for another verb (VERB.EFFECTS). A kind
8282
+ * without a declaration for the verb gives no `#CAP!` and no `#CALC!` for an effect.
8283
+ *
8284
+ * @param machine - The world and the code of the evaluators.
8285
+ * @param doc - The document, as JSON.
8286
+ * @param options - The type of a bare root value, the names of the host, the capabilities, the verb, the types and the run.
8287
+ * @returns The problems, in the order of the document. The type issues come after the other issues.
8288
+ */
8289
+ function check(machine, doc, options = {}) {
8290
+ return options.types === true ? typeCheck(machine, doc, options).issues : checkAll(machine, doc, options, void 0);
8291
+ }
8292
+ /**
8293
+ * This function checks a document, and it also checks the value types (TYPE.CHECK, D25). It finds each issue of
8294
+ * `check`. Then it synthesizes the type of each document from the types of its parts. It also checks each part
8295
+ * against the type that its position needs. The type rule of the parent, the signature of an operation or the shape
8296
+ * of the contract gives that type. A part with an issue gets the type `unknown`, thus one
8297
+ * problem does not give a chain of issues.
8298
+ *
8299
+ * A type issue has the code `#TYPE!`, the type that the position needs (`expected`) and the type that the check found
8300
+ * (`found`). It is a static finding: the evaluation of the document does not change.
8301
+ *
8302
+ * The option `rootTypes` gives the types of the roots and of the names of the host (TYPE.ROOTS). A reference then gets
8303
+ * the type that its path reaches, and a field that a closed record does not have is a type issue (TYPE.CLOSED).
8304
+ *
8305
+ * @param machine - The world and the code of the evaluators, with their type rules.
8306
+ * @param doc - The document, as JSON.
8307
+ * @param options - The options of `check`, the type that the root must have and the types of the roots.
8308
+ * @returns The type of the root, each issue, and the type of each document.
8309
+ */
8310
+ function typeCheck(machine, doc, options = {}) {
8311
+ const nodes = [];
8312
+ const issues = checkAll(machine, doc, options, nodes);
8313
+ const pass = typePass(machine, nodes, options.verb ?? "eval", options.expect, options.rootTypes);
8314
+ return {
8315
+ type: pass.type,
8316
+ issues: pass.issues.length === 0 ? issues : [...issues, ...pass.issues],
8317
+ places: pass.places
8318
+ };
8319
+ }
8320
+ /** This function tells if a table of verbs has an entry for a verb. */
8321
+ function hasVerb(table, verb) {
8322
+ return table !== void 0 && Object.hasOwn(table, verb);
8323
+ }
8324
+ /**
8325
+ * This function checks the world of a machine before a document exists. It finds each kind that has no entry for a
8326
+ * verb of the list, when the world has no default for that verb (STATIC.COVERAGE). A document of such a kind gets no
8327
+ * evaluator for the verb, thus the check gives the same proof of coverage as a type system.
8328
+ *
8329
+ * The check visits each kind of each namespace, at each depth, and the fallback kind of each namespace and of the
8330
+ * world. It does not follow an alias, because the kind of an alias has its own place. Without the option `types`, the
8331
+ * check reads only the world.
8332
+ *
8333
+ * With the option `types`, the check also examines each value type of the machine (TYPE.WORLD, D110). These issues
8334
+ * have the code `#TYPE!`, and they come after the issues of the verbs.
8335
+ *
8336
+ * @param machine - The machine, for its world.
8337
+ * @param verbs - The verbs that each kind of the language must answer, for example `eval`, `view` and `type`.
8338
+ * @param options - The option `types`.
8339
+ * @returns One issue for each kind and verb without an evaluator. The order is the order of the world, then the
8340
+ * order of the verbs. The fallback kind of a namespace comes after the entries of that namespace.
8341
+ */
8342
+ function checkWorld(machine, verbs, options = {}) {
8343
+ const world = machine.world;
8344
+ const open = verbs.filter((verb) => !hasVerb(world.defaults, verb));
8345
+ const out = [];
8346
+ if (open.length > 0) eachKind(world, (kind, path, fallback) => {
8347
+ const text = path.join(".");
8348
+ const name = fallback ? path.length === 0 ? "the fallback kind of the world" : `the fallback kind of ${text}` : `the kind ${text}`;
8349
+ for (const verb of open) {
8350
+ if (hasVerb(kind.verbs, verb)) continue;
8351
+ const reason = `${name.charAt(0).toUpperCase()}${name.slice(1)} has no entry for the verb ${verb}, and the world has no default for it.`;
8352
+ out.push(fallback ? {
8353
+ code: "#NOEVAL",
8354
+ kind: path,
8355
+ fallback: true,
8356
+ verb,
8357
+ reason
8358
+ } : {
8359
+ code: "#NOEVAL",
8360
+ kind: path,
8361
+ verb,
8362
+ reason
8363
+ });
8364
+ }
8365
+ });
8366
+ if (options.types === true) out.push(...machineTypeIssues(machine));
8367
+ return out;
8368
+ }
8369
+ /** The names that an equation of `down` sees (TREE.DOWN). */
8370
+ const DOWN_NAMES = /* @__PURE__ */ Object.freeze([
8371
+ "child",
8372
+ "index",
8373
+ "prev"
8374
+ ]);
8375
+ /** The names that the term `combine` of a fold sees (TREE.FOLD). */
8376
+ const FOLD_NAMES = /* @__PURE__ */ Object.freeze(["acc", "item"]);
8377
+ /**
8378
+ * This function gives each equation of the tree contract of a kind, with the names that it sees (D42). An equation of
8379
+ * `equations`, a `unit` and a `default` see no names. `check` and `factsOf` read the equations with this one function.
8380
+ */
8381
+ function equationsOf(kind) {
8382
+ const tree = kind.tree;
8383
+ if (tree === void 0) return [];
8384
+ const out = [];
8385
+ for (const [name, term] of Object.entries(tree.equations ?? {})) out.push({
8386
+ label: `tree.equations.${name}`,
8387
+ term,
8388
+ names: [],
8389
+ attribute: name,
8390
+ down: false
8391
+ });
8392
+ for (const [name, term] of Object.entries(tree.down ?? {})) out.push({
8393
+ label: `tree.down.${name}`,
8394
+ term,
8395
+ names: DOWN_NAMES,
8396
+ attribute: name,
8397
+ down: true
8398
+ });
8399
+ for (const [name, declared] of Object.entries(tree.attributes ?? {})) {
8400
+ if (declared.fold !== void 0) {
8401
+ out.push({
8402
+ label: `tree.attributes.${name}.fold.unit`,
8403
+ term: declared.fold.unit,
8404
+ names: [],
8405
+ attribute: name,
8406
+ down: false
8407
+ });
8408
+ out.push({
8409
+ label: `tree.attributes.${name}.fold.combine`,
8410
+ term: declared.fold.combine,
8411
+ names: FOLD_NAMES,
8412
+ attribute: name,
8413
+ down: false
8414
+ });
8415
+ }
8416
+ if (declared.default !== void 0) out.push({
8417
+ label: `tree.attributes.${name}.default`,
8418
+ term: declared.default,
8419
+ names: [],
8420
+ attribute: name,
8421
+ down: false
8422
+ });
8423
+ }
8424
+ return out;
8425
+ }
8426
+ /**
8427
+ * The steps that a node of the decorated tree answers before its ladder: `parent` and `type` (D106). An attribute with
8428
+ * one of these names gets no read.
8429
+ */
8430
+ const STRUCTURAL = /* @__PURE__ */ Object.freeze({
8431
+ parent: "the step parent gives the parent of the node",
8432
+ type: "the step type gives the type of the node"
8433
+ });
8434
+ /**
8435
+ * The standard code that gives its parts the self of its own context (D106). `check` knows the self of a document only
8436
+ * through this code and the nodes of the decorated tree.
8437
+ */
8438
+ const KEEPS_SELF = /* @__PURE__ */ new Set([
8439
+ "data.number",
8440
+ "data.text",
8441
+ "data.bool",
8442
+ "math.add",
8443
+ "math.multiply",
8444
+ "math.greater",
8445
+ "control.seq",
8446
+ "control.pure",
8447
+ "control.if",
8448
+ "list.all",
8449
+ "effect.log",
8450
+ "effect.write"
8451
+ ]);
8452
+ /** This function tells if standard code gives its parts the self of its own context (D106). */
8453
+ function keepsSelf(evaluator) {
8454
+ return evaluator !== void 0 && KEEPS_SELF.has(evaluator);
8455
+ }
8456
+ /**
8457
+ * This function makes the selves of one walk (D106). Only `eval` reads attributes, and only when the root `self` is
8458
+ * open. A node gets the self of its code as its parent. The standard code that keeps self gives its parts its own self.
8459
+ * Other code gives its parts a self that the walk does not know.
8460
+ *
8461
+ * @param machine - The machine.
8462
+ * @param verb - The verb of the walk.
8463
+ * @param root - The self of the root document: the node of an equation, or `undefined`.
8464
+ * @returns The selves.
8465
+ */
8466
+ function selvesOf(machine, verb, root) {
8467
+ const roots = machine.roots ?? ROOTS;
8468
+ const on = verb === "eval" && roots.includes("self") && hasEntry(machine.evaluators, "tree.node") && !hasEntry(machine.runners, "tree.node");
8469
+ const selves = /* @__PURE__ */ new Map();
8470
+ const isNode = (v, evaluator) => on && evaluator === "tree.node" && v.kind !== void 0;
8471
+ return {
8472
+ isNode,
8473
+ enter(v, evaluator) {
8474
+ const self = v.parent === void 0 ? root : selves.get(v.parent);
8475
+ if (!isNode(v, evaluator) || v.kind === void 0) {
8476
+ selves.set(v, keepsSelf(evaluator) ? self : void 0);
8477
+ return {
8478
+ self,
8479
+ node: void 0
8480
+ };
8481
+ }
8482
+ const read = partsOf(machine.world, v.declared ? v.doc.value : v.doc, v.declared ? typeName(v.doc.type) : void 0);
8483
+ const own = read.ok && read.split.ok ? new Set(read.split.parts.map((part) => part.key)) : void 0;
8484
+ const node = {
8485
+ kind: v.kind,
8486
+ text: typeName(v.doc.type),
8487
+ own,
8488
+ parent: self
8489
+ };
8490
+ selves.set(v, node);
8491
+ return {
8492
+ self,
8493
+ node
8494
+ };
8495
+ }
8496
+ };
8497
+ }
8498
+ /**
8499
+ * This function tells if a name is a structural step of a node of the decorated tree: `parent` or `type` (D106). An
8500
+ * attribute with such a name gets no read.
8501
+ */
8502
+ function isStructural(name) {
8503
+ return Object.hasOwn(STRUCTURAL, name);
8504
+ }
8505
+ /** The names of `down` in the world of each machine, for a parent that `check` does not know (D106). */
8506
+ const DOWNS = /* @__PURE__ */ new WeakMap();
8507
+ /**
8508
+ * This function gives each name that an equation of `down` of a kind of the world gives. The kinds include the kinds
8509
+ * of the namespaces and each fallback kind (WORLD.OPEN). A parent that `check` does not know has one of these kinds.
8510
+ */
8511
+ function downNames(world) {
8512
+ const known = DOWNS.get(world);
8513
+ if (known !== void 0) return known;
8514
+ const out = /* @__PURE__ */ new Set();
8515
+ const done = /* @__PURE__ */ new Set();
8516
+ const add = (kind) => {
8517
+ for (const name of Object.keys(kind?.tree?.down ?? {})) out.add(name);
8518
+ };
8519
+ const visit = (entries, fallback) => {
8520
+ if (done.has(entries)) return;
8521
+ done.add(entries);
8522
+ add(fallback);
8523
+ for (const entry of Object.values(entries)) if (isKind(entry)) add(entry);
8524
+ else if (isNamespace(entry)) visit(entry.kinds, entry.fallback);
8525
+ };
8526
+ visit(world.kinds, world.fallback);
8527
+ DOWNS.set(world, out);
8528
+ return out;
8529
+ }
8530
+ /** This function tells if a table of a tree contract has its own entry for a name. */
8531
+ function hasEntry(table, name) {
8532
+ return table !== void 0 && Object.hasOwn(table, name);
8533
+ }
8534
+ /**
8535
+ * This function tells if a rung of the ladder can answer an attribute of a node (TREE.LADDER). An unknown parent can
8536
+ * be a node of each kind of the world, thus each name of `down` in the world can answer. A copy can always answer,
8537
+ * because `check` does not know a node without a parent.
8538
+ */
8539
+ function answered(world, node, name) {
8540
+ if (node.own?.has(name) === true) return true;
8541
+ const tree = node.kind.tree;
8542
+ if (hasEntry(tree?.equations, name)) return true;
8543
+ if (node.parent === void 0 ? downNames(world).has(name) : hasEntry(node.parent.kind.tree?.down, name)) return true;
8544
+ const declared = tree?.attributes !== void 0 && Object.hasOwn(tree.attributes, name) ? tree.attributes[name] : void 0;
8545
+ return declared !== void 0 && (declared.copy === true || declared.fold !== void 0 || declared.default !== void 0);
8546
+ }
8547
+ /**
8548
+ * This function checks the equations of the tree contract of a kind, each with the names of its rung (TREE.DOWN-NAMES).
8549
+ * An equation evaluates without capabilities, thus a check with capabilities gives it none. Each issue gets the place
8550
+ * of the document of the kind, and its reason names the equation. The function also records the needs of the kind:
8551
+ * each declared attribute, and each attribute of the node that an equation reads (TREE.CHECK-COMPLETE).
8552
+ */
8553
+ function equationIssues(machine, kind, kindText, options, state) {
8554
+ const of = equationType(kind);
8555
+ const out = [];
8556
+ const needs = [];
8557
+ state.needs.set(kind, needs);
8558
+ for (const name of Object.keys(kind.tree?.attributes ?? {})) needs.push({
8559
+ name,
8560
+ why: "the kind declares it",
8561
+ hidden: void 0
8562
+ });
8563
+ const self = {
8564
+ kind,
8565
+ text: kindText,
8566
+ own: void 0,
8567
+ parent: void 0
8568
+ };
8569
+ for (const { label, term, names, attribute, down } of equationsOf(kind)) {
8570
+ const inner = {
8571
+ names,
8572
+ ...of === void 0 ? {} : { declaredType: of },
8573
+ ...options.caps === void 0 ? {} : { caps: [] }
8574
+ };
8575
+ const read = (name) => {
8576
+ needs.push({
8577
+ name,
8578
+ why: `the equation ${label} reads it`,
8579
+ hidden: down ? void 0 : attribute
8580
+ });
8581
+ };
8582
+ for (const issue of checkAll(machine, term, inner, void 0, state, {
8583
+ node: self,
8584
+ read
8585
+ })) out.push({
8586
+ code: issue.code,
8587
+ place: [],
8588
+ reason: `In the equation ${label} of the kind ${kindText}: ${issue.reason}`
8589
+ });
8590
+ }
8591
+ return out;
8592
+ }
8593
+ /**
8594
+ * This function finds the issues of the contract of a tree kind (TREE.CHECK-RESERVED). An attribute with the name of a
8595
+ * structural step gets no read. A tree kind of the run side contradicts the evaluation on demand of its attributes.
8596
+ */
8597
+ function contractIssues(kind, kindText) {
8598
+ const out = [];
8599
+ const tree = kind.tree;
8600
+ for (const table of [
8601
+ "equations",
8602
+ "down",
8603
+ "attributes"
8604
+ ]) for (const name of Object.keys(tree?.[table] ?? {})) {
8605
+ const why = Object.hasOwn(STRUCTURAL, name) ? STRUCTURAL[name] : void 0;
8606
+ if (why !== void 0) out.push({
8607
+ code: "#NAME?",
8608
+ place: [],
8609
+ reason: `The kind ${kindText} gives the reserved attribute tree.${table}.${name}: ${why}.`
8610
+ });
8611
+ }
8612
+ if (kind.side === "run") out.push({
8613
+ code: "#CALC!",
8614
+ place: [],
8615
+ reason: `The tree kind ${kindText} is on the run side: a node evaluates its attributes on demand, thus in no fixed order.`
8616
+ });
8617
+ return out;
8618
+ }
8619
+ /**
8620
+ * This function finds the issues of a node of a document (D106). An own part with the name of a structural step is
8621
+ * not read at any time (TREE.CHECK-RESERVED). Each need of the kind gets an answer from a rung (TREE.CHECK-COMPLETE).
8622
+ */
8623
+ function nodeIssues(machine, node, state, v) {
8624
+ const out = [];
8625
+ const at = (key) => [
8626
+ ...v.at,
8627
+ ...v.declared ? [] : ["value"],
8628
+ key
8629
+ ];
8630
+ for (const name of node.own ?? []) {
8631
+ const why = Object.hasOwn(STRUCTURAL, name) ? STRUCTURAL[name] : void 0;
8632
+ if (why !== void 0) out.push({
8633
+ code: "#NAME?",
8634
+ place: v.place,
8635
+ reason: `The part ${name} of the kind ${node.text} has a reserved name: ${why}.`,
8636
+ at: at(name)
8637
+ });
8638
+ }
8639
+ const done = /* @__PURE__ */ new Set();
8640
+ for (const need of state.needs.get(node.kind) ?? []) {
8641
+ if (done.has(need.name) || need.hidden !== void 0 && node.own?.has(need.hidden) === true) continue;
8642
+ done.add(need.name);
8643
+ if (answered(machine.world, node, need.name)) continue;
8644
+ out.push({
8645
+ code: "#N/A",
8646
+ place: v.place,
8647
+ reason: `No rung gives the attribute ${need.name} of the kind ${node.text}, and ${need.why}.`,
8648
+ at: v.at
8649
+ });
8650
+ }
8651
+ return out;
8652
+ }
8653
+ /**
8654
+ * This function examines a reference from the root `self` (TREE.CHECK-UNKNOWN). The steps `parent` go up the known
8655
+ * nodes. The first other key names an attribute of the node that they reach. When no rung answers the attribute, the
8656
+ * function gives the index of the step and the reason. In an equation, a read of the node of the equation goes to the
8657
+ * needs of its kind.
8658
+ */
8659
+ function readIssue(machine, self, path, rootSelf) {
8660
+ let node = self;
8661
+ let index = 1;
8662
+ while (node !== void 0 && index < path.length && path[index] === "parent") {
8663
+ node = node.parent;
8664
+ index += 1;
8665
+ }
8666
+ const step = path[index];
8667
+ if (node === void 0 || !isKey(step) || Object.hasOwn(STRUCTURAL, String(step))) return void 0;
8668
+ const name = String(step);
8669
+ if (node.own === void 0) {
8670
+ if (node === rootSelf?.node) rootSelf.read(name);
8671
+ return;
8672
+ }
8673
+ return answered(machine.world, node, name) ? void 0 : {
8674
+ index,
8675
+ reason: `No rung gives the attribute ${name} of the kind ${node.text}.`
8676
+ };
8677
+ }
8678
+ /**
8679
+ * This function finds the issues of `check`. With a list of nodes, it also records each document that it visits for
8680
+ * the pass of types. It marks each document with an issue. The state holds the kinds whose equations the check
8681
+ * walked, thus it walks the equations of each kind one time. In an equation, `rootSelf` is the node of the equation.
8682
+ */
8683
+ function checkAll(machine, doc, options, nodes, state = {
8684
+ seen: /* @__PURE__ */ new Set(),
8685
+ needs: /* @__PURE__ */ new Map()
8686
+ }, rootSelf) {
8687
+ const seen = state.seen;
8688
+ const issues = [];
8689
+ const verb = options.verb ?? "eval";
7091
8690
  const indices = nodes === void 0 ? void 0 : /* @__PURE__ */ new Map();
7092
8691
  let current;
7093
8692
  const push = (issue) => {
@@ -7101,6 +8700,9 @@ function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()
7101
8700
  const anyName = options.names === "any";
7102
8701
  const roots = machine.roots ?? ROOTS;
7103
8702
  const has = (table, name) => table !== void 0 && Object.hasOwn(table, name);
8703
+ const attributes = verb === "eval" && roots.includes("self");
8704
+ const selves = selvesOf(machine, verb, rootSelf?.node);
8705
+ let trees = false;
7104
8706
  walk(machine.world, doc, (v) => {
7105
8707
  if (nodes !== void 0 && indices !== void 0) {
7106
8708
  current = {
@@ -7136,14 +8738,19 @@ function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()
7136
8738
  });
7137
8739
  return "skip";
7138
8740
  }
7139
- if (v.kind?.tree !== void 0 && !seen.has(v.kind)) {
8741
+ const node = selves.isNode(v, answer.evaluator);
8742
+ if (v.kind !== void 0 && (v.kind.tree !== void 0 || node) && !seen.has(v.kind)) {
7140
8743
  seen.add(v.kind);
7141
- for (const issue of equationIssues(machine, v.kind, typeName(v.doc.type), options, seen)) push({
8744
+ const kindText = typeName(v.doc.type);
8745
+ for (const issue of [...contractIssues(v.kind, kindText), ...equationIssues(machine, v.kind, kindText, options, state)]) push({
7142
8746
  ...issue,
7143
8747
  place: v.place,
7144
8748
  at: v.at
7145
8749
  });
7146
8750
  }
8751
+ const { self, node: here } = selves.enter(v, answer.evaluator);
8752
+ if (here !== void 0) trees = true;
8753
+ if (here?.own !== void 0) for (const issue of nodeIssues(machine, here, state, v)) push(issue);
7147
8754
  const name = answer.evaluator;
7148
8755
  if (current !== void 0) current.evaluator = name;
7149
8756
  const runner = name !== void 0 && has(machine.runners, name);
@@ -7244,6 +8851,15 @@ function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()
7244
8851
  at: stepAt(1)
7245
8852
  });
7246
8853
  }
8854
+ if (attributes && root === "self" && v.address !== true && name === "ref.resolve") {
8855
+ const issue = readIssue(machine, self, path, rootSelf);
8856
+ if (issue !== void 0) push({
8857
+ code: "#N/A",
8858
+ place: v.place,
8859
+ reason: issue.reason,
8860
+ at: stepAt(issue.index)
8861
+ });
8862
+ }
7247
8863
  path.forEach((step, index) => {
7248
8864
  if (index === 0 || isKey(step)) return;
7249
8865
  if (walkerOf(machine, step) === void 0) push({
@@ -7256,7 +8872,7 @@ function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()
7256
8872
  }, {
7257
8873
  ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
7258
8874
  ...Array.isArray(options.names) ? { names: options.names } : {},
7259
- ...options.caps === void 0 ? waits === void 0 ? {} : { caps: EACH$2 } : { caps: options.caps },
8875
+ ...options.caps === void 0 ? waits === void 0 ? {} : { caps: EACH$1 } : { caps: options.caps },
7260
8876
  problem: (problem) => {
7261
8877
  issues.push({
7262
8878
  code: problem.code,
@@ -7273,237 +8889,9 @@ function checkAll(machine, doc, options, nodes, seen = /* @__PURE__ */ new Set()
7273
8889
  issues.splice(drive.index, 0, drive.issue);
7274
8890
  if (drive.node !== void 0) drive.node.marked = true;
7275
8891
  }
8892
+ if (trees && rootSelf === void 0) for (const issue of cycleIssues(machine, doc, options)) issues.push(issue);
7276
8893
  return issues;
7277
8894
  }
7278
- // src/facts.ts
7279
- /** The lazy rules that cover each part: the rules of a document whose evaluator the contract does not describe. */
7280
- const EACH$1 = "each";
7281
- /** An empty list. One frozen list serves each empty list of the facts, thus a store of many facts keeps less (PLAN.LEAN). */
7282
- const NONE = /* @__PURE__ */ Object.freeze([]);
7283
- /**
7284
- * This function gives a list of the facts with no free room. A list that grows by `push` keeps room for more items,
7285
- * thus a copy of a short list is smaller.
7286
- */
7287
- function tight(list) {
7288
- return list.length === 0 ? NONE : list.slice();
7289
- }
7290
- /**
7291
- * This function gives the name of the evaluator that the ladder finds for a verb (VERB.LADDER). It also tells if
7292
- * the contract of the kind describes that code. The contract describes the code of its kind for its verb `contract`.
7293
- * An own entry for another evaluator has code that the contract does not describe.
7294
- */
7295
- function codeOf(world, own, kind, verb, contract) {
7296
- const found = answerOf(world, own, kind, verb);
7297
- if (verb !== contract) return {
7298
- name: found?.name,
7299
- described: false
7300
- };
7301
- if (found?.rung !== "own") return {
7302
- name: found?.name,
7303
- described: true
7304
- };
7305
- return {
7306
- name: found.name,
7307
- described: found.name === answerOf(world, void 0, kind, verb)?.name
7308
- };
7309
- }
7310
- /** This function gives the position of a part among the parts that a rule covers, by the split of its document. */
7311
- function positionOf(above, parent, rule, slot) {
7312
- const positions = above.positions ??= /* @__PURE__ */ new Map();
7313
- let table = positions.get(rule);
7314
- if (table === void 0) {
7315
- table = /* @__PURE__ */ new Map();
7316
- const split = splitParts(parent.kind?.parts, parent.doc.value);
7317
- let count = 0;
7318
- for (const part of split.ok ? split.parts : []) {
7319
- if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
7320
- table.set(JSON.stringify(part.path), count);
7321
- count += 1;
7322
- }
7323
- positions.set(rule, table);
7324
- }
7325
- return table.get(JSON.stringify(slot)) ?? 0;
7326
- }
7327
- /** This function tells if the lazy rules of a document cover one of its parts. */
7328
- function partLazy(above, parent, slot) {
7329
- const rules = above.rules;
7330
- if (rules === void 0) return false;
7331
- if (rules === EACH$1) return true;
7332
- for (const rule of rules) {
7333
- if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
7334
- const after = rule.after ?? 0;
7335
- if (after <= 0 || positionOf(above, parent, rule, slot) >= after) return true;
7336
- }
7337
- return false;
7338
- }
7339
- /**
7340
- * This function gives the static facts of a document, for a schedule (R4 P2, D24). It walks the document one time,
7341
- * by the contracts of its kinds:
7342
- *
7343
- * - `reads`: each free reference, with the root and the keys of its path. A read under a lazy part has the mark
7344
- * `lazy`, for example a read in a branch of `if`. A read after a step document has `exact: false`. A kind that
7345
- * declares `reads` adds a read of each of its roots at each document of the kind. The first document of a tree
7346
- * kind also gets the lazy reads of the equations of its kind (FACTS.EQUATIONS). A read from `self` or from a name
7347
- * of a rung is not one of them, because it is not free (READS.EQUATION).
7348
- * - `side` and `effects`: from the contract of each kind.
7349
- * - `pure`: each kind declares `pure`, also in an equation, and the document has no effect and is not volatile.
7350
- * - `volatile`: a kind, an operation or a step document declares `volatile`, or the host marks a read.
7351
- *
7352
- * The hook `facts` of the machine answers for a name that a fallback kind covers, for example an operation. Its
7353
- * answer wins over the contract of the kind. The contract of a kind does not describe the evaluator of an own
7354
- * entry. Thus a document with an own entry for another evaluator is not pure, and each of its parts is lazy. The
7355
- * hook can still answer for that evaluator.
7356
- *
7357
- * The option `verb` names the verb whose code the facts describe (FACTS.VERB). A contract describes the code of
7358
- * `eval`, thus the rule of an own entry applies to each document for another verb. The side and the effects come
7359
- * from the contracts for each verb.
7360
- *
7361
- * A read is one resolution of its path. A reference that the resolution reaches and follows is a part of that read
7362
- * (DEREF.COLLAPSE), not a separate read. The facts depend only on the document and the machine. Thus a host computes
7363
- * them again only after an edit of the document or of the machine.
7364
- *
7365
- * @param machine - The world, the code and the hook `facts`.
7366
- * @param doc - The document, as JSON.
7367
- * @param options - The type of a bare root value, the verb and the volatile reads of the host.
7368
- * @returns The facts.
7369
- */
7370
- function factsOf(machine, doc, options = {}) {
7371
- const world = machine.world;
7372
- const hook = machine.facts;
7373
- const reads = [];
7374
- const effects = [];
7375
- const above = /* @__PURE__ */ new Map();
7376
- let side = "derive";
7377
- let pure = true;
7378
- let volatile = false;
7379
- let size = 0;
7380
- let seen;
7381
- const note = (isPure, isVolatile) => {
7382
- if (isPure !== true) pure = false;
7383
- if (isVolatile === true) volatile = true;
7384
- };
7385
- const add = (read) => {
7386
- reads.push(read);
7387
- if (options.volatile?.(read) === true) volatile = true;
7388
- };
7389
- /**
7390
- * This function walks a document. Without `node`, it walks the document of the facts. With `node`, it walks an
7391
- * equation of a tree kind, and each read gets the place of that node: the first document of the kind.
7392
- */
7393
- const scan = (term, walkOptions, verb, node) => {
7394
- walk(world, term, (v) => {
7395
- if (node === void 0) size += 1;
7396
- const up = v.parent === void 0 ? void 0 : above.get(v.parent);
7397
- const lazy = node !== void 0 || up !== void 0 && v.parent !== void 0 && (up.lazy || partLazy(up, v.parent, v.slot));
7398
- const place = node ?? v;
7399
- const kind = v.kind;
7400
- if (kind === void 0) {
7401
- pure = false;
7402
- above.set(v, {
7403
- lazy,
7404
- rules: void 0
7405
- });
7406
- return;
7407
- }
7408
- const code = codeOf(world, v.declared ? void 0 : v.doc.own, kind, verb, "eval");
7409
- const answer = code.name === void 0 ? void 0 : hook?.(v.typePath ?? [], code.name);
7410
- let roots;
7411
- if (code.described) {
7412
- note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
7413
- above.set(v, {
7414
- lazy,
7415
- rules: answer?.lazy ?? kind.lazy
7416
- });
7417
- roots = answer?.reads ?? kind.reads;
7418
- } else {
7419
- note(answer?.pure, answer?.volatile);
7420
- above.set(v, {
7421
- lazy,
7422
- rules: answer?.lazy ?? EACH$1
7423
- });
7424
- roots = answer?.reads;
7425
- }
7426
- for (const root of roots ?? NONE) {
7427
- if (node !== void 0 && root === "self") continue;
7428
- add({
7429
- root,
7430
- keys: NONE,
7431
- exact: true,
7432
- lazy,
7433
- address: false,
7434
- path: [root],
7435
- place: tight(place.place),
7436
- at: tight(place.at)
7437
- });
7438
- }
7439
- if (kind.side === "run") {
7440
- if (node === void 0) side = "run";
7441
- else pure = false;
7442
- }
7443
- for (const keys of declaredEffects(v)) {
7444
- if (node !== void 0) {
7445
- pure = false;
7446
- continue;
7447
- }
7448
- const text = keys.join(".");
7449
- if (!effects.includes(text)) effects.push(text);
7450
- }
7451
- if (kind.tree !== void 0 && !(seen ??= /* @__PURE__ */ new Set()).has(kind)) {
7452
- seen.add(kind);
7453
- const of = equationType(kind);
7454
- for (const { term: equation, names } of equationsOf(kind)) scan(equation, of === void 0 ? { names } : {
7455
- names,
7456
- declaredType: of
7457
- }, "eval", place);
7458
- }
7459
- if (!isRef(v.doc)) return void 0;
7460
- const path = v.doc.value;
7461
- const root = path[0];
7462
- if (typeof root !== "string" || !ROOTS.includes(root)) return void 0;
7463
- if (node !== void 0 && root === "self") return void 0;
7464
- let exact = true;
7465
- const keys = [];
7466
- for (let index = 1; index < path.length; index += 1) {
7467
- const step = path[index];
7468
- if (exact && isKey(step)) {
7469
- keys.push(step);
7470
- continue;
7471
- }
7472
- exact = false;
7473
- const found = isEnvelope(step) ? lookupKind(world, step.type) : void 0;
7474
- if (found?.ok !== true) {
7475
- pure = false;
7476
- continue;
7477
- }
7478
- const walker = codeOf(world, step.own, found.kind, "step", "step");
7479
- const stepAnswer = walker.name === void 0 ? void 0 : hook?.(found.path, walker.name);
7480
- if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
7481
- else note(stepAnswer?.pure, stepAnswer?.volatile);
7482
- }
7483
- const first = path[1];
7484
- if (root === "names" && isKey(first) && v.names.has(String(first))) return void 0;
7485
- add({
7486
- root,
7487
- keys: tight(keys),
7488
- exact,
7489
- lazy,
7490
- address: v.address === true,
7491
- path,
7492
- place: tight(place.place),
7493
- at: tight(place.at)
7494
- });
7495
- }, walkOptions);
7496
- };
7497
- scan(doc, options.declaredType === void 0 ? {} : { declaredType: options.declaredType }, options.verb ?? "eval", void 0);
7498
- return {
7499
- reads: tight(reads),
7500
- side,
7501
- effects: tight(effects),
7502
- pure: pure && !volatile && effects.length === 0 && side === "derive",
7503
- volatile,
7504
- size
7505
- };
7506
- }
7507
8895
  // src/effects.ts
7508
8896
  /** Each capability: one capability with no keys. It permits each effect, because each kind starts with no keys (CAP.KEYS). */
7509
8897
  const EACH = /* @__PURE__ */ Object.freeze([[]]);
@@ -7721,7 +9109,8 @@ function encodeTerm(value, encoder) {
7721
9109
  *
7722
9110
  * - A value that JSON writes exactly stays as it is. A literal with the shape of an envelope goes into `lit`.
7723
9111
  * - `NaN`, an infinity and `-0` become `ext.number`, and `undefined` becomes `ext.undefined`.
7724
- * - A member of a domain with a codec becomes `ext.domain`. The domains go in the order of their names.
9112
+ * - A member of a domain with a codec becomes `ext.domain`. The codec of a domain under another domain comes first
9113
+ * (EXT.SPECIFIC, D109). The order of the names decides between unrelated domains.
7725
9114
  * - A list or a plain record with such a value becomes the construct `list` or `record`.
7726
9115
  *
7727
9116
  * @param machine - The machine, or only its domains.
@@ -7731,20 +9120,38 @@ function encodeTerm(value, encoder) {
7731
9120
  */
7732
9121
  function encodeValue(machine, value) {
7733
9122
  const domains = machine.domains;
7734
- const codecs = [];
7735
- if (domains !== void 0) for (const name of Object.keys(domains).sort()) {
7736
- const domain = domainOf(name, domains);
7737
- const codec = domain === void 0 ? void 0 : codecOf(domain);
7738
- if (codec !== void 0) codecs.push([name, codec]);
7739
- }
7740
9123
  return encodeTerm(value, {
7741
9124
  domains,
7742
- codecs,
9125
+ codecs: codecOrder(domains),
7743
9126
  json: /* @__PURE__ */ new WeakMap(),
7744
9127
  open: /* @__PURE__ */ new Set()
7745
9128
  });
7746
9129
  }
7747
9130
  /**
9131
+ * This function gives the domains with a codec in the order of `encodeValue` (EXT.SPECIFIC, D109). The depth of a
9132
+ * domain is the count of the other domains with a codec in its line. A deeper domain comes first, and the order of the
9133
+ * names decides between domains of the same depth (EXT.TIE). Thus a domain comes before each domain with a codec above it.
9134
+ */
9135
+ function codecOrder(domains) {
9136
+ const codecs = [];
9137
+ if (domains === void 0) return codecs;
9138
+ let parents = false;
9139
+ for (const name of Object.keys(domains).sort()) {
9140
+ const domain = domainOf(name, domains);
9141
+ const codec = domain === void 0 ? void 0 : codecOf(domain);
9142
+ if (domain === void 0 || codec === void 0) continue;
9143
+ codecs.push([name, codec]);
9144
+ if (Array.isArray(domain.under)) parents = true;
9145
+ }
9146
+ if (!parents) return codecs;
9147
+ const depth = /* @__PURE__ */ new Map();
9148
+ for (const [name] of codecs) {
9149
+ const line = lineOf(name, domains);
9150
+ depth.set(name, codecs.filter(([other]) => other !== name && line.has(other)).length);
9151
+ }
9152
+ return codecs.sort(([a], [b]) => depth.get(b) - depth.get(a));
9153
+ }
9154
+ /**
7748
9155
  * This function reads a document of `encodeValue` again: it evaluates the document as a term, in an empty context.
7749
9156
  * A bare root value is a literal.
7750
9157
  *
@@ -7981,6 +9388,11 @@ function valueType(value) {
7981
9388
  function isSignature(value) {
7982
9389
  return typeof value === "object" && value !== null && Array.isArray(value.params) && Object.hasOwn(value, "to");
7983
9390
  }
9391
+ /** This function tells if two signatures have the same parameters and the same rest parameter. */
9392
+ function sameParams(a, b) {
9393
+ if (!docEquals(a.params, b.params)) return false;
9394
+ return a.rest === void 0 ? b.rest === void 0 : b.rest !== void 0 && docEquals(a.rest, b.rest);
9395
+ }
7984
9396
  /** This function gives the text of a signature, for the reason of an issue. */
7985
9397
  function signatureText(sig) {
7986
9398
  const params = sig.params.map(typeText);
@@ -8071,6 +9483,58 @@ function formulaTypes(profile) {
8071
9483
  bad: sigs.length !== raw.length
8072
9484
  };
8073
9485
  };
9486
+ /**
9487
+ * The declarations of the signatures, for `checkWorld` (TYPE.WORLD, D110). Only a record of signatures lists them.
9488
+ * An overload with the parameters of an earlier overload is a problem: the earlier one always fits first.
9489
+ */
9490
+ const sigsDeclared = () => {
9491
+ const sigs = profile.sigs;
9492
+ if (sigs === void 0 || typeof sigs === "function") return [];
9493
+ const out = [];
9494
+ for (const name of Object.keys(sigs)) {
9495
+ const raw = sigs[name];
9496
+ const list = Array.isArray(raw) ? raw : [raw];
9497
+ list.forEach((sig, index) => {
9498
+ const at = Array.isArray(raw) ? [
9499
+ "sigs",
9500
+ name,
9501
+ index
9502
+ ] : ["sigs", name];
9503
+ if (!isSignature(sig)) {
9504
+ out.push({
9505
+ at,
9506
+ problem: `A signature of ops.${name} is not a record with params and to. The check does not read it.`
9507
+ });
9508
+ return;
9509
+ }
9510
+ sig.params.forEach((param, position) => out.push({
9511
+ at: [
9512
+ ...at,
9513
+ "params",
9514
+ position
9515
+ ],
9516
+ type: param,
9517
+ what: `parameter ${position + 1} of a signature of ops.${name}`
9518
+ }));
9519
+ if (sig.rest !== void 0) out.push({
9520
+ at: [...at, "rest"],
9521
+ type: sig.rest,
9522
+ what: `rest parameter of a signature of ops.${name}`
9523
+ });
9524
+ out.push({
9525
+ at: [...at, "to"],
9526
+ type: sig.to,
9527
+ what: `result of a signature of ops.${name}`
9528
+ });
9529
+ const earlier = list.slice(0, index).findIndex((other) => isSignature(other) && sameParams(other, sig));
9530
+ if (earlier >= 0) out.push({
9531
+ at,
9532
+ problem: `The overload ${index + 1} of ops.${name} has the parameters of the overload ${earlier + 1}. Thus the check never selects it.`
9533
+ });
9534
+ });
9535
+ }
9536
+ return out;
9537
+ };
8074
9538
  const logic = (word) => ({
8075
9539
  part: (input, path) => truthPart(input, `term ${Number(path[0]) + 1} of ${word}`),
8076
9540
  synth: (input) => {
@@ -8215,6 +9679,11 @@ function formulaTypes(profile) {
8215
9679
  return want.to;
8216
9680
  } },
8217
9681
  "formula.if": {
9682
+ declared: () => declared ? [{
9683
+ at: ["truthType"],
9684
+ type: truth,
9685
+ what: "truth type of the profile"
9686
+ }] : [],
8218
9687
  part: (input, path) => {
8219
9688
  if (path[0] === "test") return truthPart(input, "test of if");
8220
9689
  return isUnknown(input.expected, input.machine.domains) ? {} : {
@@ -8231,6 +9700,7 @@ function formulaTypes(profile) {
8231
9700
  "formula.and": logic("and"),
8232
9701
  "formula.or": logic("or"),
8233
9702
  "formula.op": {
9703
+ declared: sigsDeclared,
8234
9704
  part: (input, path) => {
8235
9705
  const read = signatures(input);
8236
9706
  if (read === void 0 || read.sigs.length !== 1) return {};
@@ -8268,19 +9738,31 @@ function formulaTypes(profile) {
8268
9738
  return fitting.every((sig) => docEquals(sig.to, first.to)) ? first.to : "unknown";
8269
9739
  }
8270
9740
  },
8271
- "formula.ext": { synth: (input) => {
8272
- const name = nameOf(input);
8273
- if (profile.ext !== void 0 && Object.hasOwn(profile.ext, name)) {
9741
+ "formula.ext": {
9742
+ declared: () => {
8274
9743
  const types = profile.extTypes;
8275
- const declared = types !== void 0 && Object.hasOwn(types, name) ? types[name] : void 0;
8276
- if (declared === void 0) return "unknown";
8277
- const type = input.contract(declared, `type of ext.${name} in extTypes`);
8278
- return typeIssues(type, input.machine.domains).length > 0 ? "unknown" : type;
9744
+ const own = profile.ext;
9745
+ if (types === void 0 || own === void 0) return [];
9746
+ return Object.keys(types).filter((name) => Object.hasOwn(own, name)).map((name) => ({
9747
+ at: ["extTypes", name],
9748
+ type: types[name],
9749
+ what: `type of ext.${name} in extTypes`
9750
+ }));
9751
+ },
9752
+ synth: (input) => {
9753
+ const name = nameOf(input);
9754
+ if (profile.ext !== void 0 && Object.hasOwn(profile.ext, name)) {
9755
+ const types = profile.extTypes;
9756
+ const declared = types !== void 0 && Object.hasOwn(types, name) ? types[name] : void 0;
9757
+ if (declared === void 0) return "unknown";
9758
+ const type = input.contract(declared, `type of ext.${name} in extTypes`);
9759
+ return typeIssues(type, input.machine.domains).length > 0 ? "unknown" : type;
9760
+ }
9761
+ if (name === "undefined") return "undefined";
9762
+ if (name === "number") return "number";
9763
+ return name === "domain" ? domainTypeOf(input.doc.value, input.machine.domains) : "unknown";
8279
9764
  }
8280
- if (name === "undefined") return "undefined";
8281
- if (name === "number") return "number";
8282
- return name === "domain" ? domainTypeOf(input.doc.value, input.machine.domains) : "unknown";
8283
- } }
9765
+ }
8284
9766
  };
8285
9767
  }
8286
9768
  /**
@@ -13803,707 +15285,532 @@ function checkTruth(env, code, probe) {
13803
15285
  const truth = declaredTruthOf(code);
13804
15286
  if (truth === void 0) return;
13805
15287
  const domains = env.machine.domains;
13806
- if (typeIssues(truth.truthType, domains).length > 0) return;
13807
- const samples = env.results.flatMap((result) => result.ok ? [result.value] : []);
13808
- const of = (value) => `the member ${valueText(value)} of the truth type ${typeText(truth.truthType)}`;
13809
- for (const value of membersOf(truth.truthType, domains, samples)) {
13810
- let given;
13811
- try {
13812
- given = truth.truthy(value);
13813
- } catch (error) {
13814
- report(env, "truth", `The function truthy of the profile throws for ${of(value)}: ${describe(error)}`, () => probe(value));
13815
- return;
13816
- }
13817
- if (typeof given === "boolean") continue;
13818
- report(env, "truth", `The function truthy of the profile gives ${given === void 0 ? "no truth" : valueText(given)} for ${of(value)}. A truth is true or false.`, () => probe(value));
13819
- return;
13820
- }
13821
- }
13822
- /**
13823
- * This function checks the covers of the domains of the machine from samples (D94). Each sample of a covered domain
13824
- * must be in one domain of each valid cover. The samples of a domain come from its list `values`. A domain without
13825
- * that list gets its members from the palette and from the samples of the domains, as for the check `truth`.
13826
- */
13827
- function checkCovers(env, probe) {
13828
- const domains = env.machine.domains;
13829
- if (domains === void 0) return;
13830
- const palette = env.results.flatMap((result) => result.ok ? [result.value] : []);
13831
- const samples = {};
13832
- for (const [name, domain] of Object.entries(domains)) if (domain.covers !== void 0) samples[name] = membersOf(name, domains, palette);
13833
- const found = falseCovers(domains, samples)[0];
13834
- if (found === void 0) return;
13835
- report(env, "cover", `The member ${valueText(found.value)} of the domain ${found.domain} is in no domain of its cover ${found.cover.join(", ")}. The check of types trusts the cover, thus it is unsound for ${found.domain}.`, () => probe(found.value));
13836
- }
13837
- /**
13838
- * This function examines one evaluator or runner of a machine against the obligations of host code (K92, D36). It
13839
- * starts the code directly, without the kernel, with probe parts and a probe runtime. It generates probe documents from
13840
- * the contract of each kind that names the code, and it gives the probe parts chosen and random results.
13841
- *
13842
- * The checks follow the obligations C1 to C8 of `docs/SEMANTICS.md`. Two more checks follow the premises of the
13843
- * simulation of the plan. The check `local` finds state that stays from one call to the next. The check `agree` compares
13844
- * compiled code with its definition. The finding of an obligation names the first probe that breaks it. An empty list
13845
- * means that each probe conforms.
13846
- *
13847
- * The check `truth` tests the declared truth of a formula profile (D86). The check `cover` tests the covers of the
13848
- * domains of the machine from samples (D94).
13849
- *
13850
- * @param machine - The machine with the code and the world of the kinds.
13851
- * @param name - The name of the evaluator or of the runner. A runner wins over an evaluator of the same name.
13852
- * @param options - The verb, the types and the values of the probe documents, and the results of the probe parts. Also
13853
- * the definitions, the capabilities, the names, the seed, the mock and the rule of equality.
13854
- * @returns The first finding of each obligation that the code breaks, in the order of the obligations.
13855
- * @throws {Error} The machine has no code with the name, or no kind names it and the options give no types.
13856
- */
13857
- function conforms(machine, name, options = {}) {
13858
- const verb = options.verb ?? "eval";
13859
- const runnerCode = own(machine.runners, name);
13860
- const code = runnerCode ?? own(machine.evaluators, name);
13861
- if (code === void 0) throw new Error(`The machine has no evaluator and no runner with the name ${name}.`);
13862
- const runner = runnerCode !== void 0;
13863
- const env = {
13864
- machine,
13865
- name,
13866
- verb,
13867
- under: underOf(code, runner),
13868
- definition: definitionOf(machine, name, runner, options.definitions),
13869
- runner,
13870
- results: options.results ?? RESULTS,
13871
- names: options.names ?? NAMES,
13872
- runs: options.runs ?? 12,
13873
- random: random(options.seed ?? 1),
13874
- perform: options.perform,
13875
- equal: options.equal,
13876
- found: /* @__PURE__ */ new Map()
13877
- };
13878
- const types = options.types ?? typesNaming(machine.world, name, verb);
13879
- let first;
13880
- if (types.length === 0) throw new Error(`No kind of the world names ${name} for the verb ${verb}. Give the types of the probe documents in the option types.`);
13881
- for (const type of types) {
13882
- const found = lookupKind(machine.world, type);
13883
- if (!found.ok) throw new Error(`The world has no kind for the type ${typeName(type)}.`);
13884
- const contract = contractOf(env, found.kind, found.path, options.caps);
13885
- const extra = own(options.values, typeName(type)) ?? own(options.values, found.path.join(".")) ?? [];
13886
- for (const sample of samplesOf(type, found.path, found.kind, contract, extra)) {
13887
- first ??= sample;
13888
- examine(env, sample, contract);
13889
- }
13890
- }
13891
- const probeWith = (value) => first === void 0 ? {
13892
- type: typeName(types[0]),
13893
- doc: {
13894
- type: types[0],
13895
- value: null
13896
- },
13897
- results: {},
13898
- waits: [],
13899
- caps: NO_CAPS,
13900
- running: runner
13901
- } : probeOf(first, {
13902
- results: first.split.parts.map(() => ok(value)),
13903
- waits: [],
13904
- caps: NO_CAPS,
13905
- running: runner
13906
- });
13907
- checkTruth(env, code, probeWith);
13908
- checkCovers(env, probeWith);
13909
- return ORDER.filter((obligation) => env.found.has(obligation)).map((obligation) => env.found.get(obligation));
13910
- }
13911
- // src/same.ts
13912
- /**
13913
- * This function tells if two results are the same for an early cutoff (RESULT.SAME). A schedule uses it to stop the
13914
- * work when a part that evaluates again gives the same result. A wrong `true` keeps a stale value, but a wrong `false`
13915
- * only costs work. Thus each rule gives `false` when it is not sure.
13916
- *
13917
- * - Two values compare by the rules of `docEquals`. Lists and plain records compare by their items and fields. Each
13918
- * other value compares with `Object.is`.
13919
- * - Thus `-0` is not `0`, and `NaN` is `NaN`. A date, a map and a closure of `fn` are the same only as themselves.
13920
- * - Two errors are the same when they have the same code, reason and place (RESULT.SAME-ERROR). The cause is not
13921
- * compared. A `Held` value compares its error by the same rule.
13922
- * - A value and an error are not the same.
13923
- *
13924
- * `sameValue` of `agree` uses the same walk, with rules for two tiers (D20). It compares two closures by their
13925
- * parameters, and two errors by their code and place.
13926
- *
13927
- * @param a - The earlier result.
13928
- * @param b - The new result.
13929
- * @param equal - The rule of the host for two values, for example two dates. It answers first, and `undefined` gives the rules above.
13930
- * @returns `true` when the results are the same.
13931
- */
13932
- function sameResult(a, b, equal) {
13933
- if (a.ok && b.ok) return equalWith(a.value, b.value, equal === void 0 ? sameHeld : (x, y) => equal(x, y) ?? sameHeld(x, y));
13934
- if (!a.ok && !b.ok) return sameError(a.error, b.error);
13935
- return false;
13936
- }
13937
- /** The rule of `sameResult` for held errors. Two `Held` values are the same when their errors are the same. */
13938
- function sameHeld(x, y) {
13939
- if (x instanceof Held || y instanceof Held) return x instanceof Held && y instanceof Held && sameError(x.error, y.error);
13940
- }
13941
- /** Two errors are the same when they have the same code, reason and place. An error without a place has no place in both. */
13942
- function sameError(a, b) {
13943
- if (a.code !== b.code || a.reason !== b.reason) return false;
13944
- if (a.place === void 0 || b.place === void 0) return a.place === b.place;
13945
- return docEquals(a.place, b.place);
13946
- }
13947
- // src/reads.ts
13948
- /** One answer serves each list whose reads are all the same. */
13949
- const SAME = /* @__PURE__ */ Object.freeze({ same: true });
13950
- /** This function tells if two lists of hops are the same: the same steps, rungs and things, in order. */
13951
- function sameHops(a, b, equal) {
13952
- if (b === void 0 || a.length !== b.length) return false;
13953
- for (let index = 0; index < a.length; index += 1) {
13954
- const x = a[index];
13955
- const y = b[index];
13956
- if (x.by !== y.by || !docEquals(x.step, y.step) || !sameResult(ok(x.thing), ok(y.thing), equal)) return false;
13957
- }
13958
- return true;
13959
- }
13960
- /**
13961
- * This function gives the error of a name that holds a held error and stops a longer path, or `undefined`. A
13962
- * reference of the formula kit tests the binding of its first name before it resolves the rest of the path
13963
- * (FORMULA.LET). The resolution of the whole path does not show that test.
13964
- */
13965
- function heldStop(root, path) {
13966
- const name = path[1];
13967
- if (path.length <= 2 || path[0] !== "names" || typeof name !== "string" || !Object.hasOwn(root.names, name)) return void 0;
13968
- const bound = root.names[name];
13969
- return bound instanceof Held ? {
13970
- ok: false,
13971
- error: bound.error
13972
- } : void 0;
13973
- }
13974
- /**
13975
- * This function tells if an old result stays valid in a new context (READS.VERIFY, D26). It resolves the path of
13976
- * each free read again, in the order of the list, and it compares what the path reaches with `sameResult`. It stops at
13977
- * the first read that reaches another thing, and it gives that read (READS.CHANGED).
13978
- *
13979
- * - A read that is not free reads a binding that a kind made from earlier reads, for example a name of `let`. The
13980
- * function does not resolve it again.
13981
- * - A thing compares as in `sameResult`. Thus a host thing or a date is the same only as itself. A host gives a new
13982
- * object for a new state, or the option `equal`.
13983
- * - A longer path through a name that holds a `Held` in the new context is a changed read. A reference of the formula
13984
- * kit gives the error of that binding, and the resolution of the path does not show it.
13985
- * - The answer is sound only for a pure document (FACTS.PURE). A document with an effect, a volatile operation or an
13986
- * extension of a profile can read outside `resolve`. The schedule asks `factsOf` first.
13987
- *
13988
- * The values of the context must not change in place, as PLAN.CACHE says for the documents. A value that changed in
13989
- * place is the same object, thus the function cannot see the change.
13990
- *
13991
- * @param target - The machine of the evaluation, or its plan.
13992
- * @param reads - The reads of the evaluation, from the option `reads`.
13993
- * @param context - The new context.
13994
- * @param options - The rule of the host for two things.
13995
- * @returns `{ same: true }` when each free read reaches the same thing, or else the first changed read.
13996
- */
13997
- function verifyReads(target, reads, context, options = {}) {
13998
- const machine = "evaluators" in target ? target : target.machine;
13999
- const root = rootContext(machine, context);
14000
- const equal = options.equal;
14001
- for (let index = 0; index < reads.length; index += 1) {
14002
- const read = reads[index];
14003
- if (!read.free) continue;
14004
- const stop = heldStop(root, read.path);
14005
- if (stop !== void 0) return {
14006
- same: false,
14007
- index,
14008
- read,
14009
- now: stop
14010
- };
14011
- if (read.kept === true) {
14012
- const now = keptAgain(machine, root, read.path);
14013
- if (now === void 0) return {
14014
- same: false,
14015
- index,
14016
- read,
14017
- now: fail("#N/A", "The host does not know the value of the kept read yet.")
14018
- };
14019
- if (!sameResult(read.reached, now, equal)) return {
14020
- same: false,
14021
- index,
14022
- read,
14023
- now
14024
- };
14025
- continue;
14026
- }
14027
- const asked = read.hops !== void 0;
14028
- const now = readAgain(machine, root, read.path, asked);
14029
- if (!sameResult(read.reached, now.reached, equal) || read.hops !== void 0 && !sameHops(read.hops, now.hops, equal)) return {
14030
- same: false,
14031
- index,
14032
- read,
14033
- now: now.reached
14034
- };
14035
- }
14036
- return SAME;
14037
- }
14038
- // src/durable.ts
14039
- /** The most values that a cache of value documents keeps, as in `planner`. */
14040
- const MAX_VALUES = 1e3;
14041
- /** No reads. One frozen list serves each result of a pure document without reads. */
14042
- const NO_READS = /* @__PURE__ */ Object.freeze([]);
14043
- /** The key of the document `-0` in a cache of value documents. A `Map` finds the entry of `0` for `-0`. */
14044
- const NEGATIVE_ZERO = /* @__PURE__ */ Symbol("coeval.negative-zero");
14045
- /** This function makes a cache by document. A document object gives its value one time, as PLAN.CACHE says. */
14046
- function byDocument(make) {
14047
- const objects = /* @__PURE__ */ new WeakMap();
14048
- const values = /* @__PURE__ */ new Map();
14049
- return (doc) => {
14050
- if (typeof doc === "object" && doc !== null) {
14051
- if (objects.has(doc)) return objects.get(doc);
14052
- const made = make(doc);
14053
- objects.set(doc, made);
14054
- return made;
15288
+ if (typeIssues(truth.truthType, domains).length > 0) return;
15289
+ const samples = env.results.flatMap((result) => result.ok ? [result.value] : []);
15290
+ const of = (value) => `the member ${valueText(value)} of the truth type ${typeText(truth.truthType)}`;
15291
+ for (const value of membersOf(truth.truthType, domains, samples)) {
15292
+ let given;
15293
+ try {
15294
+ given = truth.truthy(value);
15295
+ } catch (error) {
15296
+ report(env, "truth", `The function truthy of the profile throws for ${of(value)}: ${describe(error)}`, () => probe(value));
15297
+ return;
14055
15298
  }
14056
- const key = Object.is(doc, -0) ? NEGATIVE_ZERO : doc;
14057
- if (values.has(key)) return values.get(key);
14058
- const made = make(doc);
14059
- if (values.size >= MAX_VALUES) values.clear();
14060
- values.set(key, made);
14061
- return made;
14062
- };
15299
+ if (typeof given === "boolean") continue;
15300
+ report(env, "truth", `The function truthy of the profile gives ${given === void 0 ? "no truth" : valueText(given)} for ${of(value)}. A truth is true or false.`, () => probe(value));
15301
+ return;
15302
+ }
14063
15303
  }
14064
15304
  /**
14065
- * This function makes a cache with two levels of durability for a host or a schedule (R4 P7, D30). The structure is
14066
- * the machine and the documents. The data is each value that a context gives: the names, `self`, `event`, the
14067
- * capabilities and the world of the host.
15305
+ * This function checks the covers of the domains of the machine from samples (D94). Each sample of a covered domain
15306
+ * must be in one domain of each valid cover. The samples of a domain come from its list `values`. A domain without
15307
+ * that list gets its members from the palette and from the samples of the domains, as for the check `truth`.
15308
+ */
15309
+ function checkCovers(env, probe) {
15310
+ const domains = env.machine.domains;
15311
+ if (domains === void 0) return;
15312
+ const palette = env.results.flatMap((result) => result.ok ? [result.value] : []);
15313
+ const samples = {};
15314
+ for (const [name, domain] of Object.entries(domains)) if (domain.covers !== void 0) samples[name] = membersOf(name, domains, palette);
15315
+ const found = falseCovers(domains, samples)[0];
15316
+ if (found === void 0) return;
15317
+ report(env, "cover", `The member ${valueText(found.value)} of the domain ${found.domain} is in no domain of its cover ${found.cover.join(", ")}. The check of types trusts the cover, thus it is unsound for ${found.domain}.`, () => probe(found.value));
15318
+ }
15319
+ /**
15320
+ * This function examines one evaluator or runner of a machine against the obligations of host code (K92, D36). It
15321
+ * starts the code directly, without the kernel, with probe parts and a probe runtime. It generates probe documents from
15322
+ * the contract of each kind that names the code, and it gives the probe parts chosen and random results.
14068
15323
  *
14069
- * - A plan and the facts depend only on the structure. A document object compiles one time for a machine, thus a
14070
- * change of data compiles nothing (DURABLE.DATA).
14071
- * - A result depends on the data too. It stays in its data epoch. After a change of data, a pure document verifies
14072
- * its reads with `verifyReads`, and each other document evaluates again.
14073
- * - An edit gives a new document object, thus only that document compiles. A new machine drops each plan, each fact
14074
- * and each result (DURABLE.STRUCTURE).
15324
+ * The checks follow the obligations C1 to C8 of `docs/SEMANTICS.md`. Two more checks follow the premises of the
15325
+ * simulation of the plan. The check `local` finds state that stays from one call to the next. The check `agree` compares
15326
+ * compiled code with its definition. The finding of an obligation names the first probe that breaks it. An empty list
15327
+ * means that each probe conforms.
14075
15328
  *
14076
- * The host keeps two promises. In one data epoch, the context of a key gives the same data. The values of a
14077
- * context and the documents do not change in place, as PLAN.CACHE and `verifyReads` say.
15329
+ * The check `truth` tests the declared truth of a formula profile (D86). The check `cover` tests the covers of the
15330
+ * domains of the machine from samples (D94).
14078
15331
  *
14079
- * @param machine - The machine of the first structure epoch.
14080
- * @param options - The type of a bare root value, the verb, the volatile reads and the rule of the host for two things.
14081
- * @returns The cache.
15332
+ * @param machine - The machine with the code and the world of the kinds.
15333
+ * @param name - The name of the evaluator or of the runner. A runner wins over an evaluator of the same name.
15334
+ * @param options - The verb, the types and the values of the probe documents, and the results of the probe parts. Also
15335
+ * the definitions, the capabilities, the names, the seed, the mock and the rule of equality.
15336
+ * @returns The first finding of each obligation that the code breaks, in the order of the obligations.
15337
+ * @throws {Error} The machine has no code with the name, or no kind names it and the options give no types.
14082
15338
  */
14083
- function durable(machine, options = {}) {
14084
- const prepareOptions = {
14085
- ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
14086
- ...options.verb === void 0 ? {} : { verb: options.verb }
14087
- };
14088
- const factsOptions = {
14089
- ...prepareOptions,
14090
- ...options.volatile === void 0 ? {} : { volatile: options.volatile }
14091
- };
14092
- const verifyOptions = options.equal === void 0 ? {} : { equal: options.equal };
14093
- const counts = {
14094
- compiles: 0,
14095
- facts: 0,
14096
- evaluations: 0,
14097
- verifications: 0,
14098
- reuses: 0
14099
- };
14100
- const results = /* @__PURE__ */ new Map();
14101
- let current = machine;
14102
- let epochs = {
14103
- structure: 0,
14104
- data: 0
14105
- };
14106
- const plansOf = (m) => byDocument((doc) => {
14107
- counts.compiles += 1;
14108
- return prepare(m, doc, prepareOptions);
14109
- });
14110
- const factsFor = (m) => byDocument((doc) => {
14111
- counts.facts += 1;
14112
- return factsOf(m, doc, factsOptions);
14113
- });
14114
- let plans = plansOf(machine);
14115
- let facts = factsFor(machine);
14116
- return {
14117
- get machine() {
14118
- return current;
14119
- },
14120
- get epochs() {
14121
- return epochs;
14122
- },
14123
- get counts() {
14124
- return { ...counts };
14125
- },
14126
- plan: (doc) => plans(doc),
14127
- facts: (doc) => facts(doc),
14128
- evaluate(key, doc, context) {
14129
- const plan = plans(doc);
14130
- const entry = results.get(key);
14131
- if (entry !== void 0 && entry.plan === plan) {
14132
- if (entry.data === epochs.data) {
14133
- counts.reuses += 1;
14134
- return entry.result;
14135
- }
14136
- if (entry.reads !== void 0) {
14137
- counts.verifications += 1;
14138
- if (verifyReads(plan, entry.reads, context, verifyOptions).same) {
14139
- entry.data = epochs.data;
14140
- counts.reuses += 1;
14141
- return entry.result;
14142
- }
14143
- }
14144
- }
14145
- const reads = facts(doc).pure ? [] : void 0;
14146
- counts.evaluations += 1;
14147
- const result = plan.evaluate(context, reads === void 0 ? void 0 : { reads });
14148
- results.set(key, {
14149
- plan,
14150
- result,
14151
- reads: reads === void 0 ? void 0 : reads.length === 0 ? NO_READS : reads.slice(),
14152
- data: epochs.data
14153
- });
14154
- return result;
14155
- },
14156
- changeData() {
14157
- epochs = {
14158
- structure: epochs.structure,
14159
- data: epochs.data + 1
14160
- };
14161
- },
14162
- changeStructure(next) {
14163
- epochs = {
14164
- structure: epochs.structure + 1,
14165
- data: epochs.data + 1
14166
- };
14167
- if (next === void 0 || next === current) return;
14168
- current = next;
14169
- plans = plansOf(next);
14170
- facts = factsFor(next);
14171
- results.clear();
14172
- },
14173
- forget(key) {
14174
- results.delete(key);
14175
- }
15339
+ function conforms(machine, name, options = {}) {
15340
+ const verb = options.verb ?? "eval";
15341
+ const runnerCode = own(machine.runners, name);
15342
+ const code = runnerCode ?? own(machine.evaluators, name);
15343
+ if (code === void 0) throw new Error(`The machine has no evaluator and no runner with the name ${name}.`);
15344
+ const runner = runnerCode !== void 0;
15345
+ const env = {
15346
+ machine,
15347
+ name,
15348
+ verb,
15349
+ under: underOf(code, runner),
15350
+ definition: definitionOf(machine, name, runner, options.definitions),
15351
+ runner,
15352
+ results: options.results ?? RESULTS,
15353
+ names: options.names ?? NAMES,
15354
+ runs: options.runs ?? 12,
15355
+ random: random(options.seed ?? 1),
15356
+ perform: options.perform,
15357
+ equal: options.equal,
15358
+ found: /* @__PURE__ */ new Map()
14176
15359
  };
14177
- }
14178
- // src/graph.ts
14179
- /** This function gives the indexed form of a graph, with the edges that the options keep. */
14180
- function indexed(graph, options) {
14181
- const eager = options.eager === true;
14182
- const ids = [...graph.keys()];
14183
- const count = ids.length;
14184
- const numbers = /* @__PURE__ */ new Map();
14185
- const sink = new Uint8Array(count);
14186
- ids.forEach((id, index) => {
14187
- numbers.set(id, index);
14188
- if (graph.get(id)?.side === "run") sink[index] = 1;
14189
- });
14190
- const start = new Int32Array(count + 2);
14191
- const targets = [];
14192
- let unknown = false;
14193
- let from = 0;
14194
- for (const node of graph.values()) {
14195
- start[from] = targets.length;
14196
- for (const edge of node.edges) {
14197
- if (eager && edge.lazy) continue;
14198
- if (edge.to === void 0) {
14199
- if (eager) continue;
14200
- unknown = true;
14201
- targets.push(count);
14202
- continue;
14203
- }
14204
- const to = numbers.get(edge.to);
14205
- if (to !== void 0 && sink[to] === 0) targets.push(to);
15360
+ const types = options.types ?? typesNaming(machine.world, name, verb);
15361
+ let first;
15362
+ if (types.length === 0) throw new Error(`No kind of the world names ${name} for the verb ${verb}. Give the types of the probe documents in the option types.`);
15363
+ for (const type of types) {
15364
+ const found = lookupKind(machine.world, type);
15365
+ if (!found.ok) throw new Error(`The world has no kind for the type ${typeName(type)}.`);
15366
+ const contract = contractOf(env, found.kind, found.path, options.caps);
15367
+ const extra = own(options.values, typeName(type)) ?? own(options.values, found.path.join(".")) ?? [];
15368
+ for (const sample of samplesOf(type, found.path, found.kind, contract, extra)) {
15369
+ first ??= sample;
15370
+ examine(env, sample, contract);
14206
15371
  }
14207
- from += 1;
14208
- }
14209
- start[count] = targets.length;
14210
- if (unknown) {
14211
- for (let to = 0; to < count; to += 1) if (sink[to] === 0) targets.push(to);
14212
15372
  }
14213
- start[count + 1] = targets.length;
14214
- return {
14215
- ids,
14216
- size: unknown ? count + 1 : count,
14217
- start,
14218
- targets: Int32Array.from(targets),
14219
- all: unknown ? count : -1
14220
- };
15373
+ const probeWith = (value) => first === void 0 ? {
15374
+ type: typeName(types[0]),
15375
+ doc: {
15376
+ type: types[0],
15377
+ value: null
15378
+ },
15379
+ results: {},
15380
+ waits: [],
15381
+ caps: NO_CAPS,
15382
+ running: runner
15383
+ } : probeOf(first, {
15384
+ results: first.split.parts.map(() => ok(value)),
15385
+ waits: [],
15386
+ caps: NO_CAPS,
15387
+ running: runner
15388
+ });
15389
+ checkTruth(env, code, probeWith);
15390
+ checkCovers(env, probeWith);
15391
+ return ORDER.filter((obligation) => env.found.has(obligation)).map((obligation) => env.found.get(obligation));
15392
+ }
15393
+ // src/same.ts
15394
+ /**
15395
+ * This function tells if two results are the same for an early cutoff (RESULT.SAME). A schedule uses it to stop the
15396
+ * work when a part that evaluates again gives the same result. A wrong `true` keeps a stale value, but a wrong `false`
15397
+ * only costs work. Thus each rule gives `false` when it is not sure.
15398
+ *
15399
+ * - Two values compare by the rules of `docEquals`. Lists and plain records compare by their items and fields. Each
15400
+ * other value compares with `Object.is`.
15401
+ * - Thus `-0` is not `0`, and `NaN` is `NaN`. A date, a map and a closure of `fn` are the same only as themselves.
15402
+ * - Two errors are the same when they have the same code, reason and place (RESULT.SAME-ERROR). The cause is not
15403
+ * compared. A `Held` value compares its error by the same rule.
15404
+ * - A value and an error are not the same.
15405
+ *
15406
+ * `sameValue` of `agree` uses the same walk, with rules for two tiers (D20). It compares two closures by their
15407
+ * parameters, and two errors by their code and place.
15408
+ *
15409
+ * @param a - The earlier result.
15410
+ * @param b - The new result.
15411
+ * @param equal - The rule of the host for two values, for example two dates. It answers first, and `undefined` gives the rules above.
15412
+ * @returns `true` when the results are the same.
15413
+ */
15414
+ function sameResult(a, b, equal) {
15415
+ if (a.ok && b.ok) return equalWith(a.value, b.value, equal === void 0 ? sameHeld : (x, y) => equal(x, y) ?? sameHeld(x, y));
15416
+ if (!a.ok && !b.ok) return sameError(a.error, b.error);
15417
+ return false;
14221
15418
  }
14222
- /**
14223
- * This function finds the strongly connected components with the algorithm of Tarjan. It keeps its own stack of
14224
- * calls in two arrays, thus a long chain does not overflow the stack of the host. Each component comes after each
14225
- * component that its nodes reach: the deepest component comes first.
15419
+ /** The rule of `sameResult` for held errors. Two `Held` values are the same when their errors are the same. */
15420
+ function sameHeld(x, y) {
15421
+ if (x instanceof Held || y instanceof Held) return x instanceof Held && y instanceof Held && sameError(x.error, y.error);
15422
+ }
15423
+ /** Two errors are the same when they have the same code, reason and place. An error without a place has no place in both. */
15424
+ function sameError(a, b) {
15425
+ if (a.code !== b.code || a.reason !== b.reason) return false;
15426
+ if (a.place === void 0 || b.place === void 0) return a.place === b.place;
15427
+ return docEquals(a.place, b.place);
15428
+ }
15429
+ // src/reads.ts
15430
+ /** One answer serves each list whose reads are all the same. */
15431
+ const SAME = /* @__PURE__ */ Object.freeze({ same: true });
15432
+ /** The default limit of the entries in the print of one value. */
15433
+ const PRINT_LIMIT = 1e4;
15434
+ /** The marks of a print. Each mark is a private object, thus no value of a host is the same as a mark. */
15435
+ const OBJECT = /* @__PURE__ */ Object.freeze({ mark: "object" });
15436
+ const LIST = /* @__PURE__ */ Object.freeze({ mark: "list" });
15437
+ const DATE = /* @__PURE__ */ Object.freeze({ mark: "date" });
15438
+ const MAP = /* @__PURE__ */ Object.freeze({ mark: "map" });
15439
+ const SET = /* @__PURE__ */ Object.freeze({ mark: "set" });
15440
+ const SEEN = /* @__PURE__ */ Object.freeze({ mark: "seen" });
15441
+ const STAMP = /* @__PURE__ */ Object.freeze({ mark: "stamp" });
15442
+ /** The print of a value that the walk cannot finish: it is too large, or the host threw. It is not the same as any print. */
15443
+ const NO_PRINT = /* @__PURE__ */ Object.freeze([]);
15444
+ /**
15445
+ * This function gives the print of a value: a flat list of its parts, in the order of a walk (D112). Two prints are
15446
+ * the same when they have the same length, and each entry is the same by `Object.is`.
15447
+ *
15448
+ * - An object starts with a mark and its prototype. A list adds its length, a date its time, and a map or a set
15449
+ * its size and its entries. Then come the count of the own enumerable fields, each name and the kind of each field.
15450
+ * - A field with a getter gives the getter function. The walk does not start host code of a field.
15451
+ * - A primitive value and a function are entries. A function compares by its identity.
15452
+ * - An object that the walk already visited gives the mark `SEEN` and its number. Thus a cycle ends.
15453
+ * - A value with more than `limit` entries, or an exception of the host, gives `NO_PRINT`.
15454
+ *
15455
+ * @param value - The value of a read.
15456
+ * @param options - The limit and the stamp of the host.
15457
+ * @returns The print.
14226
15458
  */
14227
- function strong(graph) {
14228
- const { size, start, targets } = graph;
14229
- const order = new Int32Array(size).fill(-1);
14230
- const low = new Int32Array(size);
14231
- const of = new Int32Array(size).fill(-1);
14232
- const open = new Int32Array(size);
14233
- const onOpen = new Uint8Array(size);
14234
- const calls = new Int32Array(size);
14235
- const next = new Int32Array(size);
14236
- const list = [];
14237
- let top = 0;
14238
- let count = 0;
14239
- const enter = (node, depth) => {
14240
- order[node] = count;
14241
- low[node] = count;
14242
- count += 1;
14243
- open[top] = node;
14244
- top += 1;
14245
- onOpen[node] = 1;
14246
- calls[depth] = node;
14247
- next[depth] = start[node];
14248
- };
14249
- for (let root = 0; root < size; root += 1) {
14250
- if (order[root] !== -1) continue;
14251
- enter(root, 0);
14252
- let depth = 1;
14253
- while (depth > 0) {
14254
- const node = calls[depth - 1];
14255
- const edge = next[depth - 1];
14256
- if (edge < start[node + 1]) {
14257
- next[depth - 1] = edge + 1;
14258
- const to = targets[edge];
14259
- if (order[to] === -1) {
14260
- enter(to, depth);
14261
- depth += 1;
14262
- } else if (onOpen[to] === 1 && order[to] < low[node]) low[node] = order[to];
15459
+ function printOf(value, options) {
15460
+ const limit = options.limit ?? PRINT_LIMIT;
15461
+ const stamp = options.stamp;
15462
+ const out = [];
15463
+ const ids = /* @__PURE__ */ new Map();
15464
+ const stack = [value];
15465
+ try {
15466
+ while (stack.length > 0) {
15467
+ if (out.length > limit) return NO_PRINT;
15468
+ const x = stack.pop();
15469
+ if (typeof x !== "object" || x === null) {
15470
+ out.push(x);
14263
15471
  continue;
14264
15472
  }
14265
- depth -= 1;
14266
- if (low[node] === order[node]) {
14267
- const members = [];
14268
- let member;
14269
- do {
14270
- top -= 1;
14271
- member = open[top];
14272
- onOpen[member] = 0;
14273
- of[member] = list.length;
14274
- members.push(member);
14275
- } while (member !== node);
14276
- list.push(members.sort((a, b) => a - b));
15473
+ const id = ids.get(x);
15474
+ if (id !== void 0) {
15475
+ out.push(SEEN, id);
15476
+ continue;
14277
15477
  }
14278
- if (depth > 0) {
14279
- const reader = calls[depth - 1];
14280
- if (low[node] < low[reader]) low[reader] = low[node];
15478
+ ids.set(x, ids.size);
15479
+ const stamped = stamp?.(x);
15480
+ if (stamped !== void 0) {
15481
+ out.push(STAMP, stamped);
15482
+ continue;
15483
+ }
15484
+ const children = [];
15485
+ out.push(OBJECT, Object.getPrototypeOf(x));
15486
+ if (Array.isArray(x)) out.push(LIST, x.length);
15487
+ else if (x instanceof Date) out.push(DATE, Date.prototype.getTime.call(x));
15488
+ else if (x instanceof Map) {
15489
+ out.push(MAP, x.size);
15490
+ if (out.length + 2 * x.size > limit) return NO_PRINT;
15491
+ for (const [key, item] of Map.prototype.entries.call(x)) children.push(key, item);
15492
+ } else if (x instanceof Set) {
15493
+ out.push(SET, x.size);
15494
+ if (out.length + x.size > limit) return NO_PRINT;
15495
+ for (const item of Set.prototype.values.call(x)) children.push(item);
15496
+ }
15497
+ const keys = Object.keys(x);
15498
+ if (out.length + 3 * keys.length > limit) return NO_PRINT;
15499
+ out.push(keys.length);
15500
+ for (const key of keys) {
15501
+ const field = Object.getOwnPropertyDescriptor(x, key);
15502
+ const data = field === void 0 || "value" in field;
15503
+ out.push(key, data);
15504
+ children.push(field === void 0 ? void 0 : "value" in field ? field.value : field.get);
14281
15505
  }
15506
+ for (let index = children.length - 1; index >= 0; index -= 1) stack.push(children[index]);
14282
15507
  }
15508
+ } catch {
15509
+ return NO_PRINT;
14283
15510
  }
14284
- return {
14285
- of,
14286
- list
14287
- };
14288
- }
14289
- /** This function tells if a component has a cycle: two or more nodes, or one node with an edge to itself. */
14290
- function cyclic(graph, members) {
14291
- if (members.length > 1) return true;
14292
- const node = members[0];
14293
- for (let edge = graph.start[node]; edge < graph.start[node + 1]; edge += 1) if (graph.targets[edge] === node) return true;
14294
- return false;
15511
+ return out.length > limit ? NO_PRINT : out;
14295
15512
  }
14296
- /** This function gives the names of the nodes of a component, without the node `all`. */
14297
- function named$1(graph, members) {
14298
- const out = [];
14299
- for (const member of members) if (member !== graph.all) out.push(graph.ids[member]);
14300
- return out;
15513
+ /** This function tells if two prints are the same. `NO_PRINT` is not the same as any print, also not as itself. */
15514
+ function samePrint(a, b) {
15515
+ if (a === NO_PRINT || b === NO_PRINT || a.length !== b.length) return false;
15516
+ for (let index = 0; index < a.length; index += 1) if (!Object.is(a[index], b[index])) return false;
15517
+ return true;
14301
15518
  }
14302
- /** This function gives the height of each component, in the order of `strong`. The node `all` adds no height. */
14303
- function heightsOf(graph, found) {
14304
- const { start, targets } = graph;
14305
- const heights = new Int32Array(found.list.length);
14306
- found.list.forEach((members, component) => {
14307
- let highest = -1;
14308
- let real = false;
14309
- for (const node of members) {
14310
- if (node !== graph.all) real = true;
14311
- for (let edge = start[node]; edge < start[node + 1]; edge += 1) {
14312
- const other = found.of[targets[edge]];
14313
- if (other !== component && heights[other] > highest) highest = heights[other];
14314
- }
14315
- }
14316
- heights[component] = real ? highest + 1 : highest;
14317
- });
14318
- return heights;
15519
+ /** This function gives the print of the value of a result, or `undefined` when the value holds no object. */
15520
+ function printOfResult(result, options, cache) {
15521
+ if (!result.ok || typeof result.value !== "object" || result.value === null) return void 0;
15522
+ const value = result.value;
15523
+ let print = cache.get(value);
15524
+ if (print === void 0) {
15525
+ print = printOf(value, options);
15526
+ cache.set(value, print);
15527
+ }
15528
+ return print;
14319
15529
  }
14320
15530
  /**
14321
- * This function gives the strongly connected components of a graph of nodes (GRAPH.SCC), with the algorithm of
14322
- * Tarjan. It keeps its own stack, thus a chain of 100000 nodes does not overflow the stack of the host.
15531
+ * This function gives the prints of the values of a list of reads (READS.IN-PLACE, D112). A host starts it after
15532
+ * the evaluation, and it gives the prints to `verifyReads` with the option `prints`.
14323
15533
  *
14324
- * - Each component comes after each component that it reads: the deepest component comes first.
14325
- * - A node that is on no cycle is a component of one node.
14326
- * - The nodes of a component are in the order of the graph.
15534
+ * - The print of a value walks its lists, its plain records and the own enumerable fields of each other object. A
15535
+ * date adds its time, and a map or a set adds its entries.
15536
+ * - A read that is not free, a read that reached an error and a read with a primitive value get no print.
15537
+ * - A cycle ends, because the walk visits each object one time.
15538
+ * - A value with more entries than the limit gets no print. `verifyReads` then gives that read as changed.
14327
15539
  *
14328
- * @param graph - The nodes, each with its edges.
14329
- * @param options - The option `eager` keeps only the eager edges with a target node.
14330
- * @returns The components, deepest first.
15540
+ * The walk does not see the state in a closure or a private field. It does not see a field with a symbol name, a
15541
+ * field that is not enumerable or the value of a getter. A host gives a stamp for such an object, for example its version.
15542
+ *
15543
+ * @param reads - The reads of the evaluation, from the option `reads`.
15544
+ * @param options - The limit and the stamp of the host.
15545
+ * @returns The prints, for the option `prints` of `verifyReads`.
14331
15546
  */
14332
- function components(graph, options = {}) {
14333
- const index = indexed(graph, options);
14334
- const out = [];
14335
- for (const members of strong(index).list) {
14336
- const names = named$1(index, members);
14337
- if (names.length > 0) out.push(names);
15547
+ function printReads(reads, options = {}) {
15548
+ const cache = /* @__PURE__ */ new Map();
15549
+ return {
15550
+ prints: reads.map((read) => read.free ? printOfResult(read.reached, options, cache) : void 0),
15551
+ options
15552
+ };
15553
+ }
15554
+ /** This function tells if the print of a read changed, when the read has a print. */
15555
+ function changedInPlace(prints, index, now, cache) {
15556
+ const old = prints.prints[index];
15557
+ if (old === void 0) return false;
15558
+ const print = printOfResult(now, prints.options, cache);
15559
+ return print === void 0 || !samePrint(old, print);
15560
+ }
15561
+ /** This function tells if two lists of hops are the same: the same steps, rungs and things, in order. */
15562
+ function sameHops(a, b, equal) {
15563
+ if (b === void 0 || a.length !== b.length) return false;
15564
+ for (let index = 0; index < a.length; index += 1) {
15565
+ const x = a[index];
15566
+ const y = b[index];
15567
+ if (x.by !== y.by || !docEquals(x.step, y.step) || !sameResult(ok(x.thing), ok(y.thing), equal)) return false;
14338
15568
  }
14339
- return out;
15569
+ return true;
14340
15570
  }
14341
15571
  /**
14342
- * This function gives the height of each node: the order of a push schedule (GRAPH.ORDER). A schedule that evaluates
14343
- * the nodes from the lowest height up evaluates each node after each node that it reads, except on a cycle.
14344
- *
14345
- * - A node that reads no node outside its component has the height 0.
14346
- * - Each other node is one higher than the highest node that it reads outside its component.
14347
- * - The nodes of one component have one height.
14348
- * - An edge without a target reads each node that is not a sink (GRAPH.UNKNOWN).
14349
- *
14350
- * @param graph - The nodes, each with its edges.
14351
- * @param options - The option `eager` keeps only the eager edges with a target node.
14352
- * @returns The height of each node, in the order of the graph.
15572
+ * This function gives the error of a name that holds a held error and stops a longer path, or `undefined`. A
15573
+ * reference of the formula kit tests the binding of its first name before it resolves the rest of the path
15574
+ * (FORMULA.LET). The resolution of the whole path does not show that test.
14353
15575
  */
14354
- function heights(graph, options = {}) {
14355
- const index = indexed(graph, options);
14356
- const found = strong(index);
14357
- const levels = heightsOf(index, found);
14358
- const out = /* @__PURE__ */ new Map();
14359
- index.ids.forEach((id, node) => out.set(id, levels[found.of[node]]));
14360
- return out;
15576
+ function heldStop(root, path) {
15577
+ const name = path[1];
15578
+ if (path.length <= 2 || path[0] !== "names" || typeof name !== "string" || !Object.hasOwn(root.names, name)) return void 0;
15579
+ const bound = root.names[name];
15580
+ return bound instanceof Held ? {
15581
+ ok: false,
15582
+ error: bound.error
15583
+ } : void 0;
14361
15584
  }
14362
15585
  /**
14363
- * This function puts the nodes in layers by their heights, in linear time (GRAPH.LAYERS). The first layer has the
14364
- * height 0. Two nodes of one layer read each other only inside one component. Thus a push schedule can evaluate the
14365
- * components of one layer at the same time.
15586
+ * This function tells if an old result stays valid in a new context (READS.VERIFY, D26). It resolves the path of
15587
+ * each free read again, in the order of the list, and it compares what the path reaches with `sameResult`. It stops at
15588
+ * the first read that reaches another thing, and it gives that read (READS.CHANGED).
14366
15589
  *
14367
- * @param graph - The nodes, each with its edges.
14368
- * @param options - The option `eager` keeps only the eager edges with a target node.
14369
- * @returns The layers, from the height 0 up. Each layer keeps the order of the graph.
15590
+ * - A read that is not free reads a binding that a kind made from earlier reads, for example a name of `let`. The
15591
+ * function does not resolve it again.
15592
+ * - A thing compares as in `sameResult`. Thus a host thing or a date is the same only as itself. A host gives a new
15593
+ * object for a new state, or the option `equal`.
15594
+ * - A longer path through a name that holds a `Held` in the new context is a changed read. A reference of the formula
15595
+ * kit gives the error of that binding, and the resolution of the path does not show it.
15596
+ * - The answer is sound only for a pure document (FACTS.PURE). A document with an effect, a volatile operation or an
15597
+ * extension of a profile can read outside `resolve`. The schedule asks `factsOf` first.
15598
+ *
15599
+ * The values of the context must not change in place, as PLAN.CACHE says for the documents. A value that changed in
15600
+ * place is the same object, thus `sameResult` cannot see the change. The option `prints` finds such a change
15601
+ * (READS.IN-PLACE). The prints come from `printReads` after the evaluation, and the answer then has the mark `inPlace`.
15602
+ *
15603
+ * @param target - The machine of the evaluation, or its plan.
15604
+ * @param reads - The reads of the evaluation, from the option `reads`.
15605
+ * @param context - The new context.
15606
+ * @param options - The rule of the host for two things, and the prints of the reads.
15607
+ * @returns `{ same: true }` when each free read reaches the same thing, or else the first changed read.
14370
15608
  */
14371
- function nodeLayers(graph, options = {}) {
14372
- const out = [];
14373
- for (const [id, height] of heights(graph, options)) {
14374
- while (out.length <= height) out.push([]);
14375
- out[height]?.push(id);
15609
+ function verifyReads(target, reads, context, options = {}) {
15610
+ const machine = "evaluators" in target ? target : target.machine;
15611
+ const root = rootContext(machine, context);
15612
+ const equal = options.equal;
15613
+ const prints = options.prints;
15614
+ let printed;
15615
+ for (let index = 0; index < reads.length; index += 1) {
15616
+ const read = reads[index];
15617
+ if (!read.free) continue;
15618
+ const stop = heldStop(root, read.path);
15619
+ if (stop !== void 0) return {
15620
+ same: false,
15621
+ index,
15622
+ read,
15623
+ now: stop
15624
+ };
15625
+ if (read.kept === true) {
15626
+ const now = keptAgain(machine, root, read.path);
15627
+ if (now === void 0) return {
15628
+ same: false,
15629
+ index,
15630
+ read,
15631
+ now: fail("#N/A", "The host does not know the value of the kept read yet.")
15632
+ };
15633
+ if (!sameResult(read.reached, now, equal)) return {
15634
+ same: false,
15635
+ index,
15636
+ read,
15637
+ now
15638
+ };
15639
+ if (prints !== void 0 && changedInPlace(prints, index, now, printed ??= /* @__PURE__ */ new Map())) return {
15640
+ same: false,
15641
+ index,
15642
+ read,
15643
+ now,
15644
+ inPlace: true
15645
+ };
15646
+ continue;
15647
+ }
15648
+ const asked = read.hops !== void 0;
15649
+ const now = readAgain(machine, root, read.path, asked);
15650
+ if (!sameResult(read.reached, now.reached, equal) || read.hops !== void 0 && !sameHops(read.hops, now.hops, equal)) return {
15651
+ same: false,
15652
+ index,
15653
+ read,
15654
+ now: now.reached
15655
+ };
15656
+ if (prints !== void 0 && changedInPlace(prints, index, now.reached, printed ??= /* @__PURE__ */ new Map())) return {
15657
+ same: false,
15658
+ index,
15659
+ read,
15660
+ now: now.reached,
15661
+ inPlace: true
15662
+ };
14376
15663
  }
14377
- return out;
15664
+ return SAME;
14378
15665
  }
14379
- /**
14380
- * This function gives the nodes that a set of observed nodes needs (GRAPH.NECESSARY). These are the observed nodes,
14381
- * and each node with a path of edges from them. A push schedule evaluates only these nodes. An observed name that is
14382
- * not a node of the graph adds nothing.
14383
- *
14384
- * @param graph - The nodes, each with its edges.
14385
- * @param observed - The nodes that the host shows or reads.
14386
- * @param options - The option `eager` keeps only the eager edges with a target node.
14387
- * @returns The necessary nodes, in the order of the graph.
14388
- */
14389
- function necessary(graph, observed, options = {}) {
14390
- const index = indexed(graph, options);
14391
- const numbers = /* @__PURE__ */ new Map();
14392
- index.ids.forEach((id, node) => numbers.set(id, node));
14393
- const seen = new Uint8Array(index.size);
14394
- const work = [];
14395
- for (const id of observed) {
14396
- const node = numbers.get(id);
14397
- if (node === void 0 || seen[node] === 1) continue;
14398
- seen[node] = 1;
14399
- work.push(node);
14400
- }
14401
- while (work.length > 0) {
14402
- const node = work.pop();
14403
- for (let edge = index.start[node]; edge < index.start[node + 1]; edge += 1) {
14404
- const to = index.targets[edge];
14405
- if (seen[to] === 1) continue;
14406
- seen[to] = 1;
14407
- work.push(to);
15666
+ // src/durable.ts
15667
+ /** The most values that a cache of value documents keeps, as in `planner`. */
15668
+ const MAX_VALUES = 1e3;
15669
+ /** No reads. One frozen list serves each result of a pure document without reads. */
15670
+ const NO_READS = /* @__PURE__ */ Object.freeze([]);
15671
+ /** The key of the document `-0` in a cache of value documents. A `Map` finds the entry of `0` for `-0`. */
15672
+ const NEGATIVE_ZERO = /* @__PURE__ */ Symbol("coeval.negative-zero");
15673
+ /** This function makes a cache by document. A document object gives its value one time, as PLAN.CACHE says. */
15674
+ function byDocument(make) {
15675
+ const objects = /* @__PURE__ */ new WeakMap();
15676
+ const values = /* @__PURE__ */ new Map();
15677
+ return (doc) => {
15678
+ if (typeof doc === "object" && doc !== null) {
15679
+ if (objects.has(doc)) return objects.get(doc);
15680
+ const made = make(doc);
15681
+ objects.set(doc, made);
15682
+ return made;
14408
15683
  }
14409
- }
14410
- const out = /* @__PURE__ */ new Set();
14411
- index.ids.forEach((id, node) => {
14412
- if (seen[node] === 1) out.add(id);
14413
- });
14414
- return out;
15684
+ const key = Object.is(doc, -0) ? NEGATIVE_ZERO : doc;
15685
+ if (values.has(key)) return values.get(key);
15686
+ const made = make(doc);
15687
+ if (values.size >= MAX_VALUES) values.clear();
15688
+ values.set(key, made);
15689
+ return made;
15690
+ };
14415
15691
  }
14416
15692
  /**
14417
- * This function gives the static cycles of a graph (GRAPH.CYCLE): each component with two or more nodes, and each
14418
- * node with an edge to itself. A cycle of the eager edges with a target is certain, and `check` or a host can report
14419
- * it before a run. Another cycle is possible: an evaluation can skip a lazy read.
15693
+ * This function makes a cache with two levels of durability for a host or a schedule (R4 P7, D30). The structure is
15694
+ * the machine and the documents. The data is each value that a context gives: the names, `self`, `event`, the
15695
+ * capabilities and the world of the host.
14420
15696
  *
14421
- * - A component of all the edges that is also a component of the eager edges is one certain cycle.
14422
- * - Each other component of all the edges is one possible cycle, and each certain cycle in it comes after it.
14423
- * - A read can still fail before it occurs. Thus the demand of D31, not a static cycle, gives the value of each node.
15697
+ * - A plan and the facts depend only on the structure. A document object compiles one time for a machine, thus a
15698
+ * change of data compiles nothing (DURABLE.DATA).
15699
+ * - A result depends on the data too. It stays in its data epoch. After a change of data, a pure document verifies
15700
+ * its reads with `verifyReads`, and each other document evaluates again.
15701
+ * - An edit gives a new document object, thus only that document compiles. A new machine drops each plan, each fact
15702
+ * and each result (DURABLE.STRUCTURE).
14424
15703
  *
14425
- * @param graph - The nodes, each with its edges.
14426
- * @returns The cycles, deepest first.
14427
- */
14428
- function cycles(graph) {
14429
- const every = indexed(graph, {});
14430
- const found = strong(every);
14431
- const eager = indexed(graph, { eager: true });
14432
- const inside = /* @__PURE__ */ new Map();
14433
- for (const members of strong(eager).list) {
14434
- if (!cyclic(eager, members)) continue;
14435
- const component = found.of[members[0]];
14436
- const list = inside.get(component);
14437
- if (list === void 0) inside.set(component, [members]);
14438
- else list.push(members);
14439
- }
14440
- const out = [];
14441
- found.list.forEach((members, component) => {
14442
- if (!cyclic(every, members)) return;
14443
- const nodes = named$1(every, members);
14444
- const certain = inside.get(component) ?? [];
14445
- if (certain.length === 1 && certain[0]?.length === nodes.length) {
14446
- out.push({
14447
- nodes,
14448
- certain: true
14449
- });
14450
- return;
14451
- }
14452
- out.push({
14453
- nodes,
14454
- certain: false
14455
- });
14456
- for (const part of certain) out.push({
14457
- nodes: named$1(eager, part),
14458
- certain: true
14459
- });
14460
- });
14461
- return out;
14462
- }
14463
- /**
14464
- * This function gives the nodes that a demand of a node needs first, deepest first (SCHED.LONG-CHAIN). It follows the
14465
- * eager edges with a target from the node, with its own stack. Each node comes after each node that it reads, except
14466
- * on a cycle, as in an order by heights. The walk costs only the nodes that it enters.
15704
+ * The host keeps two promises. In one data epoch, the context of a key gives the same data. The values of a
15705
+ * context and the documents do not change in place, as PLAN.CACHE and `verifyReads` say. The option `inPlace`
15706
+ * finds a change in place of a value that a pure document read (READS.IN-PLACE).
14467
15707
  *
14468
- * @param from - The node of the demand. It is not in the answer.
14469
- * @param edgesOf - This function gives the edges of a node, or `undefined` for a node that the walk does not enter.
14470
- * @returns The nodes, deepest first.
15708
+ * @param machine - The machine of the first structure epoch.
15709
+ * @param options - The type of a bare root value, the verb, the volatile reads, the rule of the host and the check of changes in place.
15710
+ * @returns The cache.
14471
15711
  */
14472
- function deepestFirst(from, edgesOf) {
14473
- const out = [];
14474
- const first = edgesOf(from);
14475
- if (first === void 0) return out;
14476
- const seen = /* @__PURE__ */ new Set([from]);
14477
- const nodes = [from];
14478
- const lists = [first];
14479
- const positions = [0];
14480
- while (nodes.length > 0) {
14481
- const top = nodes.length - 1;
14482
- const edges = lists[top];
14483
- let position = positions[top];
14484
- let entered = false;
14485
- while (position < edges.length) {
14486
- const edge = edges[position];
14487
- position += 1;
14488
- const to = edge.to;
14489
- if (edge.lazy || to === void 0 || seen.has(to)) continue;
14490
- seen.add(to);
14491
- const more = edgesOf(to);
14492
- if (more === void 0) continue;
14493
- positions[top] = position;
14494
- nodes.push(to);
14495
- lists.push(more);
14496
- positions.push(0);
14497
- entered = true;
14498
- break;
15712
+ function durable(machine, options = {}) {
15713
+ const prepareOptions = {
15714
+ ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
15715
+ ...options.verb === void 0 ? {} : { verb: options.verb }
15716
+ };
15717
+ const factsOptions = {
15718
+ ...prepareOptions,
15719
+ ...options.volatile === void 0 ? {} : { volatile: options.volatile }
15720
+ };
15721
+ const verifyOptions = options.equal === void 0 ? {} : { equal: options.equal };
15722
+ const printOptions = options.inPlace === true ? {} : options.inPlace;
15723
+ const printsOf = printOptions === void 0 ? void 0 : /* @__PURE__ */ new WeakMap();
15724
+ const counts = {
15725
+ compiles: 0,
15726
+ facts: 0,
15727
+ evaluations: 0,
15728
+ verifications: 0,
15729
+ reuses: 0
15730
+ };
15731
+ const results = /* @__PURE__ */ new Map();
15732
+ let current = machine;
15733
+ let epochs = {
15734
+ structure: 0,
15735
+ data: 0
15736
+ };
15737
+ const plansOf = (m) => byDocument((doc) => {
15738
+ counts.compiles += 1;
15739
+ return prepare(m, doc, prepareOptions);
15740
+ });
15741
+ const factsFor = (m) => byDocument((doc) => {
15742
+ counts.facts += 1;
15743
+ return factsOf(m, doc, factsOptions);
15744
+ });
15745
+ let plans = plansOf(machine);
15746
+ let facts = factsFor(machine);
15747
+ return {
15748
+ get machine() {
15749
+ return current;
15750
+ },
15751
+ get epochs() {
15752
+ return epochs;
15753
+ },
15754
+ get counts() {
15755
+ return { ...counts };
15756
+ },
15757
+ plan: (doc) => plans(doc),
15758
+ facts: (doc) => facts(doc),
15759
+ evaluate(key, doc, context) {
15760
+ const plan = plans(doc);
15761
+ const entry = results.get(key);
15762
+ if (entry !== void 0 && entry.plan === plan) {
15763
+ if (entry.data === epochs.data) {
15764
+ counts.reuses += 1;
15765
+ return entry.result;
15766
+ }
15767
+ if (entry.reads !== void 0) {
15768
+ counts.verifications += 1;
15769
+ const prints = printsOf?.get(entry);
15770
+ if (verifyReads(plan, entry.reads, context, prints === void 0 ? verifyOptions : {
15771
+ ...verifyOptions,
15772
+ prints
15773
+ }).same) {
15774
+ entry.data = epochs.data;
15775
+ counts.reuses += 1;
15776
+ return entry.result;
15777
+ }
15778
+ }
15779
+ }
15780
+ const reads = facts(doc).pure ? [] : void 0;
15781
+ counts.evaluations += 1;
15782
+ const result = plan.evaluate(context, reads === void 0 ? void 0 : { reads });
15783
+ const made = {
15784
+ plan,
15785
+ result,
15786
+ reads: reads === void 0 ? void 0 : reads.length === 0 ? NO_READS : reads.slice(),
15787
+ data: epochs.data
15788
+ };
15789
+ results.set(key, made);
15790
+ if (printsOf !== void 0 && made.reads !== void 0) printsOf.set(made, printReads(made.reads, printOptions));
15791
+ return result;
15792
+ },
15793
+ changeData() {
15794
+ epochs = {
15795
+ structure: epochs.structure,
15796
+ data: epochs.data + 1
15797
+ };
15798
+ },
15799
+ changeStructure(next) {
15800
+ epochs = {
15801
+ structure: epochs.structure + 1,
15802
+ data: epochs.data + 1
15803
+ };
15804
+ if (next === void 0 || next === current) return;
15805
+ current = next;
15806
+ plans = plansOf(next);
15807
+ facts = factsFor(next);
15808
+ results.clear();
15809
+ },
15810
+ forget(key) {
15811
+ results.delete(key);
14499
15812
  }
14500
- if (entered) continue;
14501
- const done = nodes.pop();
14502
- lists.pop();
14503
- positions.pop();
14504
- if (nodes.length > 0) out.push(done);
14505
- }
14506
- return out;
15813
+ };
14507
15814
  }
14508
15815
  // src/schedule.ts
14509
15816
  /**
@@ -15507,6 +16814,6 @@ function samplesAt(values, closed, depth) {
15507
16814
  function typeFromSamples(values, options = {}) {
15508
16815
  return samplesAt(values, options.closed === true, 0);
15509
16816
  }
15510
- 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, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, ask, attributeTrace, capKeys, check, checkLatent, checkSteps, checkWorld, classify, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, 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, placeOf, placed, planner, prepare, print, random, recorder, ref, reference, referenceRun, 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 };
16817
+ 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, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, ask, attributeGraph, attributeTrace, attributeVertexId, capKeys, check, checkLatent, checkSteps, checkWorld, classify, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, 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, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
15511
16818
 
15512
16819
  //# sourceMappingURL=index.js.map