@mark1russell7/coeval 0.26.1 → 0.27.1

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
@@ -2410,7 +2410,7 @@ function checkHidden(m, draft) {
2410
2410
  * - A runner hides the evaluator of its name. Thus one part must give both, or the merge gives a conflict.
2411
2411
  * - The hooks `known` compose in the order of the parts. A hook does not answer for a name that a later part replaces.
2412
2412
  * The hooks `facts` compose the same way, and the first answer that is not `undefined` wins.
2413
- * - Each other field, for example `permits`, `adopt`, `roots`, `plain` or `maxDepth`, is one value. Two different
2413
+ * - Each other field, for example `permits`, `adopt`, `roots`, `plain`, `maxDepth` or `maxWork`, is one value. Two different
2414
2414
  * values are a conflict. An absent field has no value.
2415
2415
  *
2416
2416
  * A conflict stops the merge, unless the later part names its path in `replaces`. A part can be a function of the
@@ -2579,483 +2579,578 @@ function restrictMachine(machine, paths) {
2579
2579
  ...tables.domains === void 0 ? {} : { domains: tables.domains }
2580
2580
  };
2581
2581
  }
2582
- // src/language.ts
2583
- const VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
2584
- function numbers$1(version) {
2585
- const found = VERSION.exec(version);
2586
- if (found === null) throw new TypeError(`A language version has the form MAJOR.MINOR.PATCH. The text ${JSON.stringify(version)} does not.`);
2587
- return [
2588
- Number(found[1]),
2589
- Number(found[2]),
2590
- Number(found[3])
2591
- ];
2592
- }
2593
- /**
2594
- * This function tells if a version satisfies a lowest version, by the rules of a caret range of SemVer. The first
2595
- * number that is not zero stays the same, and the version is not lower.
2596
- */
2597
- function compatible(version, lowest) {
2598
- const have = numbers$1(version);
2599
- const want = numbers$1(lowest);
2600
- const stable = want.findIndex((part) => part !== 0);
2601
- const fixed = stable < 0 ? 3 : stable + 1;
2602
- for (let index = 0; index < 3; index += 1) {
2603
- const [a, b] = [have[index], want[index]];
2604
- if (a !== b) return index >= fixed && a > b;
2582
+ // src/parts.ts
2583
+ var Bad$1 = class {
2584
+ reason;
2585
+ at;
2586
+ constructor(reason, at) {
2587
+ this.reason = reason;
2588
+ this.at = at;
2605
2589
  }
2606
- return true;
2607
- }
2608
- /** This function gives the JSON text of a value with its keys in order. A value that is not JSON is an error. */
2609
- function canonical(value, path) {
2610
- if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
2611
- if (typeof value === "number" && Number.isFinite(value)) return JSON.stringify(value);
2612
- if (Array.isArray(value)) return `[${value.map((item, index) => canonical(item, [...path, index])).join(",")}]`;
2613
- if (!isRecord(value)) throw new TypeError(`The data half of a language is JSON. The value at ${JSON.stringify(path)} is not.`);
2614
- return `{${Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key], [...path, key])}`).join(",")}}`;
2615
- }
2616
- function frozen(value) {
2617
- if (typeof value !== "object" || value === null) return value;
2618
- for (const item of Object.values(value)) frozen(item);
2619
- return Object.freeze(value);
2620
- }
2621
- /**
2622
- * This function makes one value of a language. The data half is JSON, thus a host can store it and compare it. The
2623
- * code half binds the evaluator names of the world.
2624
- *
2625
- * The language keeps a frozen copy of its data half, thus a later change to the input changes nothing.
2626
- *
2627
- * @param definition - The name, the version, the world, the needed languages and the code.
2628
- * @returns The language.
2629
- * @throws {TypeError} A version in the definition is not `MAJOR.MINOR.PATCH`, the name is empty, or the
2630
- * data half is not JSON.
2631
- */
2632
- function defineLanguage(definition) {
2633
- if (definition.name === "") throw new TypeError("A language has a name.");
2634
- numbers$1(definition.version);
2635
- const requires = definition.requires ?? {};
2636
- for (const name of Object.keys(requires)) numbers$1(requires[name]);
2637
- const data = canonical({
2638
- requires,
2639
- world: definition.world ?? {}
2640
- }, []);
2641
- const copy = frozen(JSON.parse(data));
2642
- const language = {
2643
- name: definition.name,
2644
- version: definition.version,
2645
- world: copy.world,
2646
- requires: copy.requires,
2647
- data
2648
- };
2649
- return Object.freeze(definition.code === void 0 ? language : {
2650
- ...language,
2651
- code: definition.code
2590
+ };
2591
+ /** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
2592
+ function setOwn$4(target, key, value) {
2593
+ if (key === "__proto__") Object.defineProperty(target, key, {
2594
+ value,
2595
+ enumerable: true,
2596
+ writable: true,
2597
+ configurable: true
2652
2598
  });
2599
+ else target[key] = value;
2653
2600
  }
2654
- function partOf(language) {
2655
- const { code, world } = language;
2656
- return typeof code === "function" ? (prev) => ({
2657
- ...code(prev),
2658
- world
2659
- }) : {
2660
- ...code,
2661
- world
2662
- };
2601
+ const NO_SLOTS = /* @__PURE__ */ Object.freeze([]);
2602
+ function hasSlots(template) {
2603
+ return template.t !== "data";
2663
2604
  }
2664
- /**
2665
- * This function merges languages into one machine, in the order of the arguments, with `mergeMachines`.
2666
- *
2667
- * - A language comes after each language that it names in `requires`, at a compatible version (LANG.REQUIRES).
2668
- * - One language that comes twice counts once. Thus two languages can share a base.
2669
- * - Two versions of one name, or two data halves under one name and one version, are conflicts (LANG.COMPOSE).
2670
- *
2671
- * @param languages - The languages.
2672
- * @returns The machine.
2673
- * @throws {MergeError} The languages do not fit, or their merge has a conflict. The error lists each conflict.
2674
- */
2675
- function compose(...languages) {
2676
- const conflicts = [];
2677
- const parts = [];
2678
- const seen = /* @__PURE__ */ new Map();
2679
- languages.forEach((language, index) => {
2680
- const earlier = seen.get(language.name);
2681
- const conflict = (name, other, reason) => {
2682
- conflicts.push({
2683
- path: ["languages", name],
2684
- parts: [Math.min(other, index), Math.max(other, index)],
2685
- reason
2686
- });
2687
- };
2688
- if (earlier !== void 0) {
2689
- if (earlier.language.version !== language.version) conflict(language.name, earlier.index, "Two versions of one language.");
2690
- else if (earlier.language.data !== language.data) conflict(language.name, earlier.index, "Two languages with one name and one version differ.");
2691
- else if (earlier.language.code !== language.code) parts.push(partOf(language));
2692
- return;
2693
- }
2694
- for (const name of Object.keys(language.requires)) {
2695
- const needed = language.requires[name];
2696
- const found = seen.get(name);
2697
- if (found === void 0) {
2698
- const later = languages.findIndex((other) => other.name === name);
2699
- if (later < 0) conflict(name, index, `A language requires ${name}, and the composition does not have it.`);
2700
- else conflict(name, later, `A language requires ${name}, and ${name} comes after it.`);
2701
- } else if (!compatible(found.language.version, needed)) conflict(name, found.index, `A language requires ${name} ${needed}, and the composition has ${found.language.version}.`);
2702
- }
2703
- seen.set(language.name, {
2704
- language,
2705
- index
2706
- });
2707
- parts.push(partOf(language));
2708
- });
2709
- if (conflicts.length > 0) throw new MergeError(conflicts);
2710
- return mergeMachines(...parts);
2605
+ /** This function gives the shape of a part with the default type `of` and the value type `expect` of its container. */
2606
+ function termOf$1(of, expect) {
2607
+ return {
2608
+ shape: "term",
2609
+ ...of === void 0 ? {} : { of },
2610
+ ...expect === void 0 ? {} : { expect }
2611
+ };
2711
2612
  }
2712
- // src/ladder.ts
2713
- /** The rungs of the ladder, in the order that a question visits them. */
2714
- const RUNGS = [
2715
- "own",
2716
- "kind",
2717
- "default"
2718
- ];
2719
- function entryOf$1(verbs, verb) {
2720
- return verbs !== void 0 && Object.hasOwn(verbs, verb) ? verbs[verb] : void 0;
2613
+ /** This function tells if a shape holds only data: no value of the shape can hold a part. */
2614
+ function isData(shape) {
2615
+ return shape.shape === "none" || shape.shape === "text" || shape.shape === "number" || shape.shape === "one";
2721
2616
  }
2722
- /**
2723
- * This function finds the kind that a type names, and follows each alias. It gives `undefined` for an unknown
2724
- * type.
2725
- *
2726
- * @param world - The world.
2727
- * @param type - The reference to the type.
2728
- * @returns The kind, or `undefined`.
2729
- */
2730
- function kindOf(world, type) {
2731
- const found = lookupKind(world, type);
2732
- return found.ok ? found.kind : void 0;
2617
+ /** This function gives the reason why a value is not data of a shape, or `undefined` when it is. */
2618
+ function dataFault(spec, item) {
2619
+ if (spec.shape === "text") return typeof item === "string" ? void 0 : "The value must be a text.";
2620
+ if (spec.shape === "one") return spec.values.some((value) => docEquals(value, item)) ? void 0 : `The value must be one of ${JSON.stringify(spec.values)}.`;
2621
+ if (typeof item !== "number") return "The value must be a number.";
2622
+ if (spec.whole === true && !Number.isInteger(item)) return "The value must be a whole number.";
2623
+ if (spec.min !== void 0 && !(item >= spec.min)) return `The value must be ${String(spec.min)} or more.`;
2624
+ if (spec.max !== void 0 && !(item <= spec.max)) return `The value must be ${String(spec.max)} or less.`;
2733
2625
  }
2734
- /**
2735
- * This function finds a kind by a text type. It is the same as `kindOf` for a one-key reference.
2736
- *
2737
- * @param world - The world.
2738
- * @param name - The text of the type.
2739
- * @returns The kind, or `undefined`.
2740
- */
2741
- function kindNamed(world, name) {
2742
- return kindOf(world, name);
2626
+ /** This function stops a split when a part has a type that its position does not permit. */
2627
+ function kindFault(kinds, item, of, path) {
2628
+ const type = isEnvelope(item) ? typePath(item.type) : of === void 0 ? void 0 : [of];
2629
+ if (type !== void 0 && kinds.some((kind) => kind.length <= type.length && kind.every((key, index) => String(key) === String(type[index])))) return;
2630
+ const names = kinds.map((kind) => kind.join(".")).join(", ");
2631
+ throw new Bad$1(`${isEnvelope(item) ? `The kind ${typeName(item.type)} is not permitted here.` : "A value without an envelope is not permitted here."} The permitted kinds are ${names}.`, path);
2743
2632
  }
2744
- /** A test that passes each name. A rung of `answerOf` then answers with each entry that it has. */
2745
- const EACH_NAME = () => true;
2746
2633
  /**
2747
- * This function finds the evaluator of a verb without the record of the rungs. It visits the rungs of `ask` in the
2748
- * same order: the own entry, then the kind, then the default of the world (VERB.LADDER). A plan without a trace,
2749
- * `deref` and the walkers of steps use it, thus each verb has one ladder.
2634
+ * This function splits a value into its parts, by the shape that its kind declares. The evaluator, the view and
2635
+ * the static kit use the same split, thus each one sees the same parts.
2750
2636
  *
2751
- * @param world - The world, for its defaults.
2752
- * @param own - The own entries of the document, when it has some.
2753
- * @param kind - The kind of the document. `undefined` skips the kind rung, as for a value without a type. `null` is
2754
- * a kind that the world does not have: the question stops there, as in `ask`.
2755
- * @param verb - The verb, for example `eval`, `format`, `deref` or `step`.
2756
- * @param has - The test of a name. A rung answers only with a name that passes it. The default passes each name.
2757
- * @returns The evaluator name and its rung, or `undefined` when no rung answers.
2637
+ * @param shape - The shape of the value. The default is data.
2638
+ * @param value - The value of the document.
2639
+ * @returns The parts and a way to fill their places, or the reason why the value does not have the shape.
2758
2640
  */
2759
- function answerOf(world, own, kind, verb, has = EACH_NAME) {
2760
- const ownName = entryOf$1(own, verb);
2761
- if (ownName !== void 0 && has(ownName)) return {
2762
- name: ownName,
2763
- rung: "own"
2641
+ function splitParts(shape, value) {
2642
+ if (shape === void 0 || shape.shape === "none") return {
2643
+ ok: true,
2644
+ parts: NO_SLOTS,
2645
+ data: value,
2646
+ fill: () => value
2764
2647
  };
2765
- if (kind === null) return void 0;
2766
- const kindName = kind === void 0 ? void 0 : entryOf$1(kind.verbs, verb);
2767
- if (kindName !== void 0 && has(kindName)) return {
2768
- name: kindName,
2769
- rung: "kind"
2648
+ const parts = [];
2649
+ const slot = (item, path, of, address = false, expect) => {
2650
+ parts.push({
2651
+ path,
2652
+ key: path.join("."),
2653
+ item,
2654
+ ...of === void 0 ? {} : { of },
2655
+ ...address ? { address: true } : {},
2656
+ ...expect === void 0 ? {} : { expect }
2657
+ });
2658
+ return {
2659
+ t: "slot",
2660
+ index: parts.length - 1
2661
+ };
2770
2662
  };
2771
- const fallback = entryOf$1(world.defaults, verb);
2772
- return fallback !== void 0 && has(fallback) ? {
2773
- name: fallback,
2774
- rung: "default"
2775
- } : void 0;
2776
- }
2777
- /**
2778
- * This function asks a document a question, and gives the evaluator that answers it.
2779
- *
2780
- * The question visits the rungs in order: the own entry of the envelope, then its kind, then the default of the
2781
- * world. The type comes from the envelope, or else from the type that the position declares. The type is a
2782
- * reference into the world. The ladder does not guess a type from the shape of a value. Each verb has this ladder:
2783
- * `eval`, `deref`, `step` and each verb of a language (VERB.LADDER).
2784
- *
2785
- * @param world - The kinds and the defaults.
2786
- * @param doc - The header of the document: an envelope, or `{}` for a bare value.
2787
- * @param verb - The verb of the question, for example `eval` or `view`.
2788
- * @param options - The type that the position declares.
2789
- * @returns The answer, with the record of each rung that the question visited.
2790
- */
2791
- function ask(world, doc, verb, options = {}) {
2792
- const steps = [];
2793
- const own = entryOf$1(doc.own, verb);
2794
- if (own !== void 0) {
2795
- steps.push({
2796
- rung: "own",
2797
- outcome: "answers",
2798
- evaluator: own
2799
- });
2663
+ const deep = (item, path, of, expect) => {
2664
+ if (isEnvelope(item)) return slot(item, path, of, false, expect);
2665
+ if (Array.isArray(item)) {
2666
+ const items = item.map((child, index) => deep(child, [...path, index], of, expect));
2667
+ return items.some(hasSlots) ? {
2668
+ t: "list",
2669
+ items
2670
+ } : {
2671
+ t: "data",
2672
+ value: item
2673
+ };
2674
+ }
2675
+ if (isRecord(item)) {
2676
+ const fields = Object.keys(item).map((key) => [key, deep(item[key], [...path, key], of, expect)]);
2677
+ return fields.some(([, child]) => hasSlots(child)) ? {
2678
+ t: "record",
2679
+ fields
2680
+ } : {
2681
+ t: "data",
2682
+ value: item
2683
+ };
2684
+ }
2800
2685
  return {
2801
- verb,
2802
- evaluator: own,
2803
- rung: "own",
2804
- steps
2686
+ t: "data",
2687
+ value: item
2805
2688
  };
2806
- }
2807
- steps.push({
2808
- rung: "own",
2809
- outcome: "no-entry"
2810
- });
2811
- const type = doc.type ?? options.declaredType;
2812
- if (type === void 0) steps.push({
2813
- rung: "kind",
2814
- outcome: "skipped"
2815
- });
2816
- else {
2817
- const source = doc.type === void 0 ? "container" : "document";
2818
- const name = typeName(type);
2819
- const kind = kindOf(world, type);
2820
- if (kind === void 0) {
2821
- steps.push({
2822
- rung: "kind",
2823
- outcome: "unknown-kind",
2824
- kind: name,
2825
- source
2826
- });
2689
+ };
2690
+ const walk = (spec, item, path) => {
2691
+ if (spec === void 0 || spec.shape === "none") return {
2692
+ t: "data",
2693
+ value: item
2694
+ };
2695
+ if (spec.shape === "text" || spec.shape === "number" || spec.shape === "one") {
2696
+ const reason = dataFault(spec, item);
2697
+ if (reason !== void 0) throw new Bad$1(reason, path);
2827
2698
  return {
2828
- verb,
2829
- error: "unknown-kind",
2830
- steps
2699
+ t: "data",
2700
+ value: item
2831
2701
  };
2832
2702
  }
2833
- const entry = entryOf$1(kind.verbs, verb);
2834
- if (entry !== void 0) {
2835
- steps.push({
2836
- rung: "kind",
2837
- outcome: "answers",
2838
- evaluator: entry,
2839
- kind: name,
2840
- source
2841
- });
2703
+ if (spec.shape === "term") {
2704
+ if (spec.kinds !== void 0) kindFault(spec.kinds, item, spec.of, path);
2705
+ return slot(item, path, spec.of, spec.address === true, spec.expect);
2706
+ }
2707
+ if (spec.shape === "deep") return deep(item, path, spec.of, spec.expect);
2708
+ if (spec.shape === "list") {
2709
+ if (!Array.isArray(item)) throw new Bad$1("The value must be a list.", path);
2710
+ const list = item;
2711
+ if (spec.distinct === true) {
2712
+ const twice = list.findIndex((child, index) => list.slice(0, index).some((before) => docEquals(before, child)));
2713
+ if (twice !== -1) throw new Bad$1("The items of the list must be different.", [...path, twice]);
2714
+ }
2715
+ const each = spec.item ?? termOf$1(spec.of, spec.expect);
2716
+ const items = list.map((child, index) => walk(each, child, [...path, index]));
2717
+ return isData(each) ? {
2718
+ t: "data",
2719
+ value: item
2720
+ } : {
2721
+ t: "list",
2722
+ items
2723
+ };
2724
+ }
2725
+ if (!isRecord(item)) throw new Bad$1("The value must be a record.", path);
2726
+ if (spec.shape === "map") {
2727
+ const each = spec.item ?? termOf$1(spec.of, spec.expect);
2842
2728
  return {
2843
- verb,
2844
- evaluator: entry,
2845
- rung: "kind",
2846
- steps
2729
+ t: "record",
2730
+ fields: Object.keys(item).map((key) => [key, walk(each, item[key], [...path, key])])
2847
2731
  };
2848
2732
  }
2849
- steps.push({
2850
- rung: "kind",
2851
- outcome: "no-entry",
2852
- kind: name,
2853
- source
2854
- });
2855
- }
2856
- const fallback = entryOf$1(world.defaults, verb);
2857
- if (fallback !== void 0) {
2858
- steps.push({
2859
- rung: "default",
2860
- outcome: "answers",
2861
- evaluator: fallback
2862
- });
2733
+ for (const name of spec.required ?? []) if (!Object.hasOwn(item, name)) throw new Bad$1(`The field ${name} is missing.`, path);
2734
+ const named = Array.isArray(spec.fields) ? Object.fromEntries(spec.fields.map((name) => [name, termOf$1(spec.of, spec.expect)])) : spec.fields;
2735
+ const fields = [];
2736
+ for (const key of Object.keys(item)) {
2737
+ if (spec.closed === true && !Object.hasOwn(named, key)) throw new Bad$1(`The field ${key} is not a field of this kind.`, [...path, key]);
2738
+ const fieldShape = Object.hasOwn(named, key) ? named[key] : spec.rest;
2739
+ fields.push([key, walk(fieldShape, item[key], [...path, key])]);
2740
+ }
2863
2741
  return {
2864
- verb,
2865
- evaluator: fallback,
2866
- rung: "default",
2867
- steps
2742
+ t: "record",
2743
+ fields
2744
+ };
2745
+ };
2746
+ let template;
2747
+ try {
2748
+ template = walk(shape, value, []);
2749
+ } catch (error) {
2750
+ if (error instanceof Bad$1) return {
2751
+ ok: false,
2752
+ reason: error.reason,
2753
+ at: error.at
2868
2754
  };
2755
+ throw error;
2869
2756
  }
2870
- steps.push({
2871
- rung: "default",
2872
- outcome: "no-entry"
2873
- });
2757
+ const strip = (node) => {
2758
+ if (node.t === "data") return node.value;
2759
+ if (node.t === "slot") return void 0;
2760
+ if (node.t === "list") return node.items.every((child) => child.t === "slot") ? null : node.items.map((child) => strip(child) ?? null);
2761
+ const out = {};
2762
+ for (const [key, child] of node.fields) {
2763
+ const kept = strip(child);
2764
+ if (kept !== void 0) setOwn$4(out, key, kept);
2765
+ }
2766
+ return out;
2767
+ };
2768
+ const fillWith = (node, handles) => {
2769
+ if (node.t === "data") return node.value;
2770
+ if (node.t === "slot") return handles[node.index];
2771
+ if (node.t === "list") return node.items.map((child) => fillWith(child, handles));
2772
+ const out = {};
2773
+ for (const [key, child] of node.fields) setOwn$4(out, key, fillWith(child, handles));
2774
+ return out;
2775
+ };
2874
2776
  return {
2875
- verb,
2876
- error: "no-answer",
2877
- steps
2777
+ ok: true,
2778
+ parts,
2779
+ data: strip(template) ?? null,
2780
+ fill: (handles) => fillWith(template, handles)
2878
2781
  };
2879
2782
  }
2880
- // src/steps.ts
2881
2783
  /**
2882
- * This function makes a ladder of steps, and it checks the declaration (STEPS.LADDER). The list of steps must have one
2883
- * step or more, with no name two times. The step of each construct must be a step of the list.
2784
+ * This function reads one document by the contracts of the world. It finds the kind of the type. A bare value gets
2785
+ * the type that its position declares. Then the function splits the value by the shape of the kind. The plan, the
2786
+ * reference interpreter and the static kit read each document with this function. Thus they see the same parts.
2884
2787
  *
2885
- * @param steps - The names of the steps, from the lowest to the highest.
2886
- * @param constructs - The step that each construct needs.
2887
- * @returns The ladder, frozen.
2888
- * @throws TypeError for a declaration that is not valid, because it is a defect of the language.
2788
+ * @param world - The world of the kinds.
2789
+ * @param value - The document, or a bare value.
2790
+ * @param declaredType - The type that the position of a bare value declares.
2791
+ * @returns The document, its kind and its parts, or the reason why the value is not a document.
2889
2792
  */
2890
- function stepLadder(steps, constructs) {
2891
- if (steps.length === 0) throw new TypeError("a ladder of steps needs one step or more");
2892
- const seen = /* @__PURE__ */ new Set();
2893
- for (const step of steps) {
2894
- if (typeof step !== "string") throw new TypeError(`the step ${String(step)} is not a name`);
2895
- if (seen.has(step)) throw new TypeError(`the step "${step}" is in the ladder two times`);
2896
- seen.add(step);
2897
- }
2898
- for (const [construct, step] of Object.entries(constructs)) if (!seen.has(step)) throw new TypeError(`the construct "${construct}" needs the step "${String(step)}", which is not a step of the ladder`);
2899
- return Object.freeze({
2900
- steps: Object.freeze([...steps]),
2901
- constructs: Object.freeze({ ...constructs })
2902
- });
2793
+ function partsOf(world, value, declaredType) {
2794
+ const envelope = isEnvelope(value) ? value : void 0;
2795
+ if (envelope === void 0 && declaredType === void 0) return {
2796
+ ok: false,
2797
+ code: "#PART?",
2798
+ reason: "The value has no envelope, and its position declares no type."
2799
+ };
2800
+ const doc = envelope ?? {
2801
+ type: declaredType,
2802
+ value
2803
+ };
2804
+ const found = lookupKind(world, doc.type);
2805
+ const kind = found.ok ? found.kind : void 0;
2806
+ const split = splitParts(kind?.parts, doc.value);
2807
+ const typePath = found.ok ? found.path : void 0;
2808
+ if (split.ok) return {
2809
+ ok: true,
2810
+ doc,
2811
+ declared: envelope === void 0,
2812
+ kind,
2813
+ typePath,
2814
+ split
2815
+ };
2816
+ const where = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
2817
+ const reason = `${split.reason}${where} The kind is ${typeName(doc.type)}.`;
2818
+ return {
2819
+ ok: true,
2820
+ doc,
2821
+ declared: envelope === void 0,
2822
+ kind,
2823
+ typePath,
2824
+ split: {
2825
+ ok: false,
2826
+ reason,
2827
+ at: split.at
2828
+ }
2829
+ };
2903
2830
  }
2904
2831
  /**
2905
- * This function tells if a value is a step of a ladder. A host uses it to check its option for the highest step.
2832
+ * This function tells if the path of a part matches a pattern of a scope rule. The key `"*"` of a pattern matches
2833
+ * each key.
2906
2834
  *
2907
- * @param ladder - The ladder.
2908
- * @param value - The value.
2909
- * @returns `true` when the value is the name of a step of the ladder.
2835
+ * @param path - The path of the part.
2836
+ * @param pattern - The pattern.
2837
+ * @returns `true` when the path matches.
2910
2838
  */
2911
- function isStep(ladder, value) {
2912
- return typeof value === "string" && ladder.steps.includes(value);
2839
+ function pathMatches(path, pattern) {
2840
+ if (path.length !== pattern.length) return false;
2841
+ for (let index = 0; index < path.length; index += 1) {
2842
+ const want = pattern[index];
2843
+ if (want !== "*" && String(want) !== String(path[index])) return false;
2844
+ }
2845
+ return true;
2913
2846
  }
2914
2847
  /**
2915
- * This function gives the position of a step in its ladder. The lowest step has the position 0.
2848
+ * This function tells if a list of rules in the form of the lazy rules covers a part (D24, D119). A rule without
2849
+ * `in` covers each part. With `after: n`, a rule covers only the parts after the first `n` parts that it matches.
2916
2850
  *
2917
- * @param ladder - The ladder.
2918
- * @param step - The step.
2919
- * @returns The position.
2920
- * @throws TypeError for a name that is not a step of the ladder.
2851
+ * @param rules - The rules.
2852
+ * @param shape - The shape of the parts of the parent.
2853
+ * @param value - The value of the parent.
2854
+ * @param slot - The path of the part in the value.
2855
+ * @returns `true` when a rule covers the part.
2921
2856
  */
2922
- function stepRank(ladder, step) {
2923
- const rank = ladder.steps.indexOf(step);
2924
- if (rank < 0) throw new TypeError(`"${String(step)}" is not a step of the ladder. The steps are ${ladder.steps.join(", ")}`);
2925
- return rank;
2857
+ function rulesCover(rules, shape, value, slot) {
2858
+ for (const rule of rules) {
2859
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
2860
+ const after = rule.after ?? 0;
2861
+ if (after <= 0) return true;
2862
+ const split = splitParts(shape, value);
2863
+ let count = 0;
2864
+ for (const part of split.ok ? split.parts : []) {
2865
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
2866
+ if (part.path.length === slot.length && pathMatches(part.path, slot)) {
2867
+ if (count >= after) return true;
2868
+ break;
2869
+ }
2870
+ count += 1;
2871
+ }
2872
+ }
2873
+ return false;
2926
2874
  }
2927
- function pathOf(visit) {
2928
- const path = [];
2929
- for (let v = visit; v?.key !== void 0; v = v.parent) path.push(v.key);
2930
- return path.reverse();
2875
+ function valueAt(value, path) {
2876
+ let here = value;
2877
+ for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
2878
+ else if (isRecord(here) && Object.hasOwn(here, String(key))) here = here[String(key)];
2879
+ else return void 0;
2880
+ return here;
2881
+ }
2882
+ function headerName(item) {
2883
+ return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
2884
+ }
2885
+ function namesOf(source, value, covered) {
2886
+ if ("fixed" in source) return source.fixed;
2887
+ if ("keysAt" in source) {
2888
+ const at = valueAt(value, source.keysAt);
2889
+ return isRecord(at) ? Object.keys(at) : [];
2890
+ }
2891
+ if ("listAt" in source) {
2892
+ const at = valueAt(value, source.listAt);
2893
+ return Array.isArray(at) ? at.filter((item) => typeof item === "string") : [];
2894
+ }
2895
+ if ("textAt" in source) {
2896
+ const at = valueAt(value, source.textAt);
2897
+ if (typeof at === "string") return [at];
2898
+ return source.otherwise === void 0 ? [] : [source.otherwise];
2899
+ }
2900
+ return covered.map((slot) => headerName(slot.item)).filter((name) => name !== void 0);
2931
2901
  }
2932
2902
  /**
2933
- * This function gives the lowest step that a document needs, with the reason (STEPS.LOWEST, STEPS.REASON). The step is
2934
- * the highest step of the constructs of its nodes. The reason is the first node in document order with that step. The
2935
- * walk uses its own stack, thus a deep document does not overflow (STEPS.LINEAR). It visits a shared node one time,
2936
- * and it stops at the first node with the highest step of the ladder.
2903
+ * This function gives the names that the scope rules of a kind give each part, and the names that only later parts
2904
+ * see. `check`, `conforms` and the plan read the scope rules with it.
2937
2905
  *
2938
- * @param ladder - The ladder of the language.
2939
- * @param walk - The construct and the child nodes of a node.
2940
- * @param root - The root node of the document.
2941
- * @returns The step, and the reason when the step is not the lowest step.
2906
+ * @param rules - The scope rules of the kind.
2907
+ * @param value - The value of the document.
2908
+ * @param slots - The parts of the value, in order.
2909
+ * @returns The names that each part sees, and the names that only the later parts see, by the index of the part.
2942
2910
  */
2943
- function stepOf(ladder, walk, root) {
2944
- const top = ladder.steps.length - 1;
2945
- let best = 0;
2946
- let reason;
2947
- const seen = /* @__PURE__ */ new Set();
2948
- const todo = [{
2949
- node: root,
2950
- key: void 0,
2951
- parent: void 0
2952
- }];
2953
- for (let visit = todo.pop(); visit !== void 0; visit = todo.pop()) {
2954
- const { node } = visit;
2955
- if (typeof node === "object" && node !== null) {
2956
- if (seen.has(node)) continue;
2957
- seen.add(node);
2958
- }
2959
- const construct = walk.construct(node);
2960
- const step = construct === void 0 || !Object.hasOwn(ladder.constructs, construct) ? void 0 : ladder.constructs[construct];
2961
- const rank = step === void 0 ? 0 : ladder.steps.indexOf(step);
2962
- if (rank > best) {
2963
- best = rank;
2964
- reason = {
2965
- construct,
2966
- step,
2967
- path: pathOf(visit),
2968
- node
2969
- };
2970
- if (best === top) break;
2911
+ function scopesOf(rules, value, slots) {
2912
+ const sees = slots.map(() => []);
2913
+ const later = slots.map(() => []);
2914
+ for (const rule of rules ?? []) {
2915
+ const covered = slots.map((slot, index) => ({
2916
+ slot,
2917
+ index
2918
+ })).filter(({ slot }) => rule.in.some((pattern) => pathMatches(slot.path, pattern)));
2919
+ if (rule.sequential !== true) {
2920
+ const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
2921
+ for (const { index } of covered) sees[index]?.push(...names);
2922
+ continue;
2971
2923
  }
2972
- const kids = [...walk.children(node)];
2973
- for (let i = kids.length - 1; i >= 0; i--) {
2974
- const [key, child] = kids[i];
2975
- todo.push({
2976
- node: child,
2977
- key,
2978
- parent: visit
2924
+ if ("headers" in rule.names) {
2925
+ covered.forEach(({ index }, position) => {
2926
+ const before = covered.slice(0, position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
2927
+ const after = covered.slice(position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
2928
+ sees[index]?.push(...before);
2929
+ later[index]?.push(...after);
2979
2930
  });
2931
+ continue;
2980
2932
  }
2933
+ const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
2934
+ covered.forEach(({ index }, position) => {
2935
+ if (position > 0) sees[index]?.push(...names);
2936
+ else later[index]?.push(...names);
2937
+ });
2981
2938
  }
2982
- const step = ladder.steps[best];
2983
- return reason === void 0 ? { step } : {
2984
- step,
2985
- reason
2939
+ return {
2940
+ sees,
2941
+ later
2986
2942
  };
2987
2943
  }
2944
+ // src/ladder.ts
2945
+ /** The rungs of the ladder, in the order that a question visits them. */
2946
+ const RUNGS = [
2947
+ "own",
2948
+ "kind",
2949
+ "default"
2950
+ ];
2951
+ function entryOf$1(verbs, verb) {
2952
+ return verbs !== void 0 && Object.hasOwn(verbs, verb) ? verbs[verb] : void 0;
2953
+ }
2988
2954
  /**
2989
- * This function compares the step of a document with the highest step that the host accepts (STEPS.MAX). The limit
2990
- * changes only which documents the host accepts. The language evaluates an accepted document as before, thus a limit
2991
- * does not change a value.
2955
+ * This function finds the kind that a type names, and follows each alias. It gives `undefined` for an unknown
2956
+ * type.
2992
2957
  *
2993
- * @param ladder - The ladder of the language.
2994
- * @param need - The step of the document, from `stepOf`.
2995
- * @param maxStep - The highest step that the host accepts.
2996
- * @returns `undefined` when the host accepts the document, or the refusal that names the needed step.
2997
- * @throws TypeError when `maxStep` or the step of `need` is not a step of the ladder.
2958
+ * @param world - The world.
2959
+ * @param type - The reference to the type.
2960
+ * @returns The kind, or `undefined`.
2998
2961
  */
2999
- function checkStep(ladder, need, maxStep) {
3000
- const limit = stepRank(ladder, maxStep);
3001
- if (stepRank(ladder, need.step) <= limit) return void 0;
3002
- const head = `the document needs the step ${need.step}, and the host accepts the steps up to ${maxStep}`;
3003
- const reason = need.reason;
3004
- if (reason === void 0) return {
3005
- needed: need.step,
3006
- maxStep,
3007
- message: head
3008
- };
3009
- const where = reason.path.length === 0 ? "at the root" : `at the path ${JSON.stringify(reason.path)}`;
3010
- return {
3011
- needed: need.step,
3012
- maxStep,
3013
- reason,
3014
- message: `${head}. The construct "${reason.construct}" ${where} needs the step ${reason.step}`
3015
- };
2962
+ function kindOf(world, type) {
2963
+ const found = lookupKind(world, type);
2964
+ return found.ok ? found.kind : void 0;
3016
2965
  }
3017
- // src/deref.ts
3018
- /**
3019
- * The brand of a host thing: an object of the host that answers the steps of a path itself. The brand is a
3020
- * global symbol, thus two copies of the kernel in one program know the things of each other.
3021
- */
3022
- const THING = /* @__PURE__ */ Symbol.for("coeval.thing");
3023
2966
  /**
3024
- * This function tells if a thing is a host thing.
2967
+ * This function finds a kind by a text type. It is the same as `kindOf` for a one-key reference.
3025
2968
  *
3026
- * @param thing - The thing.
3027
- * @returns `true` for a host thing.
2969
+ * @param world - The world.
2970
+ * @param name - The text of the type.
2971
+ * @returns The kind, or `undefined`.
3028
2972
  */
3029
- function isHostThing(thing) {
3030
- return typeof thing === "object" && thing !== null && thing[THING] === true;
3031
- }
3032
- /** The roots of a context. Each path starts with one of them. */
3033
- const ROOTS = [
3034
- "self",
3035
- "names",
3036
- "world",
3037
- "event",
3038
- "caps"
3039
- ];
3040
- /** This function gives the own entries of an envelope, when it has a record of them. */
3041
- function ownEntries(envelope) {
3042
- const own = field(envelope, "own");
3043
- return isRecord(own) ? own : void 0;
2973
+ function kindNamed(world, name) {
2974
+ return kindOf(world, name);
3044
2975
  }
3045
- /** The most kinds in the memo of one world. A larger memo starts again, thus the types of the data cannot fill the memory. */
3046
- const MAX_KINDS = 1e3;
3047
- const kindMemos = /* @__PURE__ */ new WeakMap();
2976
+ /** A test that passes each name. A rung of `answerOf` then answers with each entry that it has. */
2977
+ const EACH_NAME = () => true;
3048
2978
  /**
3049
- * This function gives the kind of a type for the ladder: `null` when the world does not have the kind. The result
3050
- * depends only on the world and on the keys of the type, thus a memo for each world keeps it (PLAN.KIND-MEMO). A
3051
- * world does not change after a plan or a resolution uses it, as for `worldThing`.
2979
+ * This function finds the evaluator of a verb without the record of the rungs. It visits the rungs of `ask` in the
2980
+ * same order: the own entry, then the kind, then the default of the world (VERB.LADDER). A plan without a trace,
2981
+ * `deref` and the walkers of steps use it, thus each verb has one ladder.
2982
+ *
2983
+ * @param world - The world, for its defaults.
2984
+ * @param own - The own entries of the document, when it has some.
2985
+ * @param kind - The kind of the document. `undefined` skips the kind rung, as for a value without a type. `null` is
2986
+ * a kind that the world does not have: the question stops there, as in `ask`.
2987
+ * @param verb - The verb, for example `eval`, `format`, `deref` or `step`.
2988
+ * @param has - The test of a name. A rung answers only with a name that passes it. The default passes each name.
2989
+ * @returns The evaluator name and its rung, or `undefined` when no rung answers.
3052
2990
  */
3053
- function kindFor(world, type) {
3054
- const keys = typeof type === "string" ? void 0 : typePath(type);
3055
- if (typeof type !== "string" && (keys === void 0 || keys.length === 0)) {
3056
- const found = lookupKind(world, type);
3057
- return found.ok ? found.kind : null;
3058
- }
2991
+ function answerOf(world, own, kind, verb, has = EACH_NAME) {
2992
+ const ownName = entryOf$1(own, verb);
2993
+ if (ownName !== void 0 && has(ownName)) return {
2994
+ name: ownName,
2995
+ rung: "own"
2996
+ };
2997
+ if (kind === null) return void 0;
2998
+ const kindName = kind === void 0 ? void 0 : entryOf$1(kind.verbs, verb);
2999
+ if (kindName !== void 0 && has(kindName)) return {
3000
+ name: kindName,
3001
+ rung: "kind"
3002
+ };
3003
+ const fallback = entryOf$1(world.defaults, verb);
3004
+ return fallback !== void 0 && has(fallback) ? {
3005
+ name: fallback,
3006
+ rung: "default"
3007
+ } : void 0;
3008
+ }
3009
+ /**
3010
+ * This function asks a document a question, and gives the evaluator that answers it.
3011
+ *
3012
+ * The question visits the rungs in order: the own entry of the envelope, then its kind, then the default of the
3013
+ * world. The type comes from the envelope, or else from the type that the position declares. The type is a
3014
+ * reference into the world. The ladder does not guess a type from the shape of a value. Each verb has this ladder:
3015
+ * `eval`, `deref`, `step` and each verb of a language (VERB.LADDER).
3016
+ *
3017
+ * @param world - The kinds and the defaults.
3018
+ * @param doc - The header of the document: an envelope, or `{}` for a bare value.
3019
+ * @param verb - The verb of the question, for example `eval` or `view`.
3020
+ * @param options - The type that the position declares.
3021
+ * @returns The answer, with the record of each rung that the question visited.
3022
+ */
3023
+ function ask(world, doc, verb, options = {}) {
3024
+ const steps = [];
3025
+ const own = entryOf$1(doc.own, verb);
3026
+ if (own !== void 0) {
3027
+ steps.push({
3028
+ rung: "own",
3029
+ outcome: "answers",
3030
+ evaluator: own
3031
+ });
3032
+ return {
3033
+ verb,
3034
+ evaluator: own,
3035
+ rung: "own",
3036
+ steps
3037
+ };
3038
+ }
3039
+ steps.push({
3040
+ rung: "own",
3041
+ outcome: "no-entry"
3042
+ });
3043
+ const type = doc.type ?? options.declaredType;
3044
+ if (type === void 0) steps.push({
3045
+ rung: "kind",
3046
+ outcome: "skipped"
3047
+ });
3048
+ else {
3049
+ const source = doc.type === void 0 ? "container" : "document";
3050
+ const name = typeName(type);
3051
+ const kind = kindOf(world, type);
3052
+ if (kind === void 0) {
3053
+ steps.push({
3054
+ rung: "kind",
3055
+ outcome: "unknown-kind",
3056
+ kind: name,
3057
+ source
3058
+ });
3059
+ return {
3060
+ verb,
3061
+ error: "unknown-kind",
3062
+ steps
3063
+ };
3064
+ }
3065
+ const entry = entryOf$1(kind.verbs, verb);
3066
+ if (entry !== void 0) {
3067
+ steps.push({
3068
+ rung: "kind",
3069
+ outcome: "answers",
3070
+ evaluator: entry,
3071
+ kind: name,
3072
+ source
3073
+ });
3074
+ return {
3075
+ verb,
3076
+ evaluator: entry,
3077
+ rung: "kind",
3078
+ steps
3079
+ };
3080
+ }
3081
+ steps.push({
3082
+ rung: "kind",
3083
+ outcome: "no-entry",
3084
+ kind: name,
3085
+ source
3086
+ });
3087
+ }
3088
+ const fallback = entryOf$1(world.defaults, verb);
3089
+ if (fallback !== void 0) {
3090
+ steps.push({
3091
+ rung: "default",
3092
+ outcome: "answers",
3093
+ evaluator: fallback
3094
+ });
3095
+ return {
3096
+ verb,
3097
+ evaluator: fallback,
3098
+ rung: "default",
3099
+ steps
3100
+ };
3101
+ }
3102
+ steps.push({
3103
+ rung: "default",
3104
+ outcome: "no-entry"
3105
+ });
3106
+ return {
3107
+ verb,
3108
+ error: "no-answer",
3109
+ steps
3110
+ };
3111
+ }
3112
+ // src/deref.ts
3113
+ /**
3114
+ * The brand of a host thing: an object of the host that answers the steps of a path itself. The brand is a
3115
+ * global symbol, thus two copies of the kernel in one program know the things of each other.
3116
+ */
3117
+ const THING = /* @__PURE__ */ Symbol.for("coeval.thing");
3118
+ /**
3119
+ * This function tells if a thing is a host thing.
3120
+ *
3121
+ * @param thing - The thing.
3122
+ * @returns `true` for a host thing.
3123
+ */
3124
+ function isHostThing(thing) {
3125
+ return typeof thing === "object" && thing !== null && thing[THING] === true;
3126
+ }
3127
+ /** The roots of a context. Each path starts with one of them. */
3128
+ const ROOTS = [
3129
+ "self",
3130
+ "names",
3131
+ "world",
3132
+ "event",
3133
+ "caps"
3134
+ ];
3135
+ /** This function gives the own entries of an envelope, when it has a record of them. */
3136
+ function ownEntries(envelope) {
3137
+ const own = field(envelope, "own");
3138
+ return isRecord(own) ? own : void 0;
3139
+ }
3140
+ /** The most kinds in the memo of one world. A larger memo starts again, thus the types of the data cannot fill the memory. */
3141
+ const MAX_KINDS = 1e3;
3142
+ const kindMemos = /* @__PURE__ */ new WeakMap();
3143
+ /**
3144
+ * This function gives the kind of a type for the ladder: `null` when the world does not have the kind. The result
3145
+ * depends only on the world and on the keys of the type, thus a memo for each world keeps it (PLAN.KIND-MEMO). A
3146
+ * world does not change after a plan or a resolution uses it, as for `worldThing`.
3147
+ */
3148
+ function kindFor(world, type) {
3149
+ const keys = typeof type === "string" ? void 0 : typePath(type);
3150
+ if (typeof type !== "string" && (keys === void 0 || keys.length === 0)) {
3151
+ const found = lookupKind(world, type);
3152
+ return found.ok ? found.kind : null;
3153
+ }
3059
3154
  let memo = kindMemos.get(world);
3060
3155
  if (memo === void 0 || memo.size >= MAX_KINDS) {
3061
3156
  memo = {
@@ -3119,847 +3214,447 @@ function plainStep(thing, key) {
3119
3214
  const name = String(key);
3120
3215
  return Object.hasOwn(thing, name) ? thing[name] : NOTHING;
3121
3216
  }
3122
- return NOTHING;
3123
- }
3124
- /**
3125
- * This function tells if a value can be an envelope by its field `type`. An envelope has its own field `type`, thus
3126
- * a value without that field is not an envelope, and the full test is not necessary.
3127
- */
3128
- function mayBeEnvelope(thing) {
3129
- return typeof thing === "object" && thing !== null && thing.type !== void 0;
3130
- }
3131
- /**
3132
- * This function answers one step of a path on a thing, through the ladder of the verb `deref`. A host thing
3133
- * answers for itself (own). A document asks its own entry, then its kind, then the default of the world
3134
- * (VERB.LADDER). A rung answers only with a `deref` that the navigator has. When no rung answers, the step goes into
3135
- * the value: an own field of an object, or an item of a list. A value without a type is data, thus the step goes
3136
- * into it at once.
3137
- *
3138
- * @param nav - The world and the code of the evaluators.
3139
- * @param thing - The thing that the path reached.
3140
- * @param key - The key of the step.
3141
- * @returns What the step reaches and the rung that answered, or `undefined` when it reaches nothing.
3142
- */
3143
- function derefStep(nav, thing, key) {
3144
- if (isHostThing(thing)) {
3145
- const reached = thing.deref(key);
3146
- return reached !== void 0 || thing.has?.(key) === true ? {
3147
- thing: reached,
3148
- by: "own"
3149
- } : void 0;
3150
- }
3151
- if (nav.plain !== true && mayBeEnvelope(thing) && isEnvelope(thing)) {
3152
- const envelope = thing;
3153
- const derefs = nav.derefs;
3154
- const answer = derefs === void 0 ? void 0 : answerOf(nav.world, ownEntries(envelope), kindFor(nav.world, envelope.type), "deref", (name) => codeIn(derefs, name));
3155
- if (answer !== void 0) {
3156
- const code = derefs[answer.name];
3157
- const reached = code?.(envelope, key);
3158
- return reached !== void 0 || code?.has?.(envelope, key) === true ? {
3159
- thing: reached,
3160
- by: answer.rung
3161
- } : void 0;
3162
- }
3163
- const reached = plainStep(envelope.value, key);
3164
- return reached === NOTHING ? void 0 : {
3165
- thing: reached,
3166
- by: "default"
3167
- };
3168
- }
3169
- const reached = plainStep(thing, key);
3170
- return reached === NOTHING ? void 0 : {
3171
- thing: reached,
3172
- by: "default"
3173
- };
3174
- }
3175
- /**
3176
- * This function tells if a thing is a reference document: an envelope of the type `ref` with a list for its path.
3177
- *
3178
- * @param thing - The thing.
3179
- * @returns `true` for a reference document.
3180
- */
3181
- function isRef(thing) {
3182
- if (typeof thing !== "object" || thing === null) return false;
3183
- const type = thing.type;
3184
- if (type === void 0 || typeof type === "string" && type !== "ref") return false;
3185
- if (!isEnvelope(thing) || !Array.isArray(thing.value)) return false;
3186
- const path = typePath(thing.type);
3187
- return path !== void 0 && path.length === 1 && path[0] === "ref";
3188
- }
3189
- const worlds = /* @__PURE__ */ new WeakMap();
3190
- /**
3191
- * This function makes the thing of the root `world`: the entries of the world as JSON. An alias is a reference
3192
- * document in it, thus a walk through the world follows each alias (collapse). The thing of a world is made one
3193
- * time.
3194
- *
3195
- * @param world - The world.
3196
- * @returns The thing.
3197
- */
3198
- function worldThing(world) {
3199
- let thing = worlds.get(world);
3200
- if (thing === void 0) {
3201
- thing = entriesAsJson(world.kinds);
3202
- worlds.set(world, thing);
3203
- }
3204
- return thing;
3205
- }
3206
- /**
3207
- * This function makes a context. The world comes from the navigator when the call gives none.
3208
- *
3209
- * @param parts - The roots to set.
3210
- * @returns The context.
3211
- */
3212
- function context(parts = {}) {
3213
- return {
3214
- self: parts.self ?? null,
3215
- names: parts.names ?? {},
3216
- world: parts.world ?? null,
3217
- event: parts.event ?? null,
3218
- caps: parts.caps ?? []
3219
- };
3220
- }
3221
- const MAX_COLLAPSE$1 = 64;
3222
- /** The reason of a resolution that reaches the bound of collapses without a cycle that it found (DEREF.CHAIN-REASON). It is a plain string, thus a bundle drops it (PKG.PURE). */
3223
- const CHAIN_REASON = "The path follows more than 64 references. One resolution follows at most 64.";
3224
- const NO_HOPS$1 = /* @__PURE__ */ Object.freeze([]);
3225
- /** A value that can be a reference document: a record with the type `ref`. The full check comes after. */
3226
- function mayBeRef(thing) {
3227
- return typeof thing === "object" && thing !== null && thing.type === "ref";
3228
- }
3229
- /** This function tells if each step of a path from an index is a key. */
3230
- function keysFrom(path, start) {
3231
- for (let index = start; index < path.length; index += 1) if (!isKey(path[index])) return false;
3232
- return true;
3233
- }
3234
- /** This function tells if a root has a value of its own for the short path: each root except `caps`. */
3235
- function quickRoot(root) {
3236
- return root === "names" || root === "self" || root === "event" || root === "world";
3237
- }
3238
- /**
3239
- * This function resolves the common path without a record of hops: a root, then keys. Plain values answer the
3240
- * keys, or a host thing answers all of them in one call. It gives `undefined` when the path needs the full
3241
- * algorithm. Examples are a host thing without `resolve`, an envelope, a reference to follow, a step document and a
3242
- * failure of a step (for its exact reason).
3243
- */
3244
- function resolveQuick(nav, ctx, path) {
3245
- const root = path[0];
3246
- if (!quickRoot(root)) return void 0;
3247
- if (nav.roots !== void 0 && !nav.roots.includes(root)) return void 0;
3248
- if (nav.adopt !== void 0) return void 0;
3249
- return walkQuick(ctx[root], path, nav.plain === true, false);
3250
- }
3251
- /**
3252
- * This function walks the steps of the short path from the value of the root (DEREF.QUICK). `resolveQuick` and each
3253
- * compiled path use it, thus the two cannot disagree. It gives `undefined` when the path needs the full algorithm.
3254
- *
3255
- * @param start - The value of the root.
3256
- * @param path - The steps. The walk starts at the index 1.
3257
- * @param plain - `true` for a plain navigation.
3258
- * @param keyed - `true` when each step after the root is a key. The walk then does not test the steps again.
3259
- */
3260
- function walkQuick(start, path, plain, keyed) {
3261
- let here = start;
3262
- for (let index = 1; index < path.length; index += 1) {
3263
- if (typeof here !== "object" || here === null) return void 0;
3264
- const type = plain ? void 0 : here.type;
3265
- if (type === "ref") return void 0;
3266
- if (here[THING] === true) {
3267
- const thing = here;
3268
- if (thing.resolve === void 0 || !(keyed || keysFrom(path, index))) return void 0;
3269
- const keys = path.slice(index);
3270
- const reached = thing.resolve(keys);
3271
- if (reached === void 0) return {
3272
- ok: false,
3273
- code: "#N/A",
3274
- reason: `The path ${keys.join(".")} reaches nothing.`,
3275
- hops: NO_HOPS$1
3276
- };
3277
- if (!plain && mayBeRef(reached.thing)) return void 0;
3278
- return {
3279
- ok: true,
3280
- thing: reached.thing,
3281
- hops: NO_HOPS$1
3282
- };
3283
- }
3284
- const step = path[index];
3285
- if (Array.isArray(here)) {
3286
- if (typeof step !== "number" || !Number.isInteger(step) || step < 0 || step >= here.length) return void 0;
3287
- here = here[step];
3288
- continue;
3289
- }
3290
- if (typeof step !== "string" || !Object.hasOwn(here, step)) return void 0;
3291
- if (type !== void 0 && isEnvelope(here)) return void 0;
3292
- here = here[step];
3293
- }
3294
- if (!plain && mayBeRef(here)) return void 0;
3295
- return {
3296
- ok: true,
3297
- thing: here,
3298
- hops: NO_HOPS$1
3299
- };
3300
- }
3301
- /** The root whose value starts the short path of a compiled path. `FULL` takes the full algorithm at once. */
3302
- const FULL = 0;
3303
- const FROM_NAMES = 1;
3304
- const FROM_SELF = 2;
3305
- const FROM_EVENT = 3;
3306
- const FROM_WORLD = 4;
3307
- /**
3308
- * A compiled path as an object with fields (PLAN.LEAN). The code of `resolve` is on the class, thus each compiled path
3309
- * keeps only its fields and makes no closure.
3310
- */
3311
- var StaticPath = class {
3312
- constructor(path, nav, known, from, plain) {
3313
- this.path = path;
3314
- this.nav = nav;
3315
- this.known = known;
3316
- this.from = from;
3317
- this.plain = plain;
3318
- }
3319
- resolve(ctx) {
3320
- const from = this.from;
3321
- if (from !== FULL) {
3322
- const quick = walkQuick(from === FROM_NAMES ? ctx.names : from === FROM_WORLD ? ctx.world : from === FROM_SELF ? ctx.self : ctx.event, this.path, this.plain, true);
3323
- if (quick !== void 0) return quick;
3324
- }
3325
- return resolveFully$1(this.nav, ctx, this.path, void 0, this.known);
3326
- }
3327
- };
3328
- /**
3329
- * This function compiles one static path for one navigator. The resolver gives the same thing, error and reason as
3330
- * `resolve` without hops (PLAN.PATH-SAME). It keeps no value of a context.
3331
- *
3332
- * - Some paths take the full algorithm at once, because the short path cannot answer them. A path from `caps` or from
3333
- * a closed root is one. A path with a step document and each path of a navigator with `adopt` are others.
3334
- * - Each other path walks the short path from its root, and it takes the full algorithm when the values need it.
3335
- * - The walker of each step document comes from the ladder one time, here. The navigator and the step document do
3336
- * not change, thus the answer does not change either.
3337
- *
3338
- * An evaluator of a language calls this function in its `compile`, with the field `machine` of the input, and reads the
3339
- * result with `resolveCompiled` (PLAN.PATH-EXPORT).
3340
- *
3341
- * @param nav - The navigator. A plan compiles its paths for its machine.
3342
- * @param path - The steps. The first step is a root. The compiled path keeps this list, thus the host must not change it.
3343
- * @returns The compiled path.
3344
- */
3345
- function compilePath(nav, path) {
3346
- const keyed = keysFrom(path, 1);
3347
- return new StaticPath(path, nav, keyed ? void 0 : walkersOf(nav, path), startOf(nav, path, keyed), nav.plain === true);
3348
- }
3349
- /** This function gives the root that starts the short path of a compiled path, or `FULL`. */
3350
- function startOf(nav, path, keyed) {
3351
- const root = path[0];
3352
- if (!keyed || !quickRoot(root) || nav.adopt !== void 0) return FULL;
3353
- if (nav.roots !== void 0 && !nav.roots.includes(root)) return FULL;
3354
- return root === "names" ? FROM_NAMES : root === "self" ? FROM_SELF : root === "event" ? FROM_EVENT : FROM_WORLD;
3355
- }
3356
- /**
3357
- * This function asks the ladder of the verb `step` for each step document of a path. A step whose lookup throws
3358
- * stays unknown, thus the full algorithm asks the ladder again for it.
3359
- */
3360
- function walkersOf(nav, path) {
3361
- if (nav.walkers === void 0) return void 0;
3362
- const out = new Array(path.length);
3363
- for (let index = 1; index < path.length; index += 1) {
3364
- const step = path[index];
3365
- if (isKey(step)) continue;
3366
- try {
3367
- out[index] = walkerOf(nav, step) ?? null;
3368
- } catch {}
3369
- }
3370
- return out;
3371
- }
3372
- /**
3373
- * This function resolves a path from a context, and records each hop.
3374
- *
3375
- * The first step is a root of the context. Each later step is a key or a step document. A key goes up the ladder
3376
- * of the verb `deref` on the thing that the path reached. A step document is evaluated by the walker that the
3377
- * ladder of the verb `step` gives, with the thing that the path reached. After each hop, a reference document is
3378
- * followed until the path reaches something else (collapse), except in a plain navigation.
3379
- *
3380
- * The codes of a failure:
3381
- *
3382
- * - `#REF!`: the path has no root, or a root that is not open here.
3383
- * - `#NAME?`: the root `names` has no such name.
3384
- * - `#N/A`: a step reaches nothing.
3385
- * - `#STEP?`: a step is not a key and not a step document.
3386
- * - `#CYCLE!`: the references form a cycle, or the resolution follows more than 64 references. The reason tells
3387
- * which (DEREF.CHAIN-REASON).
3388
- *
3389
- * @param nav - The world and the code of the evaluators.
3390
- * @param ctx - The context.
3391
- * @param path - The steps.
3392
- * @param options - `hops: false` does not record the hops.
3393
- * @returns What the path reached and each hop, or an error.
3394
- */
3395
- function resolve(nav, ctx, path, options = {}) {
3396
- if (options.hops === false) {
3397
- const quick = resolveQuick(nav, ctx, path);
3398
- if (quick !== void 0) return quick;
3399
- }
3400
- return resolveFully$1(nav, ctx, path, options.hops === false ? void 0 : [], void 0);
3401
- }
3402
- /** The functions of the last navigator that gave a walker its input. A walk with the same navigator makes no new functions. */
3403
- let lastSteps;
3404
- /**
3405
- * This function gives the functions `deref` and `has` of the input of a walker. They depend only on the navigator,
3406
- * thus the function keeps the functions of the last navigator (K170).
3407
- */
3408
- function walkSteps(nav) {
3409
- if (lastSteps !== void 0 && lastSteps.nav === nav) return lastSteps;
3410
- const adopt = nav.adopt;
3411
- lastSteps = {
3412
- nav,
3413
- deref: adopt === void 0 ? (thing, key) => derefStep(nav, thing, key)?.thing : (thing, key) => {
3414
- const reached = derefStep(nav, thing, key);
3415
- return reached === void 0 ? void 0 : adopt(reached.thing);
3416
- },
3417
- has: (thing, key) => derefStep(nav, thing, key) !== void 0
3418
- };
3419
- return lastSteps;
3420
- }
3421
- /**
3422
- * This function resolves a path with the full algorithm of `resolve`.
3423
- *
3424
- * @param nav - The world and the code of the evaluators.
3425
- * @param ctx - The context.
3426
- * @param path - The steps.
3427
- * @param hops - The list that gets each hop, or `undefined` for no record.
3428
- * @param known - The walker of each step document of the path, from `compilePath`. A reference that a step reaches has its own steps, and the ladder answers them.
3429
- * @returns What the path reached and each hop, or an error.
3430
- */
3431
- function resolveFully$1(nav, ctx, path, hops, known) {
3432
- const done = hops ?? NO_HOPS$1;
3433
- const failed = (code, reason) => ({
3434
- ok: false,
3435
- code,
3436
- reason,
3437
- hops: done
3438
- });
3439
- let collapses = 0;
3440
- let open;
3441
- const adopt = nav.adopt ?? ((value) => value);
3442
- const collapse = (thing) => {
3443
- let here = thing;
3444
- if (nav.plain === true) return {
3445
- ok: true,
3446
- thing: here,
3447
- hops: done
3448
- };
3449
- while (isRef(here)) {
3450
- if (open?.includes(here) === true) return failed("#CYCLE!", "The references form a cycle.");
3451
- collapses += 1;
3452
- if (collapses > MAX_COLLAPSE$1) return failed("#CYCLE!", CHAIN_REASON);
3453
- open ??= [];
3454
- open.push(here);
3455
- const inner = walk(here.value, void 0);
3456
- open.pop();
3457
- if (!inner.ok) return inner;
3458
- here = adopt(inner.thing);
3459
- hops?.push({
3460
- step: "collapse",
3461
- thing: here,
3462
- by: "collapse"
3463
- });
3464
- }
3465
- return {
3466
- ok: true,
3467
- thing: here,
3468
- hops: done
3469
- };
3470
- };
3471
- const walk = (steps, walkers) => {
3472
- const root = steps[0];
3473
- if (typeof root !== "string" || !ROOTS.includes(root)) return failed("#REF!", `A path starts with a root: ${ROOTS.join(", ")}.`);
3474
- if (nav.roots !== void 0 && !nav.roots.includes(root)) return failed("#REF!", `The root ${root} is not open here. The open roots are ${nav.roots.join(", ")}.`);
3475
- let here = adopt(ctx[root]);
3476
- hops?.push({
3477
- step: root,
3478
- thing: here,
3479
- by: "root"
3480
- });
3481
- const first = collapse(here);
3482
- if (!first.ok) return first;
3483
- here = first.thing;
3484
- for (let index = 1; index < steps.length; index += 1) {
3485
- const step = steps[index];
3486
- if (isHostThing(here) && here.resolve !== void 0 && keysFrom(steps, index)) {
3487
- const keys = steps.slice(index);
3488
- const reached = here.resolve(keys);
3489
- if (reached === void 0) return failed("#N/A", `The path ${keys.join(".")} reaches nothing.`);
3490
- const thing = adopt(reached.thing);
3491
- hops?.push({
3492
- step: keys,
3493
- thing,
3494
- by: "own"
3495
- });
3496
- return collapse(thing);
3497
- }
3498
- if (isKey(step)) {
3499
- const reached = derefStep(nav, here, step);
3500
- if (reached === void 0) {
3501
- if (root === "names" && index === 1) return failed("#NAME?", `The context has no name ${String(step)}.`);
3502
- return failed("#N/A", `The step ${String(step)} reaches nothing.`);
3503
- }
3504
- here = adopt(reached.thing);
3505
- hops?.push({
3506
- step,
3507
- thing: here,
3508
- by: reached.by
3509
- });
3510
- } else {
3511
- const given = walkers?.[index];
3512
- const walker = given === void 0 ? walkerOf(nav, step) : given ?? void 0;
3513
- if (walker === void 0) return failed("#STEP?", "A step is a key, or a document of a kind with the verb step.");
3514
- const envelope = step;
3515
- const { deref, has } = walkSteps(nav);
3516
- const result = walker(hops === void 0 ? {
3517
- data: envelope.value,
3518
- here,
3519
- context: ctx,
3520
- deref,
3521
- has
3522
- } : {
3523
- data: envelope.value,
3524
- here,
3525
- context: ctx,
3526
- deref,
3527
- has,
3528
- visit: (key, thing) => hops.push({
3529
- step: key,
3530
- thing,
3531
- by: "step"
3532
- })
3533
- });
3534
- if (!result.ok) return failed(result.code ?? "#N/A", result.reason);
3535
- here = adopt(result.thing);
3536
- hops?.push({
3537
- step: envelope,
3538
- thing: here,
3539
- by: "step"
3540
- });
3541
- }
3542
- const next = collapse(here);
3543
- if (!next.ok) return next;
3544
- here = next.thing;
3545
- }
3546
- return {
3547
- ok: true,
3548
- thing: here,
3549
- hops: done
3550
- };
3551
- };
3552
- if (path.length === 0) return failed("#REF!", "A path has at least one step: its root.");
3553
- return walk(path, known);
3217
+ return NOTHING;
3554
3218
  }
3555
3219
  /**
3556
- * This function gives the value of a thing: the value that a host thing gives, or else the thing itself.
3557
- *
3558
- * @param thing - The thing.
3559
- * @returns The value.
3220
+ * This function tells if a value can be an envelope by its field `type`. An envelope has its own field `type`, thus
3221
+ * a value without that field is not an envelope, and the full test is not necessary.
3560
3222
  */
3561
- function valueOfThing(thing) {
3562
- return isHostThing(thing) ? thing.toJson() : thing;
3563
- }
3564
- // src/classify.ts
3565
- function isStrictSuperset(larger, smaller) {
3566
- return larger.length > smaller.length && smaller.every((name) => larger.includes(name));
3223
+ function mayBeEnvelope(thing) {
3224
+ return typeof thing === "object" && thing !== null && thing.type !== void 0;
3567
3225
  }
3568
3226
  /**
3569
- * This function proposes a kind for a value without a type, from the fields that the value has.
3570
- * A shape applies when the value has each field of the shape. The most specific shapes are the ones that
3571
- * no other applicable shape contains. A host uses a classifier when data comes in, and then tags the data.
3572
- * The ladder does not call a classifier.
3227
+ * This function answers one step of a path on a thing, through the ladder of the verb `deref`. A host thing
3228
+ * answers for itself (own). A document asks its own entry, then its kind, then the default of the world
3229
+ * (VERB.LADDER). A rung answers only with a `deref` that the navigator has. When no rung answers, the step goes into
3230
+ * the value: an own field of an object, or an item of a list. A value without a type is data, thus the step goes
3231
+ * into it at once.
3573
3232
  *
3574
- * @param shapes - The shapes to examine.
3575
- * @param value - The value without a type.
3576
- * @returns The proposed kind, or an error with the candidates.
3233
+ * @param nav - The world and the code of the evaluators.
3234
+ * @param thing - The thing that the path reached.
3235
+ * @param key - The key of the step.
3236
+ * @returns What the step reaches and the rung that answered, or `undefined` when it reaches nothing.
3577
3237
  */
3578
- function classify(shapes, value) {
3579
- const applicable = isRecord(value) ? shapes.filter((shape) => shape.fields.every((name) => field(value, name) !== void 0)) : [];
3580
- const best = applicable.filter((shape) => !applicable.some((other) => isStrictSuperset(other.fields, shape.fields)));
3581
- const candidates = best.map((shape) => shape.name);
3582
- const only = best.length === 1 ? best[0] : void 0;
3583
- if (only !== void 0) return {
3584
- kind: only.kind,
3585
- candidates
3586
- };
3587
- return {
3588
- candidates,
3589
- error: best.length === 0 ? "no-match" : "ambiguous"
3238
+ function derefStep(nav, thing, key) {
3239
+ if (isHostThing(thing)) {
3240
+ const reached = thing.deref(key);
3241
+ return reached !== void 0 || thing.has?.(key) === true ? {
3242
+ thing: reached,
3243
+ by: "own"
3244
+ } : void 0;
3245
+ }
3246
+ if (nav.plain !== true && mayBeEnvelope(thing) && isEnvelope(thing)) {
3247
+ const envelope = thing;
3248
+ const derefs = nav.derefs;
3249
+ const answer = derefs === void 0 ? void 0 : answerOf(nav.world, ownEntries(envelope), kindFor(nav.world, envelope.type), "deref", (name) => codeIn(derefs, name));
3250
+ if (answer !== void 0) {
3251
+ const code = derefs[answer.name];
3252
+ const reached = code?.(envelope, key);
3253
+ return reached !== void 0 || code?.has?.(envelope, key) === true ? {
3254
+ thing: reached,
3255
+ by: answer.rung
3256
+ } : void 0;
3257
+ }
3258
+ const reached = plainStep(envelope.value, key);
3259
+ return reached === NOTHING ? void 0 : {
3260
+ thing: reached,
3261
+ by: "default"
3262
+ };
3263
+ }
3264
+ const reached = plainStep(thing, key);
3265
+ return reached === NOTHING ? void 0 : {
3266
+ thing: reached,
3267
+ by: "default"
3590
3268
  };
3591
3269
  }
3592
3270
  /**
3593
- * This function puts a value in an envelope with a type. The value does not change.
3271
+ * This function tells if a thing is a reference document: an envelope of the type `ref` with a list for its path.
3594
3272
  *
3595
- * @param value - The value.
3596
- * @param kind - The name of the kind.
3597
- * @returns The envelope.
3273
+ * @param thing - The thing.
3274
+ * @returns `true` for a reference document.
3598
3275
  */
3599
- function tag(value, kind) {
3600
- return typed(kind, value);
3276
+ function isRef(thing) {
3277
+ if (typeof thing !== "object" || thing === null) return false;
3278
+ const type = thing.type;
3279
+ if (type === void 0 || typeof type === "string" && type !== "ref") return false;
3280
+ if (!isEnvelope(thing) || !Array.isArray(thing.value)) return false;
3281
+ const path = typePath(thing.type);
3282
+ return path !== void 0 && path.length === 1 && path[0] === "ref";
3601
3283
  }
3602
- // src/parts.ts
3603
- var Bad$1 = class {
3604
- reason;
3605
- at;
3606
- constructor(reason, at) {
3607
- this.reason = reason;
3608
- this.at = at;
3284
+ const worlds = /* @__PURE__ */ new WeakMap();
3285
+ /**
3286
+ * This function makes the thing of the root `world`: the entries of the world as JSON. An alias is a reference
3287
+ * document in it, thus a walk through the world follows each alias (collapse). The thing of a world is made one
3288
+ * time.
3289
+ *
3290
+ * @param world - The world.
3291
+ * @returns The thing.
3292
+ */
3293
+ function worldThing(world) {
3294
+ let thing = worlds.get(world);
3295
+ if (thing === void 0) {
3296
+ thing = entriesAsJson(world.kinds);
3297
+ worlds.set(world, thing);
3609
3298
  }
3610
- };
3611
- /** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
3612
- function setOwn$4(target, key, value) {
3613
- if (key === "__proto__") Object.defineProperty(target, key, {
3614
- value,
3615
- enumerable: true,
3616
- writable: true,
3617
- configurable: true
3618
- });
3619
- else target[key] = value;
3620
- }
3621
- const NO_SLOTS = /* @__PURE__ */ Object.freeze([]);
3622
- function hasSlots(template) {
3623
- return template.t !== "data";
3624
- }
3625
- /** This function gives the shape of a part with the default type `of` and the value type `expect` of its container. */
3626
- function termOf$1(of, expect) {
3627
- return {
3628
- shape: "term",
3629
- ...of === void 0 ? {} : { of },
3630
- ...expect === void 0 ? {} : { expect }
3631
- };
3632
- }
3633
- /** This function tells if a shape holds only data: no value of the shape can hold a part. */
3634
- function isData(shape) {
3635
- return shape.shape === "none" || shape.shape === "text" || shape.shape === "number" || shape.shape === "one";
3636
- }
3637
- /** This function gives the reason why a value is not data of a shape, or `undefined` when it is. */
3638
- function dataFault(spec, item) {
3639
- if (spec.shape === "text") return typeof item === "string" ? void 0 : "The value must be a text.";
3640
- if (spec.shape === "one") return spec.values.some((value) => docEquals(value, item)) ? void 0 : `The value must be one of ${JSON.stringify(spec.values)}.`;
3641
- if (typeof item !== "number") return "The value must be a number.";
3642
- if (spec.whole === true && !Number.isInteger(item)) return "The value must be a whole number.";
3643
- if (spec.min !== void 0 && !(item >= spec.min)) return `The value must be ${String(spec.min)} or more.`;
3644
- if (spec.max !== void 0 && !(item <= spec.max)) return `The value must be ${String(spec.max)} or less.`;
3645
- }
3646
- /** This function stops a split when a part has a type that its position does not permit. */
3647
- function kindFault(kinds, item, of, path) {
3648
- const type = isEnvelope(item) ? typePath(item.type) : of === void 0 ? void 0 : [of];
3649
- if (type !== void 0 && kinds.some((kind) => kind.length <= type.length && kind.every((key, index) => String(key) === String(type[index])))) return;
3650
- const names = kinds.map((kind) => kind.join(".")).join(", ");
3651
- throw new Bad$1(`${isEnvelope(item) ? `The kind ${typeName(item.type)} is not permitted here.` : "A value without an envelope is not permitted here."} The permitted kinds are ${names}.`, path);
3299
+ return thing;
3652
3300
  }
3653
3301
  /**
3654
- * This function splits a value into its parts, by the shape that its kind declares. The evaluator, the view and
3655
- * the static kit use the same split, thus each one sees the same parts.
3302
+ * This function makes a context. The world comes from the navigator when the call gives none.
3656
3303
  *
3657
- * @param shape - The shape of the value. The default is data.
3658
- * @param value - The value of the document.
3659
- * @returns The parts and a way to fill their places, or the reason why the value does not have the shape.
3304
+ * @param parts - The roots to set.
3305
+ * @returns The context.
3660
3306
  */
3661
- function splitParts(shape, value) {
3662
- if (shape === void 0 || shape.shape === "none") return {
3663
- ok: true,
3664
- parts: NO_SLOTS,
3665
- data: value,
3666
- fill: () => value
3667
- };
3668
- const parts = [];
3669
- const slot = (item, path, of, address = false, expect) => {
3670
- parts.push({
3671
- path,
3672
- key: path.join("."),
3673
- item,
3674
- ...of === void 0 ? {} : { of },
3675
- ...address ? { address: true } : {},
3676
- ...expect === void 0 ? {} : { expect }
3677
- });
3678
- return {
3679
- t: "slot",
3680
- index: parts.length - 1
3681
- };
3682
- };
3683
- const deep = (item, path, of, expect) => {
3684
- if (isEnvelope(item)) return slot(item, path, of, false, expect);
3685
- if (Array.isArray(item)) {
3686
- const items = item.map((child, index) => deep(child, [...path, index], of, expect));
3687
- return items.some(hasSlots) ? {
3688
- t: "list",
3689
- items
3690
- } : {
3691
- t: "data",
3692
- value: item
3693
- };
3694
- }
3695
- if (isRecord(item)) {
3696
- const fields = Object.keys(item).map((key) => [key, deep(item[key], [...path, key], of, expect)]);
3697
- return fields.some(([, child]) => hasSlots(child)) ? {
3698
- t: "record",
3699
- fields
3700
- } : {
3701
- t: "data",
3702
- value: item
3703
- };
3704
- }
3705
- return {
3706
- t: "data",
3707
- value: item
3708
- };
3307
+ function context(parts = {}) {
3308
+ return {
3309
+ self: parts.self ?? null,
3310
+ names: parts.names ?? {},
3311
+ world: parts.world ?? null,
3312
+ event: parts.event ?? null,
3313
+ caps: parts.caps ?? []
3709
3314
  };
3710
- const walk = (spec, item, path) => {
3711
- if (spec === void 0 || spec.shape === "none") return {
3712
- t: "data",
3713
- value: item
3714
- };
3715
- if (spec.shape === "text" || spec.shape === "number" || spec.shape === "one") {
3716
- const reason = dataFault(spec, item);
3717
- if (reason !== void 0) throw new Bad$1(reason, path);
3718
- return {
3719
- t: "data",
3720
- value: item
3721
- };
3722
- }
3723
- if (spec.shape === "term") {
3724
- if (spec.kinds !== void 0) kindFault(spec.kinds, item, spec.of, path);
3725
- return slot(item, path, spec.of, spec.address === true, spec.expect);
3726
- }
3727
- if (spec.shape === "deep") return deep(item, path, spec.of, spec.expect);
3728
- if (spec.shape === "list") {
3729
- if (!Array.isArray(item)) throw new Bad$1("The value must be a list.", path);
3730
- const list = item;
3731
- if (spec.distinct === true) {
3732
- const twice = list.findIndex((child, index) => list.slice(0, index).some((before) => docEquals(before, child)));
3733
- if (twice !== -1) throw new Bad$1("The items of the list must be different.", [...path, twice]);
3734
- }
3735
- const each = spec.item ?? termOf$1(spec.of, spec.expect);
3736
- const items = list.map((child, index) => walk(each, child, [...path, index]));
3737
- return isData(each) ? {
3738
- t: "data",
3739
- value: item
3740
- } : {
3741
- t: "list",
3742
- items
3315
+ }
3316
+ const MAX_COLLAPSE$1 = 64;
3317
+ /** The reason of a resolution that reaches the bound of collapses without a cycle that it found (DEREF.CHAIN-REASON). It is a plain string, thus a bundle drops it (PKG.PURE). */
3318
+ const CHAIN_REASON = "The path follows more than 64 references. One resolution follows at most 64.";
3319
+ const NO_HOPS$1 = /* @__PURE__ */ Object.freeze([]);
3320
+ /** A value that can be a reference document: a record with the type `ref`. The full check comes after. */
3321
+ function mayBeRef(thing) {
3322
+ return typeof thing === "object" && thing !== null && thing.type === "ref";
3323
+ }
3324
+ /** This function tells if each step of a path from an index is a key. */
3325
+ function keysFrom(path, start) {
3326
+ for (let index = start; index < path.length; index += 1) if (!isKey(path[index])) return false;
3327
+ return true;
3328
+ }
3329
+ /** This function tells if a root has a value of its own for the short path: each root except `caps`. */
3330
+ function quickRoot(root) {
3331
+ return root === "names" || root === "self" || root === "event" || root === "world";
3332
+ }
3333
+ /**
3334
+ * This function resolves the common path without a record of hops: a root, then keys. Plain values answer the
3335
+ * keys, or a host thing answers all of them in one call. It gives `undefined` when the path needs the full
3336
+ * algorithm. Examples are a host thing without `resolve`, an envelope, a reference to follow, a step document and a
3337
+ * failure of a step (for its exact reason).
3338
+ */
3339
+ function resolveQuick(nav, ctx, path) {
3340
+ const root = path[0];
3341
+ if (!quickRoot(root)) return void 0;
3342
+ if (nav.roots !== void 0 && !nav.roots.includes(root)) return void 0;
3343
+ if (nav.adopt !== void 0) return void 0;
3344
+ return walkQuick(ctx[root], path, nav.plain === true, false);
3345
+ }
3346
+ /**
3347
+ * This function walks the steps of the short path from the value of the root (DEREF.QUICK). `resolveQuick` and each
3348
+ * compiled path use it, thus the two cannot disagree. It gives `undefined` when the path needs the full algorithm.
3349
+ *
3350
+ * @param start - The value of the root.
3351
+ * @param path - The steps. The walk starts at the index 1.
3352
+ * @param plain - `true` for a plain navigation.
3353
+ * @param keyed - `true` when each step after the root is a key. The walk then does not test the steps again.
3354
+ */
3355
+ function walkQuick(start, path, plain, keyed) {
3356
+ let here = start;
3357
+ for (let index = 1; index < path.length; index += 1) {
3358
+ if (typeof here !== "object" || here === null) return void 0;
3359
+ const type = plain ? void 0 : here.type;
3360
+ if (type === "ref") return void 0;
3361
+ if (here[THING] === true) {
3362
+ const thing = here;
3363
+ if (thing.resolve === void 0 || !(keyed || keysFrom(path, index))) return void 0;
3364
+ const keys = path.slice(index);
3365
+ const reached = thing.resolve(keys);
3366
+ if (reached === void 0) return {
3367
+ ok: false,
3368
+ code: "#N/A",
3369
+ reason: `The path ${keys.join(".")} reaches nothing.`,
3370
+ hops: NO_HOPS$1
3743
3371
  };
3744
- }
3745
- if (!isRecord(item)) throw new Bad$1("The value must be a record.", path);
3746
- if (spec.shape === "map") {
3747
- const each = spec.item ?? termOf$1(spec.of, spec.expect);
3372
+ if (!plain && mayBeRef(reached.thing)) return void 0;
3748
3373
  return {
3749
- t: "record",
3750
- fields: Object.keys(item).map((key) => [key, walk(each, item[key], [...path, key])])
3374
+ ok: true,
3375
+ thing: reached.thing,
3376
+ hops: NO_HOPS$1
3751
3377
  };
3752
3378
  }
3753
- for (const name of spec.required ?? []) if (!Object.hasOwn(item, name)) throw new Bad$1(`The field ${name} is missing.`, path);
3754
- const named = Array.isArray(spec.fields) ? Object.fromEntries(spec.fields.map((name) => [name, termOf$1(spec.of, spec.expect)])) : spec.fields;
3755
- const fields = [];
3756
- for (const key of Object.keys(item)) {
3757
- if (spec.closed === true && !Object.hasOwn(named, key)) throw new Bad$1(`The field ${key} is not a field of this kind.`, [...path, key]);
3758
- const fieldShape = Object.hasOwn(named, key) ? named[key] : spec.rest;
3759
- fields.push([key, walk(fieldShape, item[key], [...path, key])]);
3379
+ const step = path[index];
3380
+ if (Array.isArray(here)) {
3381
+ if (typeof step !== "number" || !Number.isInteger(step) || step < 0 || step >= here.length) return void 0;
3382
+ here = here[step];
3383
+ continue;
3760
3384
  }
3761
- return {
3762
- t: "record",
3763
- fields
3764
- };
3765
- };
3766
- let template;
3767
- try {
3768
- template = walk(shape, value, []);
3769
- } catch (error) {
3770
- if (error instanceof Bad$1) return {
3771
- ok: false,
3772
- reason: error.reason,
3773
- at: error.at
3774
- };
3775
- throw error;
3385
+ if (typeof step !== "string" || !Object.hasOwn(here, step)) return void 0;
3386
+ if (type !== void 0 && isEnvelope(here)) return void 0;
3387
+ here = here[step];
3776
3388
  }
3777
- const strip = (node) => {
3778
- if (node.t === "data") return node.value;
3779
- if (node.t === "slot") return void 0;
3780
- if (node.t === "list") return node.items.every((child) => child.t === "slot") ? null : node.items.map((child) => strip(child) ?? null);
3781
- const out = {};
3782
- for (const [key, child] of node.fields) {
3783
- const kept = strip(child);
3784
- if (kept !== void 0) setOwn$4(out, key, kept);
3785
- }
3786
- return out;
3787
- };
3788
- const fillWith = (node, handles) => {
3789
- if (node.t === "data") return node.value;
3790
- if (node.t === "slot") return handles[node.index];
3791
- if (node.t === "list") return node.items.map((child) => fillWith(child, handles));
3792
- const out = {};
3793
- for (const [key, child] of node.fields) setOwn$4(out, key, fillWith(child, handles));
3794
- return out;
3795
- };
3389
+ if (!plain && mayBeRef(here)) return void 0;
3796
3390
  return {
3797
3391
  ok: true,
3798
- parts,
3799
- data: strip(template) ?? null,
3800
- fill: (handles) => fillWith(template, handles)
3392
+ thing: here,
3393
+ hops: NO_HOPS$1
3801
3394
  };
3802
3395
  }
3396
+ /** The root whose value starts the short path of a compiled path. `FULL` takes the full algorithm at once. */
3397
+ const FULL = 0;
3398
+ const FROM_NAMES = 1;
3399
+ const FROM_SELF = 2;
3400
+ const FROM_EVENT = 3;
3401
+ const FROM_WORLD = 4;
3803
3402
  /**
3804
- * This function reads one document by the contracts of the world. It finds the kind of the type. A bare value gets
3805
- * the type that its position declares. Then the function splits the value by the shape of the kind. The plan, the
3806
- * reference interpreter and the static kit read each document with this function. Thus they see the same parts.
3807
- *
3808
- * @param world - The world of the kinds.
3809
- * @param value - The document, or a bare value.
3810
- * @param declaredType - The type that the position of a bare value declares.
3811
- * @returns The document, its kind and its parts, or the reason why the value is not a document.
3403
+ * A compiled path as an object with fields (PLAN.LEAN). The code of `resolve` is on the class, thus each compiled path
3404
+ * keeps only its fields and makes no closure.
3812
3405
  */
3813
- function partsOf(world, value, declaredType) {
3814
- const envelope = isEnvelope(value) ? value : void 0;
3815
- if (envelope === void 0 && declaredType === void 0) return {
3816
- ok: false,
3817
- code: "#PART?",
3818
- reason: "The value has no envelope, and its position declares no type."
3819
- };
3820
- const doc = envelope ?? {
3821
- type: declaredType,
3822
- value
3823
- };
3824
- const found = lookupKind(world, doc.type);
3825
- const kind = found.ok ? found.kind : void 0;
3826
- const split = splitParts(kind?.parts, doc.value);
3827
- const typePath = found.ok ? found.path : void 0;
3828
- if (split.ok) return {
3829
- ok: true,
3830
- doc,
3831
- declared: envelope === void 0,
3832
- kind,
3833
- typePath,
3834
- split
3835
- };
3836
- const where = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
3837
- const reason = `${split.reason}${where} The kind is ${typeName(doc.type)}.`;
3838
- return {
3839
- ok: true,
3840
- doc,
3841
- declared: envelope === void 0,
3842
- kind,
3843
- typePath,
3844
- split: {
3845
- ok: false,
3846
- reason,
3847
- at: split.at
3406
+ var StaticPath = class {
3407
+ constructor(path, nav, known, from, plain) {
3408
+ this.path = path;
3409
+ this.nav = nav;
3410
+ this.known = known;
3411
+ this.from = from;
3412
+ this.plain = plain;
3413
+ }
3414
+ resolve(ctx) {
3415
+ const from = this.from;
3416
+ if (from !== FULL) {
3417
+ const quick = walkQuick(from === FROM_NAMES ? ctx.names : from === FROM_WORLD ? ctx.world : from === FROM_SELF ? ctx.self : ctx.event, this.path, this.plain, true);
3418
+ if (quick !== void 0) return quick;
3848
3419
  }
3849
- };
3850
- }
3420
+ return resolveFully$1(this.nav, ctx, this.path, void 0, this.known);
3421
+ }
3422
+ };
3851
3423
  /**
3852
- * This function tells if the path of a part matches a pattern of a scope rule. The key `"*"` of a pattern matches
3853
- * each key.
3424
+ * This function compiles one static path for one navigator. The resolver gives the same thing, error and reason as
3425
+ * `resolve` without hops (PLAN.PATH-SAME). It keeps no value of a context.
3854
3426
  *
3855
- * @param path - The path of the part.
3856
- * @param pattern - The pattern.
3857
- * @returns `true` when the path matches.
3427
+ * - Some paths take the full algorithm at once, because the short path cannot answer them. A path from `caps` or from
3428
+ * a closed root is one. A path with a step document and each path of a navigator with `adopt` are others.
3429
+ * - Each other path walks the short path from its root, and it takes the full algorithm when the values need it.
3430
+ * - The walker of each step document comes from the ladder one time, here. The navigator and the step document do
3431
+ * not change, thus the answer does not change either.
3432
+ *
3433
+ * An evaluator of a language calls this function in its `compile`, with the field `machine` of the input, and reads the
3434
+ * result with `resolveCompiled` (PLAN.PATH-EXPORT).
3435
+ *
3436
+ * @param nav - The navigator. A plan compiles its paths for its machine.
3437
+ * @param path - The steps. The first step is a root. The compiled path keeps this list, thus the host must not change it.
3438
+ * @returns The compiled path.
3858
3439
  */
3859
- function pathMatches(path, pattern) {
3860
- if (path.length !== pattern.length) return false;
3861
- for (let index = 0; index < path.length; index += 1) {
3862
- const want = pattern[index];
3863
- if (want !== "*" && String(want) !== String(path[index])) return false;
3440
+ function compilePath(nav, path) {
3441
+ const keyed = keysFrom(path, 1);
3442
+ return new StaticPath(path, nav, keyed ? void 0 : walkersOf(nav, path), startOf(nav, path, keyed), nav.plain === true);
3443
+ }
3444
+ /** This function gives the root that starts the short path of a compiled path, or `FULL`. */
3445
+ function startOf(nav, path, keyed) {
3446
+ const root = path[0];
3447
+ if (!keyed || !quickRoot(root) || nav.adopt !== void 0) return FULL;
3448
+ if (nav.roots !== void 0 && !nav.roots.includes(root)) return FULL;
3449
+ return root === "names" ? FROM_NAMES : root === "self" ? FROM_SELF : root === "event" ? FROM_EVENT : FROM_WORLD;
3450
+ }
3451
+ /**
3452
+ * This function asks the ladder of the verb `step` for each step document of a path. A step whose lookup throws
3453
+ * stays unknown, thus the full algorithm asks the ladder again for it.
3454
+ */
3455
+ function walkersOf(nav, path) {
3456
+ if (nav.walkers === void 0) return void 0;
3457
+ const out = new Array(path.length);
3458
+ for (let index = 1; index < path.length; index += 1) {
3459
+ const step = path[index];
3460
+ if (isKey(step)) continue;
3461
+ try {
3462
+ out[index] = walkerOf(nav, step) ?? null;
3463
+ } catch {}
3864
3464
  }
3865
- return true;
3465
+ return out;
3866
3466
  }
3867
3467
  /**
3868
- * This function tells if a list of rules in the form of the lazy rules covers a part (D24, D119). A rule without
3869
- * `in` covers each part. With `after: n`, a rule covers only the parts after the first `n` parts that it matches.
3468
+ * This function resolves a path from a context, and records each hop.
3870
3469
  *
3871
- * @param rules - The rules.
3872
- * @param shape - The shape of the parts of the parent.
3873
- * @param value - The value of the parent.
3874
- * @param slot - The path of the part in the value.
3875
- * @returns `true` when a rule covers the part.
3470
+ * The first step is a root of the context. Each later step is a key or a step document. A key goes up the ladder
3471
+ * of the verb `deref` on the thing that the path reached. A step document is evaluated by the walker that the
3472
+ * ladder of the verb `step` gives, with the thing that the path reached. After each hop, a reference document is
3473
+ * followed until the path reaches something else (collapse), except in a plain navigation.
3474
+ *
3475
+ * The codes of a failure:
3476
+ *
3477
+ * - `#REF!`: the path has no root, or a root that is not open here.
3478
+ * - `#NAME?`: the root `names` has no such name.
3479
+ * - `#N/A`: a step reaches nothing.
3480
+ * - `#STEP?`: a step is not a key and not a step document.
3481
+ * - `#CYCLE!`: the references form a cycle, or the resolution follows more than 64 references. The reason tells
3482
+ * which (DEREF.CHAIN-REASON).
3483
+ *
3484
+ * @param nav - The world and the code of the evaluators.
3485
+ * @param ctx - The context.
3486
+ * @param path - The steps.
3487
+ * @param options - `hops: false` does not record the hops.
3488
+ * @returns What the path reached and each hop, or an error.
3876
3489
  */
3877
- function rulesCover(rules, shape, value, slot) {
3878
- for (const rule of rules) {
3879
- if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
3880
- const after = rule.after ?? 0;
3881
- if (after <= 0) return true;
3882
- const split = splitParts(shape, value);
3883
- let count = 0;
3884
- for (const part of split.ok ? split.parts : []) {
3885
- if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
3886
- if (part.path.length === slot.length && pathMatches(part.path, slot)) {
3887
- if (count >= after) return true;
3888
- break;
3889
- }
3890
- count += 1;
3891
- }
3490
+ function resolve(nav, ctx, path, options = {}) {
3491
+ if (options.hops === false) {
3492
+ const quick = resolveQuick(nav, ctx, path);
3493
+ if (quick !== void 0) return quick;
3892
3494
  }
3893
- return false;
3894
- }
3895
- function valueAt(value, path) {
3896
- let here = value;
3897
- for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
3898
- else if (isRecord(here) && Object.hasOwn(here, String(key))) here = here[String(key)];
3899
- else return void 0;
3900
- return here;
3901
- }
3902
- function headerName(item) {
3903
- return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
3495
+ return resolveFully$1(nav, ctx, path, options.hops === false ? void 0 : [], void 0);
3904
3496
  }
3905
- function namesOf(source, value, covered) {
3906
- if ("fixed" in source) return source.fixed;
3907
- if ("keysAt" in source) {
3908
- const at = valueAt(value, source.keysAt);
3909
- return isRecord(at) ? Object.keys(at) : [];
3910
- }
3911
- if ("listAt" in source) {
3912
- const at = valueAt(value, source.listAt);
3913
- return Array.isArray(at) ? at.filter((item) => typeof item === "string") : [];
3914
- }
3915
- if ("textAt" in source) {
3916
- const at = valueAt(value, source.textAt);
3917
- if (typeof at === "string") return [at];
3918
- return source.otherwise === void 0 ? [] : [source.otherwise];
3919
- }
3920
- return covered.map((slot) => headerName(slot.item)).filter((name) => name !== void 0);
3497
+ /** The functions of the last navigator that gave a walker its input. A walk with the same navigator makes no new functions. */
3498
+ let lastSteps;
3499
+ /**
3500
+ * This function gives the functions `deref` and `has` of the input of a walker. They depend only on the navigator,
3501
+ * thus the function keeps the functions of the last navigator (K170).
3502
+ */
3503
+ function walkSteps(nav) {
3504
+ if (lastSteps !== void 0 && lastSteps.nav === nav) return lastSteps;
3505
+ const adopt = nav.adopt;
3506
+ lastSteps = {
3507
+ nav,
3508
+ deref: adopt === void 0 ? (thing, key) => derefStep(nav, thing, key)?.thing : (thing, key) => {
3509
+ const reached = derefStep(nav, thing, key);
3510
+ return reached === void 0 ? void 0 : adopt(reached.thing);
3511
+ },
3512
+ has: (thing, key) => derefStep(nav, thing, key) !== void 0
3513
+ };
3514
+ return lastSteps;
3921
3515
  }
3922
3516
  /**
3923
- * This function gives the names that the scope rules of a kind give each part, and the names that only later parts
3924
- * see. `check`, `conforms` and the plan read the scope rules with it.
3517
+ * This function resolves a path with the full algorithm of `resolve`.
3925
3518
  *
3926
- * @param rules - The scope rules of the kind.
3927
- * @param value - The value of the document.
3928
- * @param slots - The parts of the value, in order.
3929
- * @returns The names that each part sees, and the names that only the later parts see, by the index of the part.
3519
+ * @param nav - The world and the code of the evaluators.
3520
+ * @param ctx - The context.
3521
+ * @param path - The steps.
3522
+ * @param hops - The list that gets each hop, or `undefined` for no record.
3523
+ * @param known - The walker of each step document of the path, from `compilePath`. A reference that a step reaches has its own steps, and the ladder answers them.
3524
+ * @returns What the path reached and each hop, or an error.
3930
3525
  */
3931
- function scopesOf(rules, value, slots) {
3932
- const sees = slots.map(() => []);
3933
- const later = slots.map(() => []);
3934
- for (const rule of rules ?? []) {
3935
- const covered = slots.map((slot, index) => ({
3936
- slot,
3937
- index
3938
- })).filter(({ slot }) => rule.in.some((pattern) => pathMatches(slot.path, pattern)));
3939
- if (rule.sequential !== true) {
3940
- const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
3941
- for (const { index } of covered) sees[index]?.push(...names);
3942
- continue;
3943
- }
3944
- if ("headers" in rule.names) {
3945
- covered.forEach(({ index }, position) => {
3946
- const before = covered.slice(0, position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
3947
- const after = covered.slice(position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
3948
- sees[index]?.push(...before);
3949
- later[index]?.push(...after);
3526
+ function resolveFully$1(nav, ctx, path, hops, known) {
3527
+ const done = hops ?? NO_HOPS$1;
3528
+ const failed = (code, reason) => ({
3529
+ ok: false,
3530
+ code,
3531
+ reason,
3532
+ hops: done
3533
+ });
3534
+ let collapses = 0;
3535
+ let open;
3536
+ const adopt = nav.adopt ?? ((value) => value);
3537
+ const collapse = (thing) => {
3538
+ let here = thing;
3539
+ if (nav.plain === true) return {
3540
+ ok: true,
3541
+ thing: here,
3542
+ hops: done
3543
+ };
3544
+ while (isRef(here)) {
3545
+ if (open?.includes(here) === true) return failed("#CYCLE!", "The references form a cycle.");
3546
+ collapses += 1;
3547
+ if (collapses > MAX_COLLAPSE$1) return failed("#CYCLE!", CHAIN_REASON);
3548
+ open ??= [];
3549
+ open.push(here);
3550
+ const inner = walk(here.value, void 0);
3551
+ open.pop();
3552
+ if (!inner.ok) return inner;
3553
+ here = adopt(inner.thing);
3554
+ hops?.push({
3555
+ step: "collapse",
3556
+ thing: here,
3557
+ by: "collapse"
3950
3558
  });
3951
- continue;
3952
3559
  }
3953
- const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
3954
- covered.forEach(({ index }, position) => {
3955
- if (position > 0) sees[index]?.push(...names);
3956
- else later[index]?.push(...names);
3560
+ return {
3561
+ ok: true,
3562
+ thing: here,
3563
+ hops: done
3564
+ };
3565
+ };
3566
+ const walk = (steps, walkers) => {
3567
+ const root = steps[0];
3568
+ if (typeof root !== "string" || !ROOTS.includes(root)) return failed("#REF!", `A path starts with a root: ${ROOTS.join(", ")}.`);
3569
+ if (nav.roots !== void 0 && !nav.roots.includes(root)) return failed("#REF!", `The root ${root} is not open here. The open roots are ${nav.roots.join(", ")}.`);
3570
+ let here = adopt(ctx[root]);
3571
+ hops?.push({
3572
+ step: root,
3573
+ thing: here,
3574
+ by: "root"
3957
3575
  });
3958
- }
3959
- return {
3960
- sees,
3961
- later
3576
+ const first = collapse(here);
3577
+ if (!first.ok) return first;
3578
+ here = first.thing;
3579
+ for (let index = 1; index < steps.length; index += 1) {
3580
+ const step = steps[index];
3581
+ if (isHostThing(here) && here.resolve !== void 0 && keysFrom(steps, index)) {
3582
+ const keys = steps.slice(index);
3583
+ const reached = here.resolve(keys);
3584
+ if (reached === void 0) return failed("#N/A", `The path ${keys.join(".")} reaches nothing.`);
3585
+ const thing = adopt(reached.thing);
3586
+ hops?.push({
3587
+ step: keys,
3588
+ thing,
3589
+ by: "own"
3590
+ });
3591
+ return collapse(thing);
3592
+ }
3593
+ if (isKey(step)) {
3594
+ const reached = derefStep(nav, here, step);
3595
+ if (reached === void 0) {
3596
+ if (root === "names" && index === 1) return failed("#NAME?", `The context has no name ${String(step)}.`);
3597
+ return failed("#N/A", `The step ${String(step)} reaches nothing.`);
3598
+ }
3599
+ here = adopt(reached.thing);
3600
+ hops?.push({
3601
+ step,
3602
+ thing: here,
3603
+ by: reached.by
3604
+ });
3605
+ } else {
3606
+ const given = walkers?.[index];
3607
+ const walker = given === void 0 ? walkerOf(nav, step) : given ?? void 0;
3608
+ if (walker === void 0) return failed("#STEP?", "A step is a key, or a document of a kind with the verb step.");
3609
+ const envelope = step;
3610
+ const { deref, has } = walkSteps(nav);
3611
+ const result = walker(hops === void 0 ? {
3612
+ data: envelope.value,
3613
+ here,
3614
+ context: ctx,
3615
+ deref,
3616
+ has
3617
+ } : {
3618
+ data: envelope.value,
3619
+ here,
3620
+ context: ctx,
3621
+ deref,
3622
+ has,
3623
+ visit: (key, thing) => hops.push({
3624
+ step: key,
3625
+ thing,
3626
+ by: "step"
3627
+ })
3628
+ });
3629
+ if (!result.ok) return failed(result.code ?? "#N/A", result.reason);
3630
+ here = adopt(result.thing);
3631
+ hops?.push({
3632
+ step: envelope,
3633
+ thing: here,
3634
+ by: "step"
3635
+ });
3636
+ }
3637
+ const next = collapse(here);
3638
+ if (!next.ok) return next;
3639
+ here = next.thing;
3640
+ }
3641
+ return {
3642
+ ok: true,
3643
+ thing: here,
3644
+ hops: done
3645
+ };
3962
3646
  };
3647
+ if (path.length === 0) return failed("#REF!", "A path has at least one step: its root.");
3648
+ return walk(path, known);
3649
+ }
3650
+ /**
3651
+ * This function gives the value of a thing: the value that a host thing gives, or else the thing itself.
3652
+ *
3653
+ * @param thing - The thing.
3654
+ * @returns The value.
3655
+ */
3656
+ function valueOfThing(thing) {
3657
+ return isHostThing(thing) ? thing.toJson() : thing;
3963
3658
  }
3964
3659
  // src/evaluate.ts
3965
3660
  /**
@@ -4325,6 +4020,20 @@ function placeText(place) {
4325
4020
  }
4326
4021
  return text;
4327
4022
  }
4023
+ /**
4024
+ * The most work of one evaluation for a machine without its own `maxWork` (WORK.LIMIT, D134). One application of a
4025
+ * closure is one point.
4026
+ */
4027
+ const WORK_LIMIT = 2e5;
4028
+ /**
4029
+ * This function gives the error of the limit of work. Each tier gives this error (WORK.AGREES).
4030
+ *
4031
+ * @param limit - The limit of the machine.
4032
+ * @returns The error.
4033
+ */
4034
+ function workFailure(limit) {
4035
+ return fail("#WORK!", `The work of one evaluation is more than ${limit} points. The field maxWork of the machine sets the limit.`).error;
4036
+ }
4328
4037
  function selfLabel(self) {
4329
4038
  try {
4330
4039
  if (isHostThing(self)) return self.label;
@@ -4458,7 +4167,12 @@ var Session = class {
4458
4167
  running;
4459
4168
  traced;
4460
4169
  perform;
4461
- signal;
4170
+ /**
4171
+ * The runtime of the root, on the runtime of an equation of a tree (WORK.EQUATION). The runtime of a root holds
4172
+ * itself after the end of its evaluation (WORK.AFTER, WORK.KEEPS), thus the end mark adds no field to the object.
4173
+ * Each runtime has this field, thus a tree and its equations have one object shape.
4174
+ */
4175
+ top;
4462
4176
  /**
4463
4177
  * The record of the reads. Without it, a resolution records nothing. A nested evaluation of an equation of a tree
4464
4178
  * shares the record of the evaluation around it (READS.EQUATION).
@@ -4480,18 +4194,38 @@ var Session = class {
4480
4194
  * root scope is made at the first effect or `all`, thus an evaluation without effects makes no scope.
4481
4195
  */
4482
4196
  scope;
4483
- constructor(machine, epoch, running, traced, perform, signal, effects, reading = void 0) {
4197
+ constructor(machine, epoch, running, traced, perform, top, effects, reading = void 0) {
4484
4198
  this.machine = machine;
4485
4199
  this.epoch = epoch;
4486
4200
  this.running = running;
4487
4201
  this.traced = traced;
4488
4202
  this.perform = perform;
4489
- this.signal = signal;
4203
+ this.top = top;
4490
4204
  this.reading = reading;
4491
4205
  this.list = effects;
4492
4206
  this.holder = traced ? holderNode() : void 0;
4493
4207
  this.current = this.holder;
4494
4208
  }
4209
+ /** This getter gives `true` for the runtime of an equation of a tree (WORK.NODE). */
4210
+ get nested() {
4211
+ const top = this.top;
4212
+ return top !== void 0 && top !== this;
4213
+ }
4214
+ /**
4215
+ * This function adds work to the count of the evaluation (WORK.LIMIT). One count is on the runtime of the root, thus
4216
+ * each equation of a tree adds to it. After the end of the evaluation, each entry from the host starts a new count
4217
+ * (WORK.AFTER). An entry is a point with no application of a closure that runs, on any runtime of the evaluation.
4218
+ *
4219
+ * @param points - The work.
4220
+ * @throws {Failure} The error `#WORK!`, when the count is over the limit of the machine.
4221
+ */
4222
+ spend(points) {
4223
+ const root = this.top ?? this;
4224
+ const work = (root.top === root && (root.active ?? 0) === 0 ? 0 : root.work ?? 0) + points;
4225
+ root.work = work;
4226
+ const limit = this.machine.maxWork ?? 2e5;
4227
+ if (work > limit) throw new Failure(workFailure(limit));
4228
+ }
4495
4229
  /** The effects of the evaluation, in their order. */
4496
4230
  get effects() {
4497
4231
  return this.list ??= [];
@@ -5104,6 +4838,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
5104
4838
  ...address ? { address: true } : {}
5105
4839
  };
5106
4840
  if (runner !== void 0) {
4841
+ c.keeps = true;
5107
4842
  let inner;
5108
4843
  try {
5109
4844
  inner = isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill, kind?.caps?.some((rule) => rule.rule === "grant") === true);
@@ -5114,6 +4849,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
5114
4849
  const run = placedRun(guard === void 0 ? inner : guardRun(inner, guard, c.machine.domains), place, name);
5115
4850
  return finish$2(c, meta, runnerCode(run, place, kindText), run);
5116
4851
  }
4852
+ if (!isCompiledEvaluator(evaluator) || evaluator.keeps === true) c.keeps = true;
5117
4853
  let inner;
5118
4854
  try {
5119
4855
  inner = isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill);
@@ -5187,6 +4923,8 @@ var Probe = class {
5187
4923
  running = false;
5188
4924
  /** `true` after the part asked for something that a fold cannot give. */
5189
4925
  refused = false;
4926
+ /** A node in a fold costs work, thus a tree stops the fold before it evaluates an equation (WORK.PREPARE). */
4927
+ nested = true;
5190
4928
  /** The count of the names that the part read. */
5191
4929
  reads = 0;
5192
4930
  /**
@@ -5254,6 +4992,11 @@ var Probe = class {
5254
4992
  keepsContext() {
5255
4993
  this.refused = true;
5256
4994
  }
4995
+ /** This function stops the fold at the first point of work, thus `prepare` does no such work (WORK.PREPARE). */
4996
+ spend() {
4997
+ this.refused = true;
4998
+ throw new Failure(workFailure(0));
4999
+ }
5257
5000
  };
5258
5001
  /**
5259
5002
  * This function makes a trap for a root of the context of a fold. Each read of a field calls `refuse`. A trap of the
@@ -5585,8 +5328,8 @@ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
5585
5328
  /**
5586
5329
  * This function evaluates a plan inside the evaluation of another runtime, for example an equation of a tree inside
5587
5330
  * the evaluation of its tree (READS.EQUATION). The plan gets its own runtime, as in `plan.evaluate`. The reads of the
5588
- * plan go in the record of the reads of `outer`. The context at the root of `outer` tells which reads are free
5589
- * (READS.FREE). Without such a record, the function gives `plan.evaluate(context)`.
5331
+ * plan go in the record of the reads of `outer`, and its work goes in the count of `outer` (WORK.EQUATION). The context
5332
+ * at the root of `outer` tells which reads are free (READS.FREE). Without a session, the function gives `plan.evaluate(context)`.
5590
5333
  *
5591
5334
  * @param plan - The plan.
5592
5335
  * @param context - The context of the plan.
@@ -5594,11 +5337,10 @@ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
5594
5337
  * @returns The result.
5595
5338
  */
5596
5339
  function evaluateWithin(plan, context, outer) {
5597
- const reading = outer instanceof Session ? outer.reading : void 0;
5598
- if (reading === void 0 || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
5340
+ if (!(outer instanceof Session) || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
5599
5341
  const machine = plan.machine;
5600
5342
  const ctx = rootContext(machine, context);
5601
- return plan.code(ctx, new Session(machine, ctx.caps, false, plan.traced, void 0, void 0, void 0, reading));
5343
+ return plan.code(ctx, new Session(machine, ctx.caps, false, plan.traced, void 0, outer.top ?? outer, void 0, outer.reading));
5602
5344
  }
5603
5345
  function interpret(fn, input, fill) {
5604
5346
  const { kind, typePath, doc, data, place, machine } = input;
@@ -5761,7 +5503,22 @@ function prepare(machine, doc, options = {}) {
5761
5503
  run: void 0
5762
5504
  };
5763
5505
  }
5764
- return new CompiledPlan(machine, c.traced, root.code, root.run);
5506
+ return new CompiledPlan(machine, c.traced, c.keeps === true ? endingCode(root.code) : root.code, root.run);
5507
+ }
5508
+ /**
5509
+ * This function gives the code of a plan with a document that can use its runtime after the end of the evaluation. The
5510
+ * code marks that end (WORK.KEEPS). Each other plan has no such step, thus the count adds nothing to a read.
5511
+ *
5512
+ * @param code - The code of the root.
5513
+ * @returns The code that marks the end.
5514
+ */
5515
+ function endingCode(code) {
5516
+ return (ctx, rt) => {
5517
+ const result = code(ctx, rt);
5518
+ const session = rt;
5519
+ session.top ??= session;
5520
+ return result;
5521
+ };
5765
5522
  }
5766
5523
  /**
5767
5524
  * The object of a plan (PLAN.LEAN). The code of `evaluate` and `run` is on the class, thus a plan keeps only its
@@ -5796,8 +5553,10 @@ var CompiledPlan = class {
5796
5553
  run(context = makeContext(), runOptions = {}) {
5797
5554
  const machine = this.machine;
5798
5555
  const ctx = rootContext(machine, context);
5799
- const s = new Session(machine, ctx.caps, true, this.traced, runOptions.perform, runOptions.signal, void 0, readingOf(runOptions.reads, ctx));
5800
- return driveWaiting(this.runCode()(ctx, s), runOptions.signal);
5556
+ const s = new Session(machine, ctx.caps, true, this.traced, runOptions.perform, void 0, void 0, readingOf(runOptions.reads, ctx));
5557
+ return driveWaiting(this.runCode()(ctx, s), runOptions.signal).finally(() => {
5558
+ s.top = s;
5559
+ });
5801
5560
  }
5802
5561
  };
5803
5562
  /**
@@ -5841,102 +5600,447 @@ function record(s, result) {
5841
5600
  };
5842
5601
  }
5843
5602
  /**
5844
- * This function evaluates a document, and records each evaluation in a trace.
5845
- *
5846
- * The verb of the options goes up the ladder for each document. The default verb is `eval`. The kind of the document
5847
- * tells where its parts are. The evaluator gets each part sealed: it can evaluate the part, and it cannot read its
5848
- * value.
5849
- *
5850
- * A failure gives an error value, and the function does not throw. The function records each effect in its order,
5851
- * and the host does not do it. A mock can answer each effect at once (RUN.MOCK).
5603
+ * This function evaluates a document, and records each evaluation in a trace.
5604
+ *
5605
+ * The verb of the options goes up the ladder for each document. The default verb is `eval`. The kind of the document
5606
+ * tells where its parts are. The evaluator gets each part sealed: it can evaluate the part, and it cannot read its
5607
+ * value.
5608
+ *
5609
+ * A failure gives an error value, and the function does not throw. The function records each effect in its order,
5610
+ * and the host does not do it. A mock can answer each effect at once (RUN.MOCK).
5611
+ *
5612
+ * @param machine - The world and the code of the evaluators.
5613
+ * @param doc - The document, as JSON.
5614
+ * @param context - The names and the capabilities at the root.
5615
+ * @param options - The type of a bare root value, or the options: that type, the mock of the host, the verb and a list for the reads.
5616
+ * @returns The result, the trace and the effects in their order.
5617
+ */
5618
+ function evaluate(machine, doc, context = makeContext(), options) {
5619
+ const given = typeof options === "string" ? { declaredType: options } : options ?? {};
5620
+ const declaredType = given.declaredType;
5621
+ const plan = prepare(machine, doc, {
5622
+ trace: true,
5623
+ ...declaredType === void 0 ? {} : { declaredType },
5624
+ ...given.verb === void 0 ? {} : { verb: given.verb },
5625
+ ...given.guards === void 0 ? {} : { guards: given.guards }
5626
+ });
5627
+ const ctx = rootContext(machine, context);
5628
+ const s = new Session(machine, ctx.caps, false, true, given.perform, void 0, void 0, readingOf(given.reads, ctx));
5629
+ return record(s, plan.code(ctx, s));
5630
+ }
5631
+ /**
5632
+ * This function runs a document: an evaluation in which the host does each effect. A runner waits for its
5633
+ * parts and for its effects, thus a step can read the result of the step before. The part of the run before the
5634
+ * first wait happens at once, in the call. The run records a trace.
5635
+ *
5636
+ * @param machine - The world, the evaluators and the runners.
5637
+ * @param doc - The document, as JSON.
5638
+ * @param context - The names and the capabilities at the root.
5639
+ * @param options - The host code that does the effects, the type of a bare root value, a signal, the verb and a list for the reads.
5640
+ * @returns The result, the trace and the effects in their order, when the run ends.
5641
+ */
5642
+ async function run(machine, doc, context = makeContext(), options = {}) {
5643
+ const plan = prepare(machine, doc, {
5644
+ trace: true,
5645
+ ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
5646
+ ...options.guards === void 0 ? {} : { guards: options.guards },
5647
+ ...options.verb === void 0 ? {} : { verb: options.verb }
5648
+ });
5649
+ const ctx = rootContext(machine, context);
5650
+ const s = new Session(machine, ctx.caps, true, true, options.perform, void 0, void 0, readingOf(options.reads, ctx));
5651
+ const result = await driveWaiting(plan.runCode()(ctx, s), options.signal);
5652
+ s.top = s;
5653
+ return record(s, result);
5654
+ }
5655
+ /**
5656
+ * This function finds a node of a trace by its path.
5657
+ *
5658
+ * @param trace - The root of the trace.
5659
+ * @param path - The keys from the root.
5660
+ * @returns The first evaluation at that path, or `undefined` when the document did not evaluate.
5661
+ */
5662
+ function nodeAt(trace, path) {
5663
+ const want = path.map(String);
5664
+ let node = trace;
5665
+ let at = 0;
5666
+ while (node !== void 0 && at < want.length) {
5667
+ const here = node;
5668
+ node = here.children.find((child) => {
5669
+ const tail = child.path.slice(here.path.length);
5670
+ return tail.length > 0 && tail.every((key, index) => key === want[at + index]);
5671
+ });
5672
+ if (node !== void 0) at += node.path.length - here.path.length;
5673
+ }
5674
+ return node;
5675
+ }
5676
+ /**
5677
+ * This function lists the nodes of a trace in the order of their start.
5678
+ *
5679
+ * @param trace - The root of the trace.
5680
+ * @returns Each node, the root first.
5681
+ */
5682
+ function flatten(trace) {
5683
+ const out = [];
5684
+ const stack = [trace];
5685
+ while (stack.length > 0) {
5686
+ const node = stack.pop();
5687
+ out.push(node);
5688
+ for (let index = node.children.length - 1; index >= 0; index -= 1) stack.push(node.children[index]);
5689
+ }
5690
+ return out.sort((a, b) => a.enter - b.enter);
5691
+ }
5692
+ /**
5693
+ * This function lists the errors of a trace: each node whose result is an error and whose parts did not fail
5694
+ * the same way. These nodes are where each error started.
5695
+ *
5696
+ * @param trace - The root of the trace.
5697
+ * @returns The errors, in the order of their start.
5698
+ */
5699
+ function failures(trace) {
5700
+ return flatten(trace).filter((node) => !node.result.ok && !node.children.some((child) => !child.result.ok && child.result.error === node.result.error)).map((node) => node.result.error);
5701
+ }
5702
+ // src/language.ts
5703
+ const VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
5704
+ function numbers$1(version) {
5705
+ const found = VERSION.exec(version);
5706
+ if (found === null) throw new TypeError(`A language version has the form MAJOR.MINOR.PATCH. The text ${JSON.stringify(version)} does not.`);
5707
+ return [
5708
+ Number(found[1]),
5709
+ Number(found[2]),
5710
+ Number(found[3])
5711
+ ];
5712
+ }
5713
+ /**
5714
+ * This function tells if a version satisfies a lowest version, by the rules of a caret range of SemVer. The first
5715
+ * number that is not zero stays the same, and the version is not lower.
5716
+ */
5717
+ function compatible(version, lowest) {
5718
+ const have = numbers$1(version);
5719
+ const want = numbers$1(lowest);
5720
+ const stable = want.findIndex((part) => part !== 0);
5721
+ const fixed = stable < 0 ? 3 : stable + 1;
5722
+ for (let index = 0; index < 3; index += 1) {
5723
+ const [a, b] = [have[index], want[index]];
5724
+ if (a !== b) return index >= fixed && a > b;
5725
+ }
5726
+ return true;
5727
+ }
5728
+ /** This function gives the JSON text of a value with its keys in order. A value that is not JSON is an error. */
5729
+ function canonical(value, path) {
5730
+ if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
5731
+ if (typeof value === "number" && Number.isFinite(value)) return JSON.stringify(value);
5732
+ if (Array.isArray(value)) return `[${value.map((item, index) => canonical(item, [...path, index])).join(",")}]`;
5733
+ if (!isRecord(value)) throw new TypeError(`The data half of a language is JSON. The value at ${JSON.stringify(path)} is not.`);
5734
+ return `{${Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key], [...path, key])}`).join(",")}}`;
5735
+ }
5736
+ function frozen(value) {
5737
+ if (typeof value !== "object" || value === null) return value;
5738
+ for (const item of Object.values(value)) frozen(item);
5739
+ return Object.freeze(value);
5740
+ }
5741
+ /**
5742
+ * This function makes one value of a language. The data half is JSON, thus a host can store it and compare it. The
5743
+ * code half binds the evaluator names of the world.
5744
+ *
5745
+ * The language keeps a frozen copy of its data half, thus a later change to the input changes nothing.
5746
+ *
5747
+ * @param definition - The name, the version, the world, the needed languages and the code.
5748
+ * @returns The language.
5749
+ * @throws {TypeError} A version in the definition is not `MAJOR.MINOR.PATCH`, the name is empty, or the
5750
+ * data half is not JSON.
5751
+ */
5752
+ function defineLanguage(definition) {
5753
+ if (definition.name === "") throw new TypeError("A language has a name.");
5754
+ numbers$1(definition.version);
5755
+ const requires = definition.requires ?? {};
5756
+ for (const name of Object.keys(requires)) numbers$1(requires[name]);
5757
+ const data = canonical({
5758
+ requires,
5759
+ world: definition.world ?? {}
5760
+ }, []);
5761
+ const copy = frozen(JSON.parse(data));
5762
+ const language = {
5763
+ name: definition.name,
5764
+ version: definition.version,
5765
+ world: copy.world,
5766
+ requires: copy.requires,
5767
+ data
5768
+ };
5769
+ return Object.freeze(definition.code === void 0 ? language : {
5770
+ ...language,
5771
+ code: definition.code
5772
+ });
5773
+ }
5774
+ function partOf(language) {
5775
+ const { code, world } = language;
5776
+ return typeof code === "function" ? (prev) => ({
5777
+ ...code(prev),
5778
+ world
5779
+ }) : {
5780
+ ...code,
5781
+ world
5782
+ };
5783
+ }
5784
+ /**
5785
+ * This function merges languages into one machine, in the order of the arguments, with `mergeMachines`.
5786
+ *
5787
+ * - A language comes after each language that it names in `requires`, at a compatible version (LANG.REQUIRES).
5788
+ * - One language that comes twice counts once. Thus two languages can share a base.
5789
+ * - Two versions of one name, or two data halves under one name and one version, are conflicts (LANG.COMPOSE).
5790
+ *
5791
+ * @param languages - The languages.
5792
+ * @returns The machine.
5793
+ * @throws {MergeError} The languages do not fit, or their merge has a conflict. The error lists each conflict.
5794
+ */
5795
+ function compose(...languages) {
5796
+ const conflicts = [];
5797
+ const parts = [];
5798
+ const seen = /* @__PURE__ */ new Map();
5799
+ languages.forEach((language, index) => {
5800
+ const earlier = seen.get(language.name);
5801
+ const conflict = (name, other, reason) => {
5802
+ conflicts.push({
5803
+ path: ["languages", name],
5804
+ parts: [Math.min(other, index), Math.max(other, index)],
5805
+ reason
5806
+ });
5807
+ };
5808
+ if (earlier !== void 0) {
5809
+ if (earlier.language.version !== language.version) conflict(language.name, earlier.index, "Two versions of one language.");
5810
+ else if (earlier.language.data !== language.data) conflict(language.name, earlier.index, "Two languages with one name and one version differ.");
5811
+ else if (earlier.language.code !== language.code) parts.push(partOf(language));
5812
+ return;
5813
+ }
5814
+ for (const name of Object.keys(language.requires)) {
5815
+ const needed = language.requires[name];
5816
+ const found = seen.get(name);
5817
+ if (found === void 0) {
5818
+ const later = languages.findIndex((other) => other.name === name);
5819
+ if (later < 0) conflict(name, index, `A language requires ${name}, and the composition does not have it.`);
5820
+ else conflict(name, later, `A language requires ${name}, and ${name} comes after it.`);
5821
+ } else if (!compatible(found.language.version, needed)) conflict(name, found.index, `A language requires ${name} ${needed}, and the composition has ${found.language.version}.`);
5822
+ }
5823
+ seen.set(language.name, {
5824
+ language,
5825
+ index
5826
+ });
5827
+ parts.push(partOf(language));
5828
+ });
5829
+ if (conflicts.length > 0) throw new MergeError(conflicts);
5830
+ return mergeMachines(...parts);
5831
+ }
5832
+ /**
5833
+ * This function makes the language of the boundary kind `lang` (K38, D193). A document of the kind holds the name of a
5834
+ * language and a document in that language: `{ type: "lang", value: { language, doc } }`. The machine of the named
5835
+ * language prepares and evaluates the inner document, as a module of another language (COMPOSE.BOUNDARY).
5836
+ *
5837
+ * The boundary is closed. The inner document gets no names, no capabilities and no node as `self`. Only its result
5838
+ * crosses the boundary. Thus an effect in the inner document fails with `#CAP!`, and the inner machine cannot read the
5839
+ * names of the outer document.
5840
+ *
5841
+ * @param machines - The machine of each language, by the name that a document gives.
5842
+ * @returns The language, for `compose`.
5843
+ */
5844
+ function boundary(machines) {
5845
+ const plans = /* @__PURE__ */ new Map();
5846
+ const planOf = (name) => {
5847
+ let found = plans.get(name);
5848
+ if (found === void 0 && Object.hasOwn(machines, name)) {
5849
+ found = planner(machines[name]);
5850
+ plans.set(name, found);
5851
+ }
5852
+ return found;
5853
+ };
5854
+ return defineLanguage({
5855
+ name: "boundary",
5856
+ version: "1.0.0",
5857
+ world: { kinds: { lang: {
5858
+ verbs: { eval: "boundary.lang" },
5859
+ summary: "A document in another language. The machine of that language evaluates it, with no names and no capabilities."
5860
+ } } },
5861
+ code: { evaluators: { "boundary.lang": (input) => {
5862
+ const { data, place } = input;
5863
+ if (!isRecord(data) || typeof data["language"] !== "string" || !("doc" in data)) return fail("#VALUE!", "A document of the kind lang has the value { language, doc }.", { place });
5864
+ const plans = planOf(data["language"]);
5865
+ if (plans === void 0) return fail("#NAME?", `The boundary knows no language ${JSON.stringify(data["language"])}.`, { place });
5866
+ return evaluateWithin(plans(data["doc"]), makeContext(), input[RUNTIME]);
5867
+ } } }
5868
+ });
5869
+ }
5870
+ // src/steps.ts
5871
+ /**
5872
+ * This function makes a ladder of steps, and it checks the declaration (STEPS.LADDER). The list of steps must have one
5873
+ * step or more, with no name two times. The step of each construct must be a step of the list.
5874
+ *
5875
+ * @param steps - The names of the steps, from the lowest to the highest.
5876
+ * @param constructs - The step that each construct needs.
5877
+ * @returns The ladder, frozen.
5878
+ * @throws TypeError for a declaration that is not valid, because it is a defect of the language.
5879
+ */
5880
+ function stepLadder(steps, constructs) {
5881
+ if (steps.length === 0) throw new TypeError("a ladder of steps needs one step or more");
5882
+ const seen = /* @__PURE__ */ new Set();
5883
+ for (const step of steps) {
5884
+ if (typeof step !== "string") throw new TypeError(`the step ${String(step)} is not a name`);
5885
+ if (seen.has(step)) throw new TypeError(`the step "${step}" is in the ladder two times`);
5886
+ seen.add(step);
5887
+ }
5888
+ for (const [construct, step] of Object.entries(constructs)) if (!seen.has(step)) throw new TypeError(`the construct "${construct}" needs the step "${String(step)}", which is not a step of the ladder`);
5889
+ return Object.freeze({
5890
+ steps: Object.freeze([...steps]),
5891
+ constructs: Object.freeze({ ...constructs })
5892
+ });
5893
+ }
5894
+ /**
5895
+ * This function tells if a value is a step of a ladder. A host uses it to check its option for the highest step.
5852
5896
  *
5853
- * @param machine - The world and the code of the evaluators.
5854
- * @param doc - The document, as JSON.
5855
- * @param context - The names and the capabilities at the root.
5856
- * @param options - The type of a bare root value, or the options: that type, the mock of the host, the verb and a list for the reads.
5857
- * @returns The result, the trace and the effects in their order.
5897
+ * @param ladder - The ladder.
5898
+ * @param value - The value.
5899
+ * @returns `true` when the value is the name of a step of the ladder.
5858
5900
  */
5859
- function evaluate(machine, doc, context = makeContext(), options) {
5860
- const given = typeof options === "string" ? { declaredType: options } : options ?? {};
5861
- const declaredType = given.declaredType;
5862
- const plan = prepare(machine, doc, {
5863
- trace: true,
5864
- ...declaredType === void 0 ? {} : { declaredType },
5865
- ...given.verb === void 0 ? {} : { verb: given.verb },
5866
- ...given.guards === void 0 ? {} : { guards: given.guards }
5867
- });
5868
- const ctx = rootContext(machine, context);
5869
- const s = new Session(machine, ctx.caps, false, true, given.perform, void 0, void 0, readingOf(given.reads, ctx));
5870
- return record(s, plan.code(ctx, s));
5901
+ function isStep(ladder, value) {
5902
+ return typeof value === "string" && ladder.steps.includes(value);
5871
5903
  }
5872
5904
  /**
5873
- * This function runs a document: an evaluation in which the host does each effect. A runner waits for its
5874
- * parts and for its effects, thus a step can read the result of the step before. The part of the run before the
5875
- * first wait happens at once, in the call. The run records a trace.
5905
+ * This function gives the position of a step in its ladder. The lowest step has the position 0.
5876
5906
  *
5877
- * @param machine - The world, the evaluators and the runners.
5878
- * @param doc - The document, as JSON.
5879
- * @param context - The names and the capabilities at the root.
5880
- * @param options - The host code that does the effects, the type of a bare root value, a signal, the verb and a list for the reads.
5881
- * @returns The result, the trace and the effects in their order, when the run ends.
5907
+ * @param ladder - The ladder.
5908
+ * @param step - The step.
5909
+ * @returns The position.
5910
+ * @throws TypeError for a name that is not a step of the ladder.
5882
5911
  */
5883
- async function run(machine, doc, context = makeContext(), options = {}) {
5884
- const plan = prepare(machine, doc, {
5885
- trace: true,
5886
- ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
5887
- ...options.guards === void 0 ? {} : { guards: options.guards },
5888
- ...options.verb === void 0 ? {} : { verb: options.verb }
5889
- });
5890
- const ctx = rootContext(machine, context);
5891
- const s = new Session(machine, ctx.caps, true, true, options.perform, options.signal, void 0, readingOf(options.reads, ctx));
5892
- return record(s, await driveWaiting(plan.runCode()(ctx, s), options.signal));
5912
+ function stepRank(ladder, step) {
5913
+ const rank = ladder.steps.indexOf(step);
5914
+ if (rank < 0) throw new TypeError(`"${String(step)}" is not a step of the ladder. The steps are ${ladder.steps.join(", ")}`);
5915
+ return rank;
5916
+ }
5917
+ function pathOf(visit) {
5918
+ const path = [];
5919
+ for (let v = visit; v?.key !== void 0; v = v.parent) path.push(v.key);
5920
+ return path.reverse();
5893
5921
  }
5894
5922
  /**
5895
- * This function finds a node of a trace by its path.
5923
+ * This function gives the lowest step that a document needs, with the reason (STEPS.LOWEST, STEPS.REASON). The step is
5924
+ * the highest step of the constructs of its nodes. The reason is the first node in document order with that step. The
5925
+ * walk uses its own stack, thus a deep document does not overflow (STEPS.LINEAR). It visits a shared node one time,
5926
+ * and it stops at the first node with the highest step of the ladder.
5896
5927
  *
5897
- * @param trace - The root of the trace.
5898
- * @param path - The keys from the root.
5899
- * @returns The first evaluation at that path, or `undefined` when the document did not evaluate.
5928
+ * @param ladder - The ladder of the language.
5929
+ * @param walk - The construct and the child nodes of a node.
5930
+ * @param root - The root node of the document.
5931
+ * @returns The step, and the reason when the step is not the lowest step.
5900
5932
  */
5901
- function nodeAt(trace, path) {
5902
- const want = path.map(String);
5903
- let node = trace;
5904
- let at = 0;
5905
- while (node !== void 0 && at < want.length) {
5906
- const here = node;
5907
- node = here.children.find((child) => {
5908
- const tail = child.path.slice(here.path.length);
5909
- return tail.length > 0 && tail.every((key, index) => key === want[at + index]);
5910
- });
5911
- if (node !== void 0) at += node.path.length - here.path.length;
5933
+ function stepOf(ladder, walk, root) {
5934
+ const top = ladder.steps.length - 1;
5935
+ let best = 0;
5936
+ let reason;
5937
+ const seen = /* @__PURE__ */ new Set();
5938
+ const todo = [{
5939
+ node: root,
5940
+ key: void 0,
5941
+ parent: void 0
5942
+ }];
5943
+ for (let visit = todo.pop(); visit !== void 0; visit = todo.pop()) {
5944
+ const { node } = visit;
5945
+ if (typeof node === "object" && node !== null) {
5946
+ if (seen.has(node)) continue;
5947
+ seen.add(node);
5948
+ }
5949
+ const construct = walk.construct(node);
5950
+ const step = construct === void 0 || !Object.hasOwn(ladder.constructs, construct) ? void 0 : ladder.constructs[construct];
5951
+ const rank = step === void 0 ? 0 : ladder.steps.indexOf(step);
5952
+ if (rank > best) {
5953
+ best = rank;
5954
+ reason = {
5955
+ construct,
5956
+ step,
5957
+ path: pathOf(visit),
5958
+ node
5959
+ };
5960
+ if (best === top) break;
5961
+ }
5962
+ const kids = [...walk.children(node)];
5963
+ for (let i = kids.length - 1; i >= 0; i--) {
5964
+ const [key, child] = kids[i];
5965
+ todo.push({
5966
+ node: child,
5967
+ key,
5968
+ parent: visit
5969
+ });
5970
+ }
5912
5971
  }
5913
- return node;
5972
+ const step = ladder.steps[best];
5973
+ return reason === void 0 ? { step } : {
5974
+ step,
5975
+ reason
5976
+ };
5914
5977
  }
5915
5978
  /**
5916
- * This function lists the nodes of a trace in the order of their start.
5979
+ * This function compares the step of a document with the highest step that the host accepts (STEPS.MAX). The limit
5980
+ * changes only which documents the host accepts. The language evaluates an accepted document as before, thus a limit
5981
+ * does not change a value.
5917
5982
  *
5918
- * @param trace - The root of the trace.
5919
- * @returns Each node, the root first.
5983
+ * @param ladder - The ladder of the language.
5984
+ * @param need - The step of the document, from `stepOf`.
5985
+ * @param maxStep - The highest step that the host accepts.
5986
+ * @returns `undefined` when the host accepts the document, or the refusal that names the needed step.
5987
+ * @throws TypeError when `maxStep` or the step of `need` is not a step of the ladder.
5920
5988
  */
5921
- function flatten(trace) {
5922
- const out = [];
5923
- const stack = [trace];
5924
- while (stack.length > 0) {
5925
- const node = stack.pop();
5926
- out.push(node);
5927
- for (let index = node.children.length - 1; index >= 0; index -= 1) stack.push(node.children[index]);
5928
- }
5929
- return out.sort((a, b) => a.enter - b.enter);
5989
+ function checkStep(ladder, need, maxStep) {
5990
+ const limit = stepRank(ladder, maxStep);
5991
+ if (stepRank(ladder, need.step) <= limit) return void 0;
5992
+ const head = `the document needs the step ${need.step}, and the host accepts the steps up to ${maxStep}`;
5993
+ const reason = need.reason;
5994
+ if (reason === void 0) return {
5995
+ needed: need.step,
5996
+ maxStep,
5997
+ message: head
5998
+ };
5999
+ const where = reason.path.length === 0 ? "at the root" : `at the path ${JSON.stringify(reason.path)}`;
6000
+ return {
6001
+ needed: need.step,
6002
+ maxStep,
6003
+ reason,
6004
+ message: `${head}. The construct "${reason.construct}" ${where} needs the step ${reason.step}`
6005
+ };
6006
+ }
6007
+ // src/classify.ts
6008
+ function isStrictSuperset(larger, smaller) {
6009
+ return larger.length > smaller.length && smaller.every((name) => larger.includes(name));
5930
6010
  }
5931
6011
  /**
5932
- * This function lists the errors of a trace: each node whose result is an error and whose parts did not fail
5933
- * the same way. These nodes are where each error started.
6012
+ * This function proposes a kind for a value without a type, from the fields that the value has.
6013
+ * A shape applies when the value has each field of the shape. The most specific shapes are the ones that
6014
+ * no other applicable shape contains. A host uses a classifier when data comes in, and then tags the data.
6015
+ * The ladder does not call a classifier.
5934
6016
  *
5935
- * @param trace - The root of the trace.
5936
- * @returns The errors, in the order of their start.
6017
+ * @param shapes - The shapes to examine.
6018
+ * @param value - The value without a type.
6019
+ * @returns The proposed kind, or an error with the candidates.
5937
6020
  */
5938
- function failures(trace) {
5939
- return flatten(trace).filter((node) => !node.result.ok && !node.children.some((child) => !child.result.ok && child.result.error === node.result.error)).map((node) => node.result.error);
6021
+ function classify(shapes, value) {
6022
+ const applicable = isRecord(value) ? shapes.filter((shape) => shape.fields.every((name) => field(value, name) !== void 0)) : [];
6023
+ const best = applicable.filter((shape) => !applicable.some((other) => isStrictSuperset(other.fields, shape.fields)));
6024
+ const candidates = best.map((shape) => shape.name);
6025
+ const only = best.length === 1 ? best[0] : void 0;
6026
+ if (only !== void 0) return {
6027
+ kind: only.kind,
6028
+ candidates
6029
+ };
6030
+ return {
6031
+ candidates,
6032
+ error: best.length === 0 ? "no-match" : "ambiguous"
6033
+ };
6034
+ }
6035
+ /**
6036
+ * This function puts a value in an envelope with a type. The value does not change.
6037
+ *
6038
+ * @param value - The value.
6039
+ * @param kind - The name of the kind.
6040
+ * @returns The envelope.
6041
+ */
6042
+ function tag(value, kind) {
6043
+ return typed(kind, value);
5940
6044
  }
5941
6045
  // src/stdlib.ts
5942
6046
  /**
@@ -6437,9 +6541,13 @@ function allValues(results) {
6437
6541
  const errors = results.filter((result) => !result.ok);
6438
6542
  const first = errors[0];
6439
6543
  if (first !== void 0 && errors.length === 1) return { error: first };
6440
- if (errors.length > 1) return { error: fail("#ARGS", `${errors.length} parts failed.`) };
6544
+ if (errors.length > 1) return { error: partsFailed(errors) };
6441
6545
  return { values: results.map((result) => result.ok ? result.value : null) };
6442
6546
  }
6547
+ /** This function gives the error of more than one failed part. */
6548
+ function partsFailed(errors) {
6549
+ return errors.find((result) => !result.ok && result.error.code === "#WORK!") ?? fail("#ARGS", `${errors.length} parts failed.`);
6550
+ }
6443
6551
  function numbers(values, kind) {
6444
6552
  const bad = values.findIndex((value) => !isNumber(value));
6445
6553
  if (bad !== -1) return fail("#VALUE!", `Part ${bad} of ${kind} is not a number.`);
@@ -6919,20 +7027,24 @@ function putField(target, key, value) {
6919
7027
  * This function gives a value with the JSON of each node of a tree in it. A list or a plain record is new only when
6920
7028
  * it holds a node. A container that holds itself stays as it is.
6921
7029
  */
6922
- function plainOf(value, path) {
7030
+ function plainOf(value, path, runtime) {
7031
+ if (typeof value !== "object" || value === null) return ok(value);
6923
7032
  const state = stateOf(value);
7033
+ const open = path.get(value);
6924
7034
  if (state !== void 0) {
6925
- if (path.has(value)) return fail("#CYCLE!", `The JSON of the node ${state.type} at [${state.place.join(", ")}] holds the node itself.`);
7035
+ if (open === true) return fail("#CYCLE!", `The JSON of the node ${state.type} at [${state.place.join(", ")}] holds the node itself.`);
7036
+ if (open === false) runtime?.spend?.(1);
6926
7037
  return state.json(path);
6927
7038
  }
6928
- if (typeof value !== "object" || value === null || path.has(value) || isHostThing(value)) return ok(value);
7039
+ if (open === true || isHostThing(value)) return ok(value);
6929
7040
  if (!Array.isArray(value) && !isRecord(value)) return ok(value);
6930
- path.add(value);
7041
+ if (open === false) runtime?.spend?.(1);
7042
+ path.set(value, true);
6931
7043
  try {
6932
7044
  if (Array.isArray(value)) {
6933
7045
  let list;
6934
7046
  for (let index = 0; index < value.length; index += 1) {
6935
- const item = plainOf(value[index], path);
7047
+ const item = plainOf(value[index], path, runtime);
6936
7048
  if (!item.ok) return item;
6937
7049
  if (item.value !== value[index]) (list ??= [...value])[index] = item.value;
6938
7050
  }
@@ -6941,7 +7053,7 @@ function plainOf(value, path) {
6941
7053
  const record = value;
6942
7054
  let out;
6943
7055
  for (const key of Object.keys(record)) {
6944
- const item = plainOf(record[key], path);
7056
+ const item = plainOf(record[key], path, runtime);
6945
7057
  if (!item.ok) return item;
6946
7058
  if (item.value === record[key]) continue;
6947
7059
  if (out === void 0) {
@@ -6952,7 +7064,7 @@ function plainOf(value, path) {
6952
7064
  }
6953
7065
  return ok(out ?? value);
6954
7066
  } finally {
6955
- path.delete(value);
7067
+ path.set(value, false);
6956
7068
  }
6957
7069
  }
6958
7070
  /**
@@ -7404,19 +7516,19 @@ function treeThing(input, place, build, outer, host) {
7404
7516
  };
7405
7517
  },
7406
7518
  json(path) {
7407
- path.add(node);
7519
+ path.set(node, true);
7408
7520
  try {
7409
7521
  const out = {};
7410
7522
  for (const part of parts) {
7411
7523
  const result = read(part.key);
7412
7524
  if (!result.ok) return result;
7413
- const value = plainOf(result.value, path);
7525
+ const value = plainOf(result.value, path, runtime);
7414
7526
  if (!value.ok) return value;
7415
7527
  putField(out, part.key, value.value);
7416
7528
  }
7417
7529
  return ok(out);
7418
7530
  } finally {
7419
- path.delete(node);
7531
+ path.set(node, false);
7420
7532
  }
7421
7533
  }
7422
7534
  };
@@ -7439,7 +7551,7 @@ function treeThing(input, place, build, outer, host) {
7439
7551
  return cell !== void 0 && !cell.busy && cell.result !== void 0;
7440
7552
  },
7441
7553
  toJson() {
7442
- const result = state.json(/* @__PURE__ */ new Set());
7554
+ const result = state.json(/* @__PURE__ */ new Map());
7443
7555
  if (!result.ok) throw new Failure(result.error);
7444
7556
  return result.value;
7445
7557
  }
@@ -7479,6 +7591,8 @@ const NO_HOPS = /* @__PURE__ */ Object.freeze({ hops: false });
7479
7591
  * The argument `host` gives the memo cells of the host (TREE.CELL), or `undefined` for the plain memo of each node.
7480
7592
  */
7481
7593
  function treeNode(input, host) {
7594
+ const runtime = input[RUNTIME];
7595
+ if (runtime?.nested === true) runtime.spend?.(8);
7482
7596
  const found = input.resolve(SELF_PATH, NO_HOPS);
7483
7597
  const outer = found.ok ? found.thing : void 0;
7484
7598
  const above = stateOf(outer);
@@ -7488,7 +7602,7 @@ function treeNode(input, host) {
7488
7602
  build.open = true;
7489
7603
  const root = treeThing(input, place, build, outer, host);
7490
7604
  try {
7491
- return stateOf(root).json(/* @__PURE__ */ new Set());
7605
+ return stateOf(root).json(/* @__PURE__ */ new Map());
7492
7606
  } finally {
7493
7607
  build.open = false;
7494
7608
  }
@@ -11280,8 +11394,11 @@ function setOwn$2(target, key, value) {
11280
11394
  });
11281
11395
  else target[key] = value;
11282
11396
  }
11283
- function compiled(compile) {
11284
- return { compile };
11397
+ function compiled(compile, keeps) {
11398
+ return keeps === void 0 ? { compile } : {
11399
+ compile,
11400
+ keeps
11401
+ };
11285
11402
  }
11286
11403
  /** This function evaluates parts in order. It gives the value of each part, or the first error. */
11287
11404
  function valuesOf(parts, ctx, rt) {
@@ -12009,7 +12126,7 @@ function makeEvaluators(profile) {
12009
12126
  const evaluator = evaluators[name];
12010
12127
  const type = Object.hasOwn(types, name) ? types[name] : void 0;
12011
12128
  const made = Object.freeze(type === void 0 ? evaluator : {
12012
- compile: evaluator.compile,
12129
+ ...evaluator,
12013
12130
  type
12014
12131
  });
12015
12132
  if (truth !== void 0 && TRUTH_READERS.includes(name)) truthByCode.set(made, truth);
@@ -12278,7 +12395,10 @@ function formulaCode(profile) {
12278
12395
  const closure = (...args) => {
12279
12396
  const level = (clock.applying ?? 0) + 1;
12280
12397
  if (level > limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
12398
+ rt.spend?.(1);
12399
+ const root = clock.top ?? clock;
12281
12400
  clock.applying = level;
12401
+ root.active = (root.active ?? 0) + 1;
12282
12402
  try {
12283
12403
  const scope = { ...ctx.names };
12284
12404
  names.forEach((name, index) => setOwn$2(scope, name, args[index]));
@@ -12290,12 +12410,13 @@ function formulaCode(profile) {
12290
12410
  return result.value;
12291
12411
  } finally {
12292
12412
  clock.applying = level - 1;
12413
+ root.active = (root.active ?? 1) - 1;
12293
12414
  }
12294
12415
  };
12295
12416
  Object.defineProperty(closure, CLOSURE$3, { value: { params: names } });
12296
12417
  return ok(closure);
12297
12418
  };
12298
- }),
12419
+ }, true),
12299
12420
  "formula.call": compiled(({ value }) => {
12300
12421
  const record = partsOf$1(value);
12301
12422
  const fnPart = record["fn"];
@@ -13081,22 +13202,35 @@ function* together(env, list, options = {}) {
13081
13202
  * @returns The result.
13082
13203
  */
13083
13204
  function reference(machine, doc, context = makeContext(), options = {}) {
13084
- return evaluateRoot(machine, doc, context, options, void 0);
13205
+ return evaluateRoot(machine, doc, context, options, void 0, void 0);
13085
13206
  }
13086
13207
  /**
13087
- * This function evaluates a document from its root. An equation of a tree gives the record of its tree. Thus the
13088
- * reads of the equation go in the list of the outer evaluation (REF.READS).
13208
+ * This function evaluates a document from its root. An equation of a tree gives the record of its tree and the count
13209
+ * of its work. Thus its reads go in the list of the outer evaluation (REF.READS), and its work in the outer count
13210
+ * (WORK.EQUATION).
13089
13211
  */
13090
- function evaluateRoot(machine, doc, context, options, outer) {
13212
+ function evaluateRoot(machine, doc, context, options, outer, meter) {
13091
13213
  const at = rootAt(machine, doc, context, options);
13092
- const env = envOf(machine, options, false, at.ctx, outer);
13214
+ const env = envOf(machine, options, false, at.ctx, outer, meter);
13093
13215
  try {
13094
13216
  return within(env, () => evaluateAt(env, at));
13095
13217
  } catch (error) {
13096
13218
  return placed(thrown(error, "the reference"), []);
13219
+ } finally {
13220
+ if (!env.nested) env.meter.ended = true;
13097
13221
  }
13098
13222
  }
13099
13223
  /**
13224
+ * WORK.LIMIT: this function adds work to the count of an evaluation. After the end of the evaluation, each entry from
13225
+ * the host starts a new count (WORK.AFTER). A count over the limit throws `#WORK!`.
13226
+ */
13227
+ function spend(env, points) {
13228
+ const meter = env.meter;
13229
+ if (meter.ended && meter.active === 0) meter.spent = 0;
13230
+ meter.spent += points;
13231
+ if (meter.spent > env.maxWork) throw new Failure(workFailure(env.maxWork));
13232
+ }
13233
+ /**
13100
13234
  * This function starts a run of a document by the rules, without a compilation (REF.RUN). The host does each effect of a runner,
13101
13235
  * and a step waits when the host waits (RUN.SEQ). `all` settles the waits in the order of the host, or in the order
13102
13236
  * of the journal of a replay (RUN.REPLAY). An effect of an evaluator gives `#CALC!` (RUN.NEEDS-RUNNER). A signal that
@@ -13113,14 +13247,16 @@ function evaluateRoot(machine, doc, context, options, outer) {
13113
13247
  */
13114
13248
  function referenceRun(machine, doc, context = makeContext(), options = {}) {
13115
13249
  const at = rootAt(machine, doc, context, options);
13116
- const env = envOf(machine, options, true, at.ctx, void 0);
13117
- return driveRun(env, stepsAt(env, at), options.signal).catch((error) => placed(thrown(error, "the reference"), []));
13250
+ const env = envOf(machine, options, true, at.ctx, void 0, void 0);
13251
+ return driveRun(env, stepsAt(env, at), options.signal).catch((error) => placed(thrown(error, "the reference"), [])).finally(() => {
13252
+ env.meter.ended = true;
13253
+ });
13118
13254
  }
13119
13255
  /**
13120
13256
  * This function makes the state of the reference for one evaluation or one run. The record of the reads comes from
13121
13257
  * the evaluation around it, or from the list of the options.
13122
13258
  */
13123
- function envOf(machine, options, running, root, outer) {
13259
+ function envOf(machine, options, running, root, outer, meter) {
13124
13260
  const perform = options.perform;
13125
13261
  return {
13126
13262
  machine,
@@ -13138,6 +13274,13 @@ function envOf(machine, options, running, root, outer) {
13138
13274
  },
13139
13275
  held: 0,
13140
13276
  applying: 0,
13277
+ maxWork: machine.maxWork ?? 2e5,
13278
+ meter: meter ?? {
13279
+ spent: 0,
13280
+ ended: false,
13281
+ active: 0
13282
+ },
13283
+ nested: meter !== void 0,
13141
13284
  reading: outer ?? (options.reads === void 0 ? void 0 : {
13142
13285
  list: options.reads,
13143
13286
  root
@@ -13231,7 +13374,7 @@ function equationOf(node, term, names) {
13231
13374
  return evaluateRoot(env.machine, term, ctx, {
13232
13375
  definitions: env.definitions,
13233
13376
  ...node.of === void 0 ? {} : { declaredType: node.of }
13234
- }, env.reading);
13377
+ }, env.reading, env.meter);
13235
13378
  }
13236
13379
  function termIn(table, name) {
13237
13380
  return table === void 0 || !Object.hasOwn(table, name) ? void 0 : table[name];
@@ -13581,42 +13724,55 @@ function instanceOf$1(node, attr, args) {
13581
13724
  return result;
13582
13725
  }
13583
13726
  /** TREE.RESULT: the JSON of a node. `open` holds the nodes and the containers whose JSON is in progress. */
13584
- function jsonOfNode(node, self, open) {
13585
- const record = {};
13586
- for (const part of node.parts) {
13587
- const result = attributeOf(node, part.key);
13588
- if (!result.ok) return result;
13589
- const value = plainValue(result.value, [...open, self]);
13590
- if (!value.ok) return value;
13591
- setField$2(record, part.key, value.value);
13727
+ function jsonOfNode(node, self, open, seen) {
13728
+ try {
13729
+ const record = {};
13730
+ for (const part of node.parts) {
13731
+ const result = attributeOf(node, part.key);
13732
+ if (!result.ok) return result;
13733
+ const value = plainValue(node, result.value, [...open, self], seen);
13734
+ if (!value.ok) return value;
13735
+ setField$2(record, part.key, value.value);
13736
+ }
13737
+ return ok(record);
13738
+ } finally {
13739
+ seen.add(self);
13592
13740
  }
13593
- return ok(record);
13594
13741
  }
13595
- /** This function gives a copy of a value with the JSON of each node in it. */
13596
- function plainValue(value, open) {
13742
+ /**
13743
+ * This function gives a copy of a value with the JSON of each node in it. The set `seen` holds each node, list and
13744
+ * record that the walk left. A second visit of one of them counts one point on the evaluation of `owner` (WORK.SHARED).
13745
+ */
13746
+ function plainValue(owner, value, open, seen) {
13597
13747
  const node = refNodeOf(value);
13598
13748
  if (node !== void 0) {
13599
13749
  if (open.includes(value)) return fail("#CYCLE!", `The JSON of the node ${node.kind} at [${node.place.join(", ")}] holds the node itself.`);
13600
- return jsonOfNode(node, value, open);
13750
+ if (seen.has(value) && owner.env !== void 0) spend(owner.env, 1);
13751
+ return jsonOfNode(node, value, open, seen);
13601
13752
  }
13602
13753
  if (typeof value !== "object" || value === null || isHostThing(value) || open.includes(value)) return ok(value);
13603
- if (Array.isArray(value)) {
13604
- const items = [];
13605
- for (const item of value) {
13606
- const plain = plainValue(item, [...open, value]);
13754
+ if (!Array.isArray(value) && !isRecord(value)) return ok(value);
13755
+ if (seen.has(value) && owner.env !== void 0) spend(owner.env, 1);
13756
+ try {
13757
+ if (Array.isArray(value)) {
13758
+ const items = [];
13759
+ for (const item of value) {
13760
+ const plain = plainValue(owner, item, [...open, value], seen);
13761
+ if (!plain.ok) return plain;
13762
+ items.push(plain.value);
13763
+ }
13764
+ return ok(items);
13765
+ }
13766
+ const copy = {};
13767
+ for (const key of Object.keys(value)) {
13768
+ const plain = plainValue(owner, value[key], [...open, value], seen);
13607
13769
  if (!plain.ok) return plain;
13608
- items.push(plain.value);
13770
+ setField$2(copy, key, plain.value);
13609
13771
  }
13610
- return ok(items);
13611
- }
13612
- if (!isRecord(value)) return ok(value);
13613
- const copy = {};
13614
- for (const key of Object.keys(value)) {
13615
- const plain = plainValue(value[key], [...open, value]);
13616
- if (!plain.ok) return plain;
13617
- setField$2(copy, key, plain.value);
13772
+ return ok(copy);
13773
+ } finally {
13774
+ seen.add(value);
13618
13775
  }
13619
- return ok(copy);
13620
13776
  }
13621
13777
  /**
13622
13778
  * TREE.LAZY, TREE.PARENT, TREE.SIBLING and TREE.ERROR: a node of an open tree gives its thing, and the root of a new
@@ -13624,6 +13780,8 @@ function plainValue(value, open) {
13624
13780
  * reads `self` only through `resolve` (C4, TREE.SELF).
13625
13781
  */
13626
13782
  const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolve: walk, doc }) => {
13783
+ const maker = activeEnvs[activeEnvs.length - 1];
13784
+ if (maker?.nested === true) spend(maker, 8);
13627
13785
  const reached = walk(["self"]);
13628
13786
  const parent = reached.ok ? reached.thing : void 0;
13629
13787
  const outer = refNodeOf(parent);
@@ -13659,7 +13817,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
13659
13817
  },
13660
13818
  has: (key) => key === "parent" || key === "type" || parts.some((part) => part.key === String(key)) || node.values.has(String(key)),
13661
13819
  toJson: () => {
13662
- const result = jsonOfNode(node, self, []);
13820
+ const result = jsonOfNode(node, self, [], /* @__PURE__ */ new Set());
13663
13821
  if (result.ok) return result.value;
13664
13822
  throw new Failure(result.error);
13665
13823
  }
@@ -13669,7 +13827,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
13669
13827
  AT_READERS.set(self, (attr, args) => instanceOf$1(node, attr, args));
13670
13828
  if (nested) return ok(self);
13671
13829
  try {
13672
- return jsonOfNode(node, self, []);
13830
+ return jsonOfNode(node, self, [], /* @__PURE__ */ new Set());
13673
13831
  } finally {
13674
13832
  node.tree.open = false;
13675
13833
  }
@@ -13806,26 +13964,37 @@ function formulaDefinitions(profile = {}) {
13806
13964
  if (!Array.isArray(params) || !params.every((param) => typeof param === "string") || new Set(params).size !== params.length) return fail("#VALUE!", "The params of fn are a list of different texts.");
13807
13965
  const names = params;
13808
13966
  const body = partNamed$1(parts, "body");
13809
- const clock = activeEnvs[activeEnvs.length - 1] ?? {
13967
+ const maker = activeEnvs[activeEnvs.length - 1];
13968
+ const clock = maker ?? {
13810
13969
  applying: 0,
13811
- maxDepth: 1e3
13970
+ maxDepth: 1e3,
13971
+ maxWork: 2e5,
13972
+ meter: {
13973
+ spent: 0,
13974
+ ended: false,
13975
+ active: 0
13976
+ }
13812
13977
  };
13813
13978
  const limit = Math.ceil(clock.maxDepth / 4);
13814
13979
  const closure = (...args) => {
13815
13980
  if (clock.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
13981
+ spend(clock, 1);
13816
13982
  clock.applying += 1;
13983
+ clock.meter.active += 1;
13817
13984
  try {
13818
13985
  const scope = {};
13819
13986
  for (const key of Object.keys(context.names)) setField$2(scope, key, context.names[key]);
13820
13987
  names.forEach((name, index) => setField$2(scope, name, args[index]));
13821
- const result = body.evaluate({
13988
+ const scoped = {
13822
13989
  ...context,
13823
13990
  names: scope
13824
- });
13991
+ };
13992
+ const result = maker === void 0 ? body.evaluate(scoped) : within(maker, () => body.evaluate(scoped));
13825
13993
  if (!result.ok) throw new Failure(result.error);
13826
13994
  return result.value;
13827
13995
  } finally {
13828
13996
  clock.applying -= 1;
13997
+ clock.meter.active -= 1;
13829
13998
  }
13830
13999
  };
13831
14000
  Object.defineProperty(closure, CLOSURE$2, { value: { params: names } });
@@ -14322,6 +14491,11 @@ function apply(p, c, target, args) {
14322
14491
  }
14323
14492
  const limit = Math.ceil(p.maxDepth / 4);
14324
14493
  if (c.applying >= limit) return back(c, fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`));
14494
+ p.work += 1;
14495
+ if (p.work > p.maxWork) return back(c, {
14496
+ ok: false,
14497
+ error: workFailure(p.maxWork)
14498
+ });
14325
14499
  pushed(c, {
14326
14500
  f: "return",
14327
14501
  place: closure.place.concat(closure.body.path)
@@ -14348,6 +14522,9 @@ function hostClosure(p, value, closure) {
14348
14522
  const fn = (...args) => {
14349
14523
  const limit = Math.ceil(p.maxDepth / 4);
14350
14524
  if (p.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
14525
+ p.work = (p.ended && p.applying === 0 ? 0 : p.work) + 1;
14526
+ if (p.work > p.maxWork) throw new Failure(workFailure(p.maxWork));
14527
+ const before = p.applying;
14351
14528
  p.applying += 1;
14352
14529
  try {
14353
14530
  const place = closure.place.concat(closure.body.path);
@@ -14364,7 +14541,7 @@ function hostClosure(p, value, closure) {
14364
14541
  if (!end.result.ok) throw new Failure(end.result.error);
14365
14542
  return forHost(p, end, end.result.value);
14366
14543
  } finally {
14367
- p.applying -= 1;
14544
+ p.applying = before;
14368
14545
  }
14369
14546
  };
14370
14547
  Object.defineProperty(fn, CLOSURE$1, { value: { params: closure.params } });
@@ -14695,7 +14872,7 @@ function cause(p, ctx, kind, payload, place) {
14695
14872
  const count = counts.get(at) ?? 0;
14696
14873
  counts.set(at, count + 1);
14697
14874
  const effect = {
14698
- index: effects.length,
14875
+ index: p.before + effects.length,
14699
14876
  kind: text,
14700
14877
  path: keys,
14701
14878
  payload,
@@ -14801,7 +14978,8 @@ function evaluateDoc(p, c) {
14801
14978
  } catch (error) {
14802
14979
  return back(c, thrown(error, `the evaluator ${name}`));
14803
14980
  }
14804
- const defined = own$1(p.definitions.evaluators, name);
14981
+ const standard = code === own$1(STD_EVALUATORS, name) ? own$1(STD_DEFINITIONS.evaluators, name) : void 0;
14982
+ const defined = own$1(p.definitions.evaluators, name) ?? standard;
14805
14983
  if (defined !== void 0) return hostEvaluator(p, c, name, defined, doc, keys, read.data, read.slots, site);
14806
14984
  return back(c, fail("#NOEVAL", `The stepper has no definition of the compiled evaluator ${name}.`));
14807
14985
  }
@@ -14958,7 +15136,11 @@ function programOf(machine, options) {
14958
15136
  effects: options.effects ?? [],
14959
15137
  perform: options.perform,
14960
15138
  counts: /* @__PURE__ */ new Map(),
14961
- applying: 0
15139
+ before: 0,
15140
+ applying: 0,
15141
+ maxWork: machine.maxWork ?? 2e5,
15142
+ work: 0,
15143
+ ended: false
14962
15144
  };
14963
15145
  }
14964
15146
  /**
@@ -15014,10 +15196,21 @@ function stepperNext(machine, configuration, options = {}) {
15014
15196
  };
15015
15197
  else stack[stack.length - 1] = { ...top };
15016
15198
  }
15017
- return advance(programOf(machine, options), {
15199
+ const p = programOf(machine, options);
15200
+ p.work = configuration.work ?? 0;
15201
+ for (const [at, count] of Object.entries(configuration.counts ?? {})) p.counts.set(at, count);
15202
+ p.before = options.effects === void 0 ? configuration.effected ?? 0 : 0;
15203
+ const next = advance(p, {
15018
15204
  ...configuration,
15019
15205
  stack
15020
15206
  });
15207
+ const effected = p.before + p.effects.length;
15208
+ return {
15209
+ ...next,
15210
+ ...p.work === 0 ? {} : { work: p.work },
15211
+ ...p.counts.size === 0 ? {} : { counts: Object.fromEntries(p.counts) },
15212
+ ...effected === 0 ? {} : { effected }
15213
+ };
15021
15214
  }
15022
15215
  /**
15023
15216
  * This function evaluates a document with an explicit stack (K95, D158). It gives the result of `reference` for each
@@ -15035,6 +15228,7 @@ function stepper(machine, doc, context = makeContext(), options = {}) {
15035
15228
  const p = programOf(machine, options);
15036
15229
  try {
15037
15230
  const end = drive$1(p, stepperStart(machine, doc, context, options));
15231
+ p.ended = true;
15038
15232
  return end.result.ok ? ok(forHost(p, end, end.result.value)) : end.result;
15039
15233
  } catch (error) {
15040
15234
  return placed(thrown(error, "the stepper"), []);
@@ -18786,7 +18980,10 @@ function generate(world, options) {
18786
18980
  value
18787
18981
  };
18788
18982
  if (header !== void 0) out["name"] = header;
18789
- if (options.own !== void 0 && options.own.length > 0 && rng.chance(.03)) out["own"] = { eval: rng.pick(options.own) };
18983
+ if (options.own !== void 0 && options.own.length > 0 && rng.chance(.03)) {
18984
+ const code = rng.pick(options.own);
18985
+ if ((kindOf(type)?.scope ?? []).length === 0) out["own"] = { eval: code };
18986
+ }
18790
18987
  return out;
18791
18988
  };
18792
18989
  /**
@@ -22434,6 +22631,6 @@ function samplesAt(values, closed, depth) {
22434
22631
  function typeFromSamples(values, options = {}) {
22435
22632
  return samplesAt(values, options.closed === true, 0);
22436
22633
  }
22437
- export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, GENERATION_LIMIT, Held, JOURNAL, MAX_SYNTAX_ISSUES, 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, agreeTypes, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, boundariesOf, capKeys, check, checkCycles, checkLatent, checkStep, checkSteps, checkSyntax, checkWorld, circularOf, classify, codecLaws, collectOf, compilePath, components, compose, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, defineLanguage, derefStep, describe, docEquals, documentKey, 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, ifRunner, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapDocs, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partGrants, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, resolveCompiled, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stepper, stepperNext, stepperStart, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
22634
+ export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, GENERATION_LIMIT, Held, JOURNAL, MAX_SYNTAX_ISSUES, 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, WORK_LIMIT, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, agreeTypes, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, boundariesOf, boundary, capKeys, check, checkCycles, checkLatent, checkStep, checkSteps, checkSyntax, checkWorld, circularOf, classify, codecLaws, collectOf, compilePath, components, compose, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, defineLanguage, derefStep, describe, docEquals, documentKey, 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, ifRunner, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapDocs, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partGrants, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, resolveCompiled, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stepper, stepperNext, stepperStart, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
22438
22635
 
22439
22636
  //# sourceMappingURL=index.js.map