@mark1russell7/coeval 0.27.0 → 0.27.2
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.d.ts +19 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1415 -1398
- package/build/index.js.map +1 -1
- package/package.json +3 -1
- package/src/evaluate.ts +7 -2
- package/src/formula.ts +6 -1
- package/src/generate.ts +6 -1
- package/src/graph.ts +5 -64
- package/src/index.ts +1 -1
- package/src/language.ts +51 -1
- package/src/reference.ts +12 -4
- package/src/stepper.ts +49 -6
package/build/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { strongComponentsCompact } from "@mark1russell7/collections/graph";
|
|
1
2
|
import { mulberry32 } from "@mark1russell7/rigor-generators";
|
|
2
3
|
// src/doc.ts
|
|
3
4
|
/** The keys that an envelope can have. */
|
|
@@ -2579,483 +2580,578 @@ function restrictMachine(machine, paths) {
|
|
|
2579
2580
|
...tables.domains === void 0 ? {} : { domains: tables.domains }
|
|
2580
2581
|
};
|
|
2581
2582
|
}
|
|
2582
|
-
// src/
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
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;
|
|
2583
|
+
// src/parts.ts
|
|
2584
|
+
var Bad$1 = class {
|
|
2585
|
+
reason;
|
|
2586
|
+
at;
|
|
2587
|
+
constructor(reason, at) {
|
|
2588
|
+
this.reason = reason;
|
|
2589
|
+
this.at = at;
|
|
2605
2590
|
}
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
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
|
|
2591
|
+
};
|
|
2592
|
+
/** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
|
|
2593
|
+
function setOwn$4(target, key, value) {
|
|
2594
|
+
if (key === "__proto__") Object.defineProperty(target, key, {
|
|
2595
|
+
value,
|
|
2596
|
+
enumerable: true,
|
|
2597
|
+
writable: true,
|
|
2598
|
+
configurable: true
|
|
2652
2599
|
});
|
|
2600
|
+
else target[key] = value;
|
|
2653
2601
|
}
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
return
|
|
2657
|
-
...code(prev),
|
|
2658
|
-
world
|
|
2659
|
-
}) : {
|
|
2660
|
-
...code,
|
|
2661
|
-
world
|
|
2662
|
-
};
|
|
2602
|
+
const NO_SLOTS = /* @__PURE__ */ Object.freeze([]);
|
|
2603
|
+
function hasSlots(template) {
|
|
2604
|
+
return template.t !== "data";
|
|
2663
2605
|
}
|
|
2664
|
-
/**
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
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);
|
|
2606
|
+
/** This function gives the shape of a part with the default type `of` and the value type `expect` of its container. */
|
|
2607
|
+
function termOf$1(of, expect) {
|
|
2608
|
+
return {
|
|
2609
|
+
shape: "term",
|
|
2610
|
+
...of === void 0 ? {} : { of },
|
|
2611
|
+
...expect === void 0 ? {} : { expect }
|
|
2612
|
+
};
|
|
2711
2613
|
}
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
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;
|
|
2614
|
+
/** This function tells if a shape holds only data: no value of the shape can hold a part. */
|
|
2615
|
+
function isData(shape) {
|
|
2616
|
+
return shape.shape === "none" || shape.shape === "text" || shape.shape === "number" || shape.shape === "one";
|
|
2721
2617
|
}
|
|
2722
|
-
/**
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
function kindOf(world, type) {
|
|
2731
|
-
const found = lookupKind(world, type);
|
|
2732
|
-
return found.ok ? found.kind : void 0;
|
|
2618
|
+
/** This function gives the reason why a value is not data of a shape, or `undefined` when it is. */
|
|
2619
|
+
function dataFault(spec, item) {
|
|
2620
|
+
if (spec.shape === "text") return typeof item === "string" ? void 0 : "The value must be a text.";
|
|
2621
|
+
if (spec.shape === "one") return spec.values.some((value) => docEquals(value, item)) ? void 0 : `The value must be one of ${JSON.stringify(spec.values)}.`;
|
|
2622
|
+
if (typeof item !== "number") return "The value must be a number.";
|
|
2623
|
+
if (spec.whole === true && !Number.isInteger(item)) return "The value must be a whole number.";
|
|
2624
|
+
if (spec.min !== void 0 && !(item >= spec.min)) return `The value must be ${String(spec.min)} or more.`;
|
|
2625
|
+
if (spec.max !== void 0 && !(item <= spec.max)) return `The value must be ${String(spec.max)} or less.`;
|
|
2733
2626
|
}
|
|
2734
|
-
/**
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
*/
|
|
2741
|
-
function kindNamed(world, name) {
|
|
2742
|
-
return kindOf(world, name);
|
|
2627
|
+
/** This function stops a split when a part has a type that its position does not permit. */
|
|
2628
|
+
function kindFault(kinds, item, of, path) {
|
|
2629
|
+
const type = isEnvelope(item) ? typePath(item.type) : of === void 0 ? void 0 : [of];
|
|
2630
|
+
if (type !== void 0 && kinds.some((kind) => kind.length <= type.length && kind.every((key, index) => String(key) === String(type[index])))) return;
|
|
2631
|
+
const names = kinds.map((kind) => kind.join(".")).join(", ");
|
|
2632
|
+
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
2633
|
}
|
|
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
2634
|
/**
|
|
2747
|
-
* This function
|
|
2748
|
-
*
|
|
2749
|
-
* `deref` and the walkers of steps use it, thus each verb has one ladder.
|
|
2635
|
+
* This function splits a value into its parts, by the shape that its kind declares. The evaluator, the view and
|
|
2636
|
+
* the static kit use the same split, thus each one sees the same parts.
|
|
2750
2637
|
*
|
|
2751
|
-
* @param
|
|
2752
|
-
* @param
|
|
2753
|
-
* @
|
|
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.
|
|
2638
|
+
* @param shape - The shape of the value. The default is data.
|
|
2639
|
+
* @param value - The value of the document.
|
|
2640
|
+
* @returns The parts and a way to fill their places, or the reason why the value does not have the shape.
|
|
2758
2641
|
*/
|
|
2759
|
-
function
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2642
|
+
function splitParts(shape, value) {
|
|
2643
|
+
if (shape === void 0 || shape.shape === "none") return {
|
|
2644
|
+
ok: true,
|
|
2645
|
+
parts: NO_SLOTS,
|
|
2646
|
+
data: value,
|
|
2647
|
+
fill: () => value
|
|
2764
2648
|
};
|
|
2765
|
-
|
|
2766
|
-
const
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2649
|
+
const parts = [];
|
|
2650
|
+
const slot = (item, path, of, address = false, expect) => {
|
|
2651
|
+
parts.push({
|
|
2652
|
+
path,
|
|
2653
|
+
key: path.join("."),
|
|
2654
|
+
item,
|
|
2655
|
+
...of === void 0 ? {} : { of },
|
|
2656
|
+
...address ? { address: true } : {},
|
|
2657
|
+
...expect === void 0 ? {} : { expect }
|
|
2658
|
+
});
|
|
2659
|
+
return {
|
|
2660
|
+
t: "slot",
|
|
2661
|
+
index: parts.length - 1
|
|
2662
|
+
};
|
|
2770
2663
|
};
|
|
2771
|
-
const
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
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
|
-
});
|
|
2664
|
+
const deep = (item, path, of, expect) => {
|
|
2665
|
+
if (isEnvelope(item)) return slot(item, path, of, false, expect);
|
|
2666
|
+
if (Array.isArray(item)) {
|
|
2667
|
+
const items = item.map((child, index) => deep(child, [...path, index], of, expect));
|
|
2668
|
+
return items.some(hasSlots) ? {
|
|
2669
|
+
t: "list",
|
|
2670
|
+
items
|
|
2671
|
+
} : {
|
|
2672
|
+
t: "data",
|
|
2673
|
+
value: item
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
if (isRecord(item)) {
|
|
2677
|
+
const fields = Object.keys(item).map((key) => [key, deep(item[key], [...path, key], of, expect)]);
|
|
2678
|
+
return fields.some(([, child]) => hasSlots(child)) ? {
|
|
2679
|
+
t: "record",
|
|
2680
|
+
fields
|
|
2681
|
+
} : {
|
|
2682
|
+
t: "data",
|
|
2683
|
+
value: item
|
|
2684
|
+
};
|
|
2685
|
+
}
|
|
2800
2686
|
return {
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
rung: "own",
|
|
2804
|
-
steps
|
|
2687
|
+
t: "data",
|
|
2688
|
+
value: item
|
|
2805
2689
|
};
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
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
|
-
});
|
|
2690
|
+
};
|
|
2691
|
+
const walk = (spec, item, path) => {
|
|
2692
|
+
if (spec === void 0 || spec.shape === "none") return {
|
|
2693
|
+
t: "data",
|
|
2694
|
+
value: item
|
|
2695
|
+
};
|
|
2696
|
+
if (spec.shape === "text" || spec.shape === "number" || spec.shape === "one") {
|
|
2697
|
+
const reason = dataFault(spec, item);
|
|
2698
|
+
if (reason !== void 0) throw new Bad$1(reason, path);
|
|
2827
2699
|
return {
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
steps
|
|
2700
|
+
t: "data",
|
|
2701
|
+
value: item
|
|
2831
2702
|
};
|
|
2832
2703
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2704
|
+
if (spec.shape === "term") {
|
|
2705
|
+
if (spec.kinds !== void 0) kindFault(spec.kinds, item, spec.of, path);
|
|
2706
|
+
return slot(item, path, spec.of, spec.address === true, spec.expect);
|
|
2707
|
+
}
|
|
2708
|
+
if (spec.shape === "deep") return deep(item, path, spec.of, spec.expect);
|
|
2709
|
+
if (spec.shape === "list") {
|
|
2710
|
+
if (!Array.isArray(item)) throw new Bad$1("The value must be a list.", path);
|
|
2711
|
+
const list = item;
|
|
2712
|
+
if (spec.distinct === true) {
|
|
2713
|
+
const twice = list.findIndex((child, index) => list.slice(0, index).some((before) => docEquals(before, child)));
|
|
2714
|
+
if (twice !== -1) throw new Bad$1("The items of the list must be different.", [...path, twice]);
|
|
2715
|
+
}
|
|
2716
|
+
const each = spec.item ?? termOf$1(spec.of, spec.expect);
|
|
2717
|
+
const items = list.map((child, index) => walk(each, child, [...path, index]));
|
|
2718
|
+
return isData(each) ? {
|
|
2719
|
+
t: "data",
|
|
2720
|
+
value: item
|
|
2721
|
+
} : {
|
|
2722
|
+
t: "list",
|
|
2723
|
+
items
|
|
2724
|
+
};
|
|
2725
|
+
}
|
|
2726
|
+
if (!isRecord(item)) throw new Bad$1("The value must be a record.", path);
|
|
2727
|
+
if (spec.shape === "map") {
|
|
2728
|
+
const each = spec.item ?? termOf$1(spec.of, spec.expect);
|
|
2842
2729
|
return {
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
rung: "kind",
|
|
2846
|
-
steps
|
|
2730
|
+
t: "record",
|
|
2731
|
+
fields: Object.keys(item).map((key) => [key, walk(each, item[key], [...path, key])])
|
|
2847
2732
|
};
|
|
2848
2733
|
}
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
if (fallback !== void 0) {
|
|
2858
|
-
steps.push({
|
|
2859
|
-
rung: "default",
|
|
2860
|
-
outcome: "answers",
|
|
2861
|
-
evaluator: fallback
|
|
2862
|
-
});
|
|
2734
|
+
for (const name of spec.required ?? []) if (!Object.hasOwn(item, name)) throw new Bad$1(`The field ${name} is missing.`, path);
|
|
2735
|
+
const named = Array.isArray(spec.fields) ? Object.fromEntries(spec.fields.map((name) => [name, termOf$1(spec.of, spec.expect)])) : spec.fields;
|
|
2736
|
+
const fields = [];
|
|
2737
|
+
for (const key of Object.keys(item)) {
|
|
2738
|
+
if (spec.closed === true && !Object.hasOwn(named, key)) throw new Bad$1(`The field ${key} is not a field of this kind.`, [...path, key]);
|
|
2739
|
+
const fieldShape = Object.hasOwn(named, key) ? named[key] : spec.rest;
|
|
2740
|
+
fields.push([key, walk(fieldShape, item[key], [...path, key])]);
|
|
2741
|
+
}
|
|
2863
2742
|
return {
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2743
|
+
t: "record",
|
|
2744
|
+
fields
|
|
2745
|
+
};
|
|
2746
|
+
};
|
|
2747
|
+
let template;
|
|
2748
|
+
try {
|
|
2749
|
+
template = walk(shape, value, []);
|
|
2750
|
+
} catch (error) {
|
|
2751
|
+
if (error instanceof Bad$1) return {
|
|
2752
|
+
ok: false,
|
|
2753
|
+
reason: error.reason,
|
|
2754
|
+
at: error.at
|
|
2868
2755
|
};
|
|
2756
|
+
throw error;
|
|
2869
2757
|
}
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2758
|
+
const strip = (node) => {
|
|
2759
|
+
if (node.t === "data") return node.value;
|
|
2760
|
+
if (node.t === "slot") return void 0;
|
|
2761
|
+
if (node.t === "list") return node.items.every((child) => child.t === "slot") ? null : node.items.map((child) => strip(child) ?? null);
|
|
2762
|
+
const out = {};
|
|
2763
|
+
for (const [key, child] of node.fields) {
|
|
2764
|
+
const kept = strip(child);
|
|
2765
|
+
if (kept !== void 0) setOwn$4(out, key, kept);
|
|
2766
|
+
}
|
|
2767
|
+
return out;
|
|
2768
|
+
};
|
|
2769
|
+
const fillWith = (node, handles) => {
|
|
2770
|
+
if (node.t === "data") return node.value;
|
|
2771
|
+
if (node.t === "slot") return handles[node.index];
|
|
2772
|
+
if (node.t === "list") return node.items.map((child) => fillWith(child, handles));
|
|
2773
|
+
const out = {};
|
|
2774
|
+
for (const [key, child] of node.fields) setOwn$4(out, key, fillWith(child, handles));
|
|
2775
|
+
return out;
|
|
2776
|
+
};
|
|
2874
2777
|
return {
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2778
|
+
ok: true,
|
|
2779
|
+
parts,
|
|
2780
|
+
data: strip(template) ?? null,
|
|
2781
|
+
fill: (handles) => fillWith(template, handles)
|
|
2878
2782
|
};
|
|
2879
2783
|
}
|
|
2880
|
-
// src/steps.ts
|
|
2881
2784
|
/**
|
|
2882
|
-
* This function
|
|
2883
|
-
*
|
|
2785
|
+
* This function reads one document by the contracts of the world. It finds the kind of the type. A bare value gets
|
|
2786
|
+
* the type that its position declares. Then the function splits the value by the shape of the kind. The plan, the
|
|
2787
|
+
* reference interpreter and the static kit read each document with this function. Thus they see the same parts.
|
|
2884
2788
|
*
|
|
2885
|
-
* @param
|
|
2886
|
-
* @param
|
|
2887
|
-
* @
|
|
2888
|
-
* @
|
|
2789
|
+
* @param world - The world of the kinds.
|
|
2790
|
+
* @param value - The document, or a bare value.
|
|
2791
|
+
* @param declaredType - The type that the position of a bare value declares.
|
|
2792
|
+
* @returns The document, its kind and its parts, or the reason why the value is not a document.
|
|
2889
2793
|
*/
|
|
2890
|
-
function
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2794
|
+
function partsOf(world, value, declaredType) {
|
|
2795
|
+
const envelope = isEnvelope(value) ? value : void 0;
|
|
2796
|
+
if (envelope === void 0 && declaredType === void 0) return {
|
|
2797
|
+
ok: false,
|
|
2798
|
+
code: "#PART?",
|
|
2799
|
+
reason: "The value has no envelope, and its position declares no type."
|
|
2800
|
+
};
|
|
2801
|
+
const doc = envelope ?? {
|
|
2802
|
+
type: declaredType,
|
|
2803
|
+
value
|
|
2804
|
+
};
|
|
2805
|
+
const found = lookupKind(world, doc.type);
|
|
2806
|
+
const kind = found.ok ? found.kind : void 0;
|
|
2807
|
+
const split = splitParts(kind?.parts, doc.value);
|
|
2808
|
+
const typePath = found.ok ? found.path : void 0;
|
|
2809
|
+
if (split.ok) return {
|
|
2810
|
+
ok: true,
|
|
2811
|
+
doc,
|
|
2812
|
+
declared: envelope === void 0,
|
|
2813
|
+
kind,
|
|
2814
|
+
typePath,
|
|
2815
|
+
split
|
|
2816
|
+
};
|
|
2817
|
+
const where = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
|
|
2818
|
+
const reason = `${split.reason}${where} The kind is ${typeName(doc.type)}.`;
|
|
2819
|
+
return {
|
|
2820
|
+
ok: true,
|
|
2821
|
+
doc,
|
|
2822
|
+
declared: envelope === void 0,
|
|
2823
|
+
kind,
|
|
2824
|
+
typePath,
|
|
2825
|
+
split: {
|
|
2826
|
+
ok: false,
|
|
2827
|
+
reason,
|
|
2828
|
+
at: split.at
|
|
2829
|
+
}
|
|
2830
|
+
};
|
|
2903
2831
|
}
|
|
2904
2832
|
/**
|
|
2905
|
-
* This function tells if
|
|
2833
|
+
* This function tells if the path of a part matches a pattern of a scope rule. The key `"*"` of a pattern matches
|
|
2834
|
+
* each key.
|
|
2906
2835
|
*
|
|
2907
|
-
* @param
|
|
2908
|
-
* @param
|
|
2909
|
-
* @returns `true` when the
|
|
2836
|
+
* @param path - The path of the part.
|
|
2837
|
+
* @param pattern - The pattern.
|
|
2838
|
+
* @returns `true` when the path matches.
|
|
2910
2839
|
*/
|
|
2911
|
-
function
|
|
2912
|
-
|
|
2840
|
+
function pathMatches(path, pattern) {
|
|
2841
|
+
if (path.length !== pattern.length) return false;
|
|
2842
|
+
for (let index = 0; index < path.length; index += 1) {
|
|
2843
|
+
const want = pattern[index];
|
|
2844
|
+
if (want !== "*" && String(want) !== String(path[index])) return false;
|
|
2845
|
+
}
|
|
2846
|
+
return true;
|
|
2913
2847
|
}
|
|
2914
2848
|
/**
|
|
2915
|
-
* This function
|
|
2849
|
+
* This function tells if a list of rules in the form of the lazy rules covers a part (D24, D119). A rule without
|
|
2850
|
+
* `in` covers each part. With `after: n`, a rule covers only the parts after the first `n` parts that it matches.
|
|
2916
2851
|
*
|
|
2917
|
-
* @param
|
|
2918
|
-
* @param
|
|
2919
|
-
* @
|
|
2920
|
-
* @
|
|
2852
|
+
* @param rules - The rules.
|
|
2853
|
+
* @param shape - The shape of the parts of the parent.
|
|
2854
|
+
* @param value - The value of the parent.
|
|
2855
|
+
* @param slot - The path of the part in the value.
|
|
2856
|
+
* @returns `true` when a rule covers the part.
|
|
2921
2857
|
*/
|
|
2922
|
-
function
|
|
2923
|
-
const
|
|
2924
|
-
|
|
2925
|
-
|
|
2858
|
+
function rulesCover(rules, shape, value, slot) {
|
|
2859
|
+
for (const rule of rules) {
|
|
2860
|
+
if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(slot, pattern))) continue;
|
|
2861
|
+
const after = rule.after ?? 0;
|
|
2862
|
+
if (after <= 0) return true;
|
|
2863
|
+
const split = splitParts(shape, value);
|
|
2864
|
+
let count = 0;
|
|
2865
|
+
for (const part of split.ok ? split.parts : []) {
|
|
2866
|
+
if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(part.path, pattern))) continue;
|
|
2867
|
+
if (part.path.length === slot.length && pathMatches(part.path, slot)) {
|
|
2868
|
+
if (count >= after) return true;
|
|
2869
|
+
break;
|
|
2870
|
+
}
|
|
2871
|
+
count += 1;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
return false;
|
|
2926
2875
|
}
|
|
2927
|
-
function
|
|
2928
|
-
|
|
2929
|
-
for (
|
|
2930
|
-
|
|
2876
|
+
function valueAt(value, path) {
|
|
2877
|
+
let here = value;
|
|
2878
|
+
for (const key of path) if (Array.isArray(here)) here = here[Number(key)];
|
|
2879
|
+
else if (isRecord(here) && Object.hasOwn(here, String(key))) here = here[String(key)];
|
|
2880
|
+
else return void 0;
|
|
2881
|
+
return here;
|
|
2882
|
+
}
|
|
2883
|
+
function headerName(item) {
|
|
2884
|
+
return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
|
|
2885
|
+
}
|
|
2886
|
+
function namesOf(source, value, covered) {
|
|
2887
|
+
if ("fixed" in source) return source.fixed;
|
|
2888
|
+
if ("keysAt" in source) {
|
|
2889
|
+
const at = valueAt(value, source.keysAt);
|
|
2890
|
+
return isRecord(at) ? Object.keys(at) : [];
|
|
2891
|
+
}
|
|
2892
|
+
if ("listAt" in source) {
|
|
2893
|
+
const at = valueAt(value, source.listAt);
|
|
2894
|
+
return Array.isArray(at) ? at.filter((item) => typeof item === "string") : [];
|
|
2895
|
+
}
|
|
2896
|
+
if ("textAt" in source) {
|
|
2897
|
+
const at = valueAt(value, source.textAt);
|
|
2898
|
+
if (typeof at === "string") return [at];
|
|
2899
|
+
return source.otherwise === void 0 ? [] : [source.otherwise];
|
|
2900
|
+
}
|
|
2901
|
+
return covered.map((slot) => headerName(slot.item)).filter((name) => name !== void 0);
|
|
2931
2902
|
}
|
|
2932
2903
|
/**
|
|
2933
|
-
* This function gives the
|
|
2934
|
-
*
|
|
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.
|
|
2904
|
+
* This function gives the names that the scope rules of a kind give each part, and the names that only later parts
|
|
2905
|
+
* see. `check`, `conforms` and the plan read the scope rules with it.
|
|
2937
2906
|
*
|
|
2938
|
-
* @param
|
|
2939
|
-
* @param
|
|
2940
|
-
* @param
|
|
2941
|
-
* @returns The
|
|
2907
|
+
* @param rules - The scope rules of the kind.
|
|
2908
|
+
* @param value - The value of the document.
|
|
2909
|
+
* @param slots - The parts of the value, in order.
|
|
2910
|
+
* @returns The names that each part sees, and the names that only the later parts see, by the index of the part.
|
|
2942
2911
|
*/
|
|
2943
|
-
function
|
|
2944
|
-
const
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
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;
|
|
2912
|
+
function scopesOf(rules, value, slots) {
|
|
2913
|
+
const sees = slots.map(() => []);
|
|
2914
|
+
const later = slots.map(() => []);
|
|
2915
|
+
for (const rule of rules ?? []) {
|
|
2916
|
+
const covered = slots.map((slot, index) => ({
|
|
2917
|
+
slot,
|
|
2918
|
+
index
|
|
2919
|
+
})).filter(({ slot }) => rule.in.some((pattern) => pathMatches(slot.path, pattern)));
|
|
2920
|
+
if (rule.sequential !== true) {
|
|
2921
|
+
const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
|
|
2922
|
+
for (const { index } of covered) sees[index]?.push(...names);
|
|
2923
|
+
continue;
|
|
2971
2924
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
parent: visit
|
|
2925
|
+
if ("headers" in rule.names) {
|
|
2926
|
+
covered.forEach(({ index }, position) => {
|
|
2927
|
+
const before = covered.slice(0, position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
|
|
2928
|
+
const after = covered.slice(position).map(({ slot }) => headerName(slot.item)).filter((name) => name !== void 0);
|
|
2929
|
+
sees[index]?.push(...before);
|
|
2930
|
+
later[index]?.push(...after);
|
|
2979
2931
|
});
|
|
2932
|
+
continue;
|
|
2980
2933
|
}
|
|
2934
|
+
const names = namesOf(rule.names, value, covered.map(({ slot }) => slot));
|
|
2935
|
+
covered.forEach(({ index }, position) => {
|
|
2936
|
+
if (position > 0) sees[index]?.push(...names);
|
|
2937
|
+
else later[index]?.push(...names);
|
|
2938
|
+
});
|
|
2981
2939
|
}
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
reason
|
|
2940
|
+
return {
|
|
2941
|
+
sees,
|
|
2942
|
+
later
|
|
2986
2943
|
};
|
|
2987
2944
|
}
|
|
2945
|
+
// src/ladder.ts
|
|
2946
|
+
/** The rungs of the ladder, in the order that a question visits them. */
|
|
2947
|
+
const RUNGS = [
|
|
2948
|
+
"own",
|
|
2949
|
+
"kind",
|
|
2950
|
+
"default"
|
|
2951
|
+
];
|
|
2952
|
+
function entryOf$1(verbs, verb) {
|
|
2953
|
+
return verbs !== void 0 && Object.hasOwn(verbs, verb) ? verbs[verb] : void 0;
|
|
2954
|
+
}
|
|
2988
2955
|
/**
|
|
2989
|
-
* This function
|
|
2990
|
-
*
|
|
2991
|
-
* does not change a value.
|
|
2956
|
+
* This function finds the kind that a type names, and follows each alias. It gives `undefined` for an unknown
|
|
2957
|
+
* type.
|
|
2992
2958
|
*
|
|
2993
|
-
* @param
|
|
2994
|
-
* @param
|
|
2995
|
-
* @
|
|
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.
|
|
2959
|
+
* @param world - The world.
|
|
2960
|
+
* @param type - The reference to the type.
|
|
2961
|
+
* @returns The kind, or `undefined`.
|
|
2998
2962
|
*/
|
|
2999
|
-
function
|
|
3000
|
-
const
|
|
3001
|
-
|
|
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
|
-
};
|
|
2963
|
+
function kindOf(world, type) {
|
|
2964
|
+
const found = lookupKind(world, type);
|
|
2965
|
+
return found.ok ? found.kind : void 0;
|
|
3016
2966
|
}
|
|
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
2967
|
/**
|
|
3024
|
-
* This function
|
|
2968
|
+
* This function finds a kind by a text type. It is the same as `kindOf` for a one-key reference.
|
|
3025
2969
|
*
|
|
3026
|
-
* @param
|
|
3027
|
-
* @
|
|
2970
|
+
* @param world - The world.
|
|
2971
|
+
* @param name - The text of the type.
|
|
2972
|
+
* @returns The kind, or `undefined`.
|
|
3028
2973
|
*/
|
|
3029
|
-
function
|
|
3030
|
-
return
|
|
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;
|
|
2974
|
+
function kindNamed(world, name) {
|
|
2975
|
+
return kindOf(world, name);
|
|
3044
2976
|
}
|
|
3045
|
-
/**
|
|
3046
|
-
const
|
|
3047
|
-
const kindMemos = /* @__PURE__ */ new WeakMap();
|
|
2977
|
+
/** A test that passes each name. A rung of `answerOf` then answers with each entry that it has. */
|
|
2978
|
+
const EACH_NAME = () => true;
|
|
3048
2979
|
/**
|
|
3049
|
-
* This function
|
|
3050
|
-
*
|
|
3051
|
-
*
|
|
2980
|
+
* This function finds the evaluator of a verb without the record of the rungs. It visits the rungs of `ask` in the
|
|
2981
|
+
* same order: the own entry, then the kind, then the default of the world (VERB.LADDER). A plan without a trace,
|
|
2982
|
+
* `deref` and the walkers of steps use it, thus each verb has one ladder.
|
|
2983
|
+
*
|
|
2984
|
+
* @param world - The world, for its defaults.
|
|
2985
|
+
* @param own - The own entries of the document, when it has some.
|
|
2986
|
+
* @param kind - The kind of the document. `undefined` skips the kind rung, as for a value without a type. `null` is
|
|
2987
|
+
* a kind that the world does not have: the question stops there, as in `ask`.
|
|
2988
|
+
* @param verb - The verb, for example `eval`, `format`, `deref` or `step`.
|
|
2989
|
+
* @param has - The test of a name. A rung answers only with a name that passes it. The default passes each name.
|
|
2990
|
+
* @returns The evaluator name and its rung, or `undefined` when no rung answers.
|
|
3052
2991
|
*/
|
|
3053
|
-
function
|
|
3054
|
-
const
|
|
3055
|
-
if (
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
}
|
|
2992
|
+
function answerOf(world, own, kind, verb, has = EACH_NAME) {
|
|
2993
|
+
const ownName = entryOf$1(own, verb);
|
|
2994
|
+
if (ownName !== void 0 && has(ownName)) return {
|
|
2995
|
+
name: ownName,
|
|
2996
|
+
rung: "own"
|
|
2997
|
+
};
|
|
2998
|
+
if (kind === null) return void 0;
|
|
2999
|
+
const kindName = kind === void 0 ? void 0 : entryOf$1(kind.verbs, verb);
|
|
3000
|
+
if (kindName !== void 0 && has(kindName)) return {
|
|
3001
|
+
name: kindName,
|
|
3002
|
+
rung: "kind"
|
|
3003
|
+
};
|
|
3004
|
+
const fallback = entryOf$1(world.defaults, verb);
|
|
3005
|
+
return fallback !== void 0 && has(fallback) ? {
|
|
3006
|
+
name: fallback,
|
|
3007
|
+
rung: "default"
|
|
3008
|
+
} : void 0;
|
|
3009
|
+
}
|
|
3010
|
+
/**
|
|
3011
|
+
* This function asks a document a question, and gives the evaluator that answers it.
|
|
3012
|
+
*
|
|
3013
|
+
* The question visits the rungs in order: the own entry of the envelope, then its kind, then the default of the
|
|
3014
|
+
* world. The type comes from the envelope, or else from the type that the position declares. The type is a
|
|
3015
|
+
* reference into the world. The ladder does not guess a type from the shape of a value. Each verb has this ladder:
|
|
3016
|
+
* `eval`, `deref`, `step` and each verb of a language (VERB.LADDER).
|
|
3017
|
+
*
|
|
3018
|
+
* @param world - The kinds and the defaults.
|
|
3019
|
+
* @param doc - The header of the document: an envelope, or `{}` for a bare value.
|
|
3020
|
+
* @param verb - The verb of the question, for example `eval` or `view`.
|
|
3021
|
+
* @param options - The type that the position declares.
|
|
3022
|
+
* @returns The answer, with the record of each rung that the question visited.
|
|
3023
|
+
*/
|
|
3024
|
+
function ask(world, doc, verb, options = {}) {
|
|
3025
|
+
const steps = [];
|
|
3026
|
+
const own = entryOf$1(doc.own, verb);
|
|
3027
|
+
if (own !== void 0) {
|
|
3028
|
+
steps.push({
|
|
3029
|
+
rung: "own",
|
|
3030
|
+
outcome: "answers",
|
|
3031
|
+
evaluator: own
|
|
3032
|
+
});
|
|
3033
|
+
return {
|
|
3034
|
+
verb,
|
|
3035
|
+
evaluator: own,
|
|
3036
|
+
rung: "own",
|
|
3037
|
+
steps
|
|
3038
|
+
};
|
|
3039
|
+
}
|
|
3040
|
+
steps.push({
|
|
3041
|
+
rung: "own",
|
|
3042
|
+
outcome: "no-entry"
|
|
3043
|
+
});
|
|
3044
|
+
const type = doc.type ?? options.declaredType;
|
|
3045
|
+
if (type === void 0) steps.push({
|
|
3046
|
+
rung: "kind",
|
|
3047
|
+
outcome: "skipped"
|
|
3048
|
+
});
|
|
3049
|
+
else {
|
|
3050
|
+
const source = doc.type === void 0 ? "container" : "document";
|
|
3051
|
+
const name = typeName(type);
|
|
3052
|
+
const kind = kindOf(world, type);
|
|
3053
|
+
if (kind === void 0) {
|
|
3054
|
+
steps.push({
|
|
3055
|
+
rung: "kind",
|
|
3056
|
+
outcome: "unknown-kind",
|
|
3057
|
+
kind: name,
|
|
3058
|
+
source
|
|
3059
|
+
});
|
|
3060
|
+
return {
|
|
3061
|
+
verb,
|
|
3062
|
+
error: "unknown-kind",
|
|
3063
|
+
steps
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3066
|
+
const entry = entryOf$1(kind.verbs, verb);
|
|
3067
|
+
if (entry !== void 0) {
|
|
3068
|
+
steps.push({
|
|
3069
|
+
rung: "kind",
|
|
3070
|
+
outcome: "answers",
|
|
3071
|
+
evaluator: entry,
|
|
3072
|
+
kind: name,
|
|
3073
|
+
source
|
|
3074
|
+
});
|
|
3075
|
+
return {
|
|
3076
|
+
verb,
|
|
3077
|
+
evaluator: entry,
|
|
3078
|
+
rung: "kind",
|
|
3079
|
+
steps
|
|
3080
|
+
};
|
|
3081
|
+
}
|
|
3082
|
+
steps.push({
|
|
3083
|
+
rung: "kind",
|
|
3084
|
+
outcome: "no-entry",
|
|
3085
|
+
kind: name,
|
|
3086
|
+
source
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3089
|
+
const fallback = entryOf$1(world.defaults, verb);
|
|
3090
|
+
if (fallback !== void 0) {
|
|
3091
|
+
steps.push({
|
|
3092
|
+
rung: "default",
|
|
3093
|
+
outcome: "answers",
|
|
3094
|
+
evaluator: fallback
|
|
3095
|
+
});
|
|
3096
|
+
return {
|
|
3097
|
+
verb,
|
|
3098
|
+
evaluator: fallback,
|
|
3099
|
+
rung: "default",
|
|
3100
|
+
steps
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
steps.push({
|
|
3104
|
+
rung: "default",
|
|
3105
|
+
outcome: "no-entry"
|
|
3106
|
+
});
|
|
3107
|
+
return {
|
|
3108
|
+
verb,
|
|
3109
|
+
error: "no-answer",
|
|
3110
|
+
steps
|
|
3111
|
+
};
|
|
3112
|
+
}
|
|
3113
|
+
// src/deref.ts
|
|
3114
|
+
/**
|
|
3115
|
+
* The brand of a host thing: an object of the host that answers the steps of a path itself. The brand is a
|
|
3116
|
+
* global symbol, thus two copies of the kernel in one program know the things of each other.
|
|
3117
|
+
*/
|
|
3118
|
+
const THING = /* @__PURE__ */ Symbol.for("coeval.thing");
|
|
3119
|
+
/**
|
|
3120
|
+
* This function tells if a thing is a host thing.
|
|
3121
|
+
*
|
|
3122
|
+
* @param thing - The thing.
|
|
3123
|
+
* @returns `true` for a host thing.
|
|
3124
|
+
*/
|
|
3125
|
+
function isHostThing(thing) {
|
|
3126
|
+
return typeof thing === "object" && thing !== null && thing[THING] === true;
|
|
3127
|
+
}
|
|
3128
|
+
/** The roots of a context. Each path starts with one of them. */
|
|
3129
|
+
const ROOTS = [
|
|
3130
|
+
"self",
|
|
3131
|
+
"names",
|
|
3132
|
+
"world",
|
|
3133
|
+
"event",
|
|
3134
|
+
"caps"
|
|
3135
|
+
];
|
|
3136
|
+
/** This function gives the own entries of an envelope, when it has a record of them. */
|
|
3137
|
+
function ownEntries(envelope) {
|
|
3138
|
+
const own = field(envelope, "own");
|
|
3139
|
+
return isRecord(own) ? own : void 0;
|
|
3140
|
+
}
|
|
3141
|
+
/** The most kinds in the memo of one world. A larger memo starts again, thus the types of the data cannot fill the memory. */
|
|
3142
|
+
const MAX_KINDS = 1e3;
|
|
3143
|
+
const kindMemos = /* @__PURE__ */ new WeakMap();
|
|
3144
|
+
/**
|
|
3145
|
+
* This function gives the kind of a type for the ladder: `null` when the world does not have the kind. The result
|
|
3146
|
+
* depends only on the world and on the keys of the type, thus a memo for each world keeps it (PLAN.KIND-MEMO). A
|
|
3147
|
+
* world does not change after a plan or a resolution uses it, as for `worldThing`.
|
|
3148
|
+
*/
|
|
3149
|
+
function kindFor(world, type) {
|
|
3150
|
+
const keys = typeof type === "string" ? void 0 : typePath(type);
|
|
3151
|
+
if (typeof type !== "string" && (keys === void 0 || keys.length === 0)) {
|
|
3152
|
+
const found = lookupKind(world, type);
|
|
3153
|
+
return found.ok ? found.kind : null;
|
|
3154
|
+
}
|
|
3059
3155
|
let memo = kindMemos.get(world);
|
|
3060
3156
|
if (memo === void 0 || memo.size >= MAX_KINDS) {
|
|
3061
3157
|
memo = {
|
|
@@ -3089,877 +3185,477 @@ function nodeOf(first, keys) {
|
|
|
3089
3185
|
}
|
|
3090
3186
|
/** This function tells if a table of code has the name. An entry of a document can hold another value than a text. */
|
|
3091
3187
|
function codeIn(table, name) {
|
|
3092
|
-
return typeof name === "string" && Object.hasOwn(table, name);
|
|
3093
|
-
}
|
|
3094
|
-
/**
|
|
3095
|
-
* This function finds the walker of a step document through the ladder of the verb `step` (VERB.LADDER). The rungs
|
|
3096
|
-
* are the own entry, then the kind, then the default of the world. A rung answers only with a walker that the
|
|
3097
|
-
* navigator has. A resolution and `check` use this function, thus they agree on `#STEP?`.
|
|
3098
|
-
*
|
|
3099
|
-
* @param nav - The world and the walkers.
|
|
3100
|
-
* @param step - A step of a path that is not a key.
|
|
3101
|
-
* @returns The walker, or `undefined` when no rung answers.
|
|
3102
|
-
*/
|
|
3103
|
-
function walkerOf(nav, step) {
|
|
3104
|
-
const walkers = nav.walkers;
|
|
3105
|
-
if (walkers === void 0 || !isEnvelope(step)) return void 0;
|
|
3106
|
-
const answer = answerOf(nav.world, ownEntries(step), kindFor(nav.world, step.type), "step", (name) => codeIn(walkers, name));
|
|
3107
|
-
return answer === void 0 ? void 0 : walkers[answer.name];
|
|
3108
|
-
}
|
|
3109
|
-
/** The answer of `plainStep` for a field that the value does not have. A field can hold `undefined`. */
|
|
3110
|
-
const NOTHING = /* @__PURE__ */ Symbol("nothing");
|
|
3111
|
-
/** The own fields of a value: the items and the length of a list, and the own properties of an object. */
|
|
3112
|
-
function plainStep(thing, key) {
|
|
3113
|
-
if (Array.isArray(thing)) {
|
|
3114
|
-
if (key === "length") return thing.length;
|
|
3115
|
-
const index = typeof key === "number" ? key : /^\d+$/.test(key) ? Number(key) : -1;
|
|
3116
|
-
return index >= 0 && index < thing.length ? thing[index] : NOTHING;
|
|
3117
|
-
}
|
|
3118
|
-
if (typeof thing === "object" && thing !== null) {
|
|
3119
|
-
const name = String(key);
|
|
3120
|
-
return Object.hasOwn(thing, name) ? thing[name] : NOTHING;
|
|
3121
|
-
}
|
|
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);
|
|
3188
|
+
return typeof name === "string" && Object.hasOwn(table, name);
|
|
3554
3189
|
}
|
|
3555
3190
|
/**
|
|
3556
|
-
* This function
|
|
3191
|
+
* This function finds the walker of a step document through the ladder of the verb `step` (VERB.LADDER). The rungs
|
|
3192
|
+
* are the own entry, then the kind, then the default of the world. A rung answers only with a walker that the
|
|
3193
|
+
* navigator has. A resolution and `check` use this function, thus they agree on `#STEP?`.
|
|
3557
3194
|
*
|
|
3558
|
-
* @param
|
|
3559
|
-
* @
|
|
3195
|
+
* @param nav - The world and the walkers.
|
|
3196
|
+
* @param step - A step of a path that is not a key.
|
|
3197
|
+
* @returns The walker, or `undefined` when no rung answers.
|
|
3560
3198
|
*/
|
|
3561
|
-
function
|
|
3562
|
-
|
|
3199
|
+
function walkerOf(nav, step) {
|
|
3200
|
+
const walkers = nav.walkers;
|
|
3201
|
+
if (walkers === void 0 || !isEnvelope(step)) return void 0;
|
|
3202
|
+
const answer = answerOf(nav.world, ownEntries(step), kindFor(nav.world, step.type), "step", (name) => codeIn(walkers, name));
|
|
3203
|
+
return answer === void 0 ? void 0 : walkers[answer.name];
|
|
3563
3204
|
}
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3205
|
+
/** The answer of `plainStep` for a field that the value does not have. A field can hold `undefined`. */
|
|
3206
|
+
const NOTHING = /* @__PURE__ */ Symbol("nothing");
|
|
3207
|
+
/** The own fields of a value: the items and the length of a list, and the own properties of an object. */
|
|
3208
|
+
function plainStep(thing, key) {
|
|
3209
|
+
if (Array.isArray(thing)) {
|
|
3210
|
+
if (key === "length") return thing.length;
|
|
3211
|
+
const index = typeof key === "number" ? key : /^\d+$/.test(key) ? Number(key) : -1;
|
|
3212
|
+
return index >= 0 && index < thing.length ? thing[index] : NOTHING;
|
|
3213
|
+
}
|
|
3214
|
+
if (typeof thing === "object" && thing !== null) {
|
|
3215
|
+
const name = String(key);
|
|
3216
|
+
return Object.hasOwn(thing, name) ? thing[name] : NOTHING;
|
|
3217
|
+
}
|
|
3218
|
+
return NOTHING;
|
|
3567
3219
|
}
|
|
3568
3220
|
/**
|
|
3569
|
-
* This function
|
|
3570
|
-
*
|
|
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.
|
|
3573
|
-
*
|
|
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.
|
|
3221
|
+
* This function tells if a value can be an envelope by its field `type`. An envelope has its own field `type`, thus
|
|
3222
|
+
* a value without that field is not an envelope, and the full test is not necessary.
|
|
3577
3223
|
*/
|
|
3578
|
-
function
|
|
3579
|
-
|
|
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"
|
|
3590
|
-
};
|
|
3224
|
+
function mayBeEnvelope(thing) {
|
|
3225
|
+
return typeof thing === "object" && thing !== null && thing.type !== void 0;
|
|
3591
3226
|
}
|
|
3592
3227
|
/**
|
|
3593
|
-
* This function
|
|
3228
|
+
* This function answers one step of a path on a thing, through the ladder of the verb `deref`. A host thing
|
|
3229
|
+
* answers for itself (own). A document asks its own entry, then its kind, then the default of the world
|
|
3230
|
+
* (VERB.LADDER). A rung answers only with a `deref` that the navigator has. When no rung answers, the step goes into
|
|
3231
|
+
* 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
|
|
3232
|
+
* into it at once.
|
|
3594
3233
|
*
|
|
3595
|
-
* @param
|
|
3596
|
-
* @param
|
|
3597
|
-
* @
|
|
3234
|
+
* @param nav - The world and the code of the evaluators.
|
|
3235
|
+
* @param thing - The thing that the path reached.
|
|
3236
|
+
* @param key - The key of the step.
|
|
3237
|
+
* @returns What the step reaches and the rung that answered, or `undefined` when it reaches nothing.
|
|
3598
3238
|
*/
|
|
3599
|
-
function
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
constructor(reason, at) {
|
|
3607
|
-
this.reason = reason;
|
|
3608
|
-
this.at = at;
|
|
3239
|
+
function derefStep(nav, thing, key) {
|
|
3240
|
+
if (isHostThing(thing)) {
|
|
3241
|
+
const reached = thing.deref(key);
|
|
3242
|
+
return reached !== void 0 || thing.has?.(key) === true ? {
|
|
3243
|
+
thing: reached,
|
|
3244
|
+
by: "own"
|
|
3245
|
+
} : void 0;
|
|
3609
3246
|
}
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
}
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3247
|
+
if (nav.plain !== true && mayBeEnvelope(thing) && isEnvelope(thing)) {
|
|
3248
|
+
const envelope = thing;
|
|
3249
|
+
const derefs = nav.derefs;
|
|
3250
|
+
const answer = derefs === void 0 ? void 0 : answerOf(nav.world, ownEntries(envelope), kindFor(nav.world, envelope.type), "deref", (name) => codeIn(derefs, name));
|
|
3251
|
+
if (answer !== void 0) {
|
|
3252
|
+
const code = derefs[answer.name];
|
|
3253
|
+
const reached = code?.(envelope, key);
|
|
3254
|
+
return reached !== void 0 || code?.has?.(envelope, key) === true ? {
|
|
3255
|
+
thing: reached,
|
|
3256
|
+
by: answer.rung
|
|
3257
|
+
} : void 0;
|
|
3258
|
+
}
|
|
3259
|
+
const reached = plainStep(envelope.value, key);
|
|
3260
|
+
return reached === NOTHING ? void 0 : {
|
|
3261
|
+
thing: reached,
|
|
3262
|
+
by: "default"
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
const reached = plainStep(thing, key);
|
|
3266
|
+
return reached === NOTHING ? void 0 : {
|
|
3267
|
+
thing: reached,
|
|
3268
|
+
by: "default"
|
|
3631
3269
|
};
|
|
3632
3270
|
}
|
|
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);
|
|
3652
|
-
}
|
|
3653
3271
|
/**
|
|
3654
|
-
* This function
|
|
3655
|
-
* the static kit use the same split, thus each one sees the same parts.
|
|
3272
|
+
* This function tells if a thing is a reference document: an envelope of the type `ref` with a list for its path.
|
|
3656
3273
|
*
|
|
3657
|
-
* @param
|
|
3658
|
-
* @
|
|
3659
|
-
* @returns The parts and a way to fill their places, or the reason why the value does not have the shape.
|
|
3274
|
+
* @param thing - The thing.
|
|
3275
|
+
* @returns `true` for a reference document.
|
|
3660
3276
|
*/
|
|
3661
|
-
function
|
|
3662
|
-
if (
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3277
|
+
function isRef(thing) {
|
|
3278
|
+
if (typeof thing !== "object" || thing === null) return false;
|
|
3279
|
+
const type = thing.type;
|
|
3280
|
+
if (type === void 0 || typeof type === "string" && type !== "ref") return false;
|
|
3281
|
+
if (!isEnvelope(thing) || !Array.isArray(thing.value)) return false;
|
|
3282
|
+
const path = typePath(thing.type);
|
|
3283
|
+
return path !== void 0 && path.length === 1 && path[0] === "ref";
|
|
3284
|
+
}
|
|
3285
|
+
const worlds = /* @__PURE__ */ new WeakMap();
|
|
3286
|
+
/**
|
|
3287
|
+
* This function makes the thing of the root `world`: the entries of the world as JSON. An alias is a reference
|
|
3288
|
+
* document in it, thus a walk through the world follows each alias (collapse). The thing of a world is made one
|
|
3289
|
+
* time.
|
|
3290
|
+
*
|
|
3291
|
+
* @param world - The world.
|
|
3292
|
+
* @returns The thing.
|
|
3293
|
+
*/
|
|
3294
|
+
function worldThing(world) {
|
|
3295
|
+
let thing = worlds.get(world);
|
|
3296
|
+
if (thing === void 0) {
|
|
3297
|
+
thing = entriesAsJson(world.kinds);
|
|
3298
|
+
worlds.set(world, thing);
|
|
3299
|
+
}
|
|
3300
|
+
return thing;
|
|
3301
|
+
}
|
|
3302
|
+
/**
|
|
3303
|
+
* This function makes a context. The world comes from the navigator when the call gives none.
|
|
3304
|
+
*
|
|
3305
|
+
* @param parts - The roots to set.
|
|
3306
|
+
* @returns The context.
|
|
3307
|
+
*/
|
|
3308
|
+
function context(parts = {}) {
|
|
3309
|
+
return {
|
|
3310
|
+
self: parts.self ?? null,
|
|
3311
|
+
names: parts.names ?? {},
|
|
3312
|
+
world: parts.world ?? null,
|
|
3313
|
+
event: parts.event ?? null,
|
|
3314
|
+
caps: parts.caps ?? []
|
|
3315
|
+
};
|
|
3316
|
+
}
|
|
3317
|
+
const MAX_COLLAPSE$1 = 64;
|
|
3318
|
+
/** 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). */
|
|
3319
|
+
const CHAIN_REASON = "The path follows more than 64 references. One resolution follows at most 64.";
|
|
3320
|
+
const NO_HOPS$1 = /* @__PURE__ */ Object.freeze([]);
|
|
3321
|
+
/** A value that can be a reference document: a record with the type `ref`. The full check comes after. */
|
|
3322
|
+
function mayBeRef(thing) {
|
|
3323
|
+
return typeof thing === "object" && thing !== null && thing.type === "ref";
|
|
3324
|
+
}
|
|
3325
|
+
/** This function tells if each step of a path from an index is a key. */
|
|
3326
|
+
function keysFrom(path, start) {
|
|
3327
|
+
for (let index = start; index < path.length; index += 1) if (!isKey(path[index])) return false;
|
|
3328
|
+
return true;
|
|
3329
|
+
}
|
|
3330
|
+
/** This function tells if a root has a value of its own for the short path: each root except `caps`. */
|
|
3331
|
+
function quickRoot(root) {
|
|
3332
|
+
return root === "names" || root === "self" || root === "event" || root === "world";
|
|
3333
|
+
}
|
|
3334
|
+
/**
|
|
3335
|
+
* This function resolves the common path without a record of hops: a root, then keys. Plain values answer the
|
|
3336
|
+
* keys, or a host thing answers all of them in one call. It gives `undefined` when the path needs the full
|
|
3337
|
+
* algorithm. Examples are a host thing without `resolve`, an envelope, a reference to follow, a step document and a
|
|
3338
|
+
* failure of a step (for its exact reason).
|
|
3339
|
+
*/
|
|
3340
|
+
function resolveQuick(nav, ctx, path) {
|
|
3341
|
+
const root = path[0];
|
|
3342
|
+
if (!quickRoot(root)) return void 0;
|
|
3343
|
+
if (nav.roots !== void 0 && !nav.roots.includes(root)) return void 0;
|
|
3344
|
+
if (nav.adopt !== void 0) return void 0;
|
|
3345
|
+
return walkQuick(ctx[root], path, nav.plain === true, false);
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* This function walks the steps of the short path from the value of the root (DEREF.QUICK). `resolveQuick` and each
|
|
3349
|
+
* compiled path use it, thus the two cannot disagree. It gives `undefined` when the path needs the full algorithm.
|
|
3350
|
+
*
|
|
3351
|
+
* @param start - The value of the root.
|
|
3352
|
+
* @param path - The steps. The walk starts at the index 1.
|
|
3353
|
+
* @param plain - `true` for a plain navigation.
|
|
3354
|
+
* @param keyed - `true` when each step after the root is a key. The walk then does not test the steps again.
|
|
3355
|
+
*/
|
|
3356
|
+
function walkQuick(start, path, plain, keyed) {
|
|
3357
|
+
let here = start;
|
|
3358
|
+
for (let index = 1; index < path.length; index += 1) {
|
|
3359
|
+
if (typeof here !== "object" || here === null) return void 0;
|
|
3360
|
+
const type = plain ? void 0 : here.type;
|
|
3361
|
+
if (type === "ref") return void 0;
|
|
3362
|
+
if (here[THING] === true) {
|
|
3363
|
+
const thing = here;
|
|
3364
|
+
if (thing.resolve === void 0 || !(keyed || keysFrom(path, index))) return void 0;
|
|
3365
|
+
const keys = path.slice(index);
|
|
3366
|
+
const reached = thing.resolve(keys);
|
|
3367
|
+
if (reached === void 0) return {
|
|
3368
|
+
ok: false,
|
|
3369
|
+
code: "#N/A",
|
|
3370
|
+
reason: `The path ${keys.join(".")} reaches nothing.`,
|
|
3371
|
+
hops: NO_HOPS$1
|
|
3743
3372
|
};
|
|
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);
|
|
3373
|
+
if (!plain && mayBeRef(reached.thing)) return void 0;
|
|
3748
3374
|
return {
|
|
3749
|
-
|
|
3750
|
-
|
|
3375
|
+
ok: true,
|
|
3376
|
+
thing: reached.thing,
|
|
3377
|
+
hops: NO_HOPS$1
|
|
3751
3378
|
};
|
|
3752
3379
|
}
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
const fieldShape = Object.hasOwn(named, key) ? named[key] : spec.rest;
|
|
3759
|
-
fields.push([key, walk(fieldShape, item[key], [...path, key])]);
|
|
3380
|
+
const step = path[index];
|
|
3381
|
+
if (Array.isArray(here)) {
|
|
3382
|
+
if (typeof step !== "number" || !Number.isInteger(step) || step < 0 || step >= here.length) return void 0;
|
|
3383
|
+
here = here[step];
|
|
3384
|
+
continue;
|
|
3760
3385
|
}
|
|
3761
|
-
return
|
|
3762
|
-
|
|
3763
|
-
|
|
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;
|
|
3386
|
+
if (typeof step !== "string" || !Object.hasOwn(here, step)) return void 0;
|
|
3387
|
+
if (type !== void 0 && isEnvelope(here)) return void 0;
|
|
3388
|
+
here = here[step];
|
|
3776
3389
|
}
|
|
3777
|
-
|
|
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
|
-
};
|
|
3390
|
+
if (!plain && mayBeRef(here)) return void 0;
|
|
3796
3391
|
return {
|
|
3797
3392
|
ok: true,
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
fill: (handles) => fillWith(template, handles)
|
|
3393
|
+
thing: here,
|
|
3394
|
+
hops: NO_HOPS$1
|
|
3801
3395
|
};
|
|
3802
3396
|
}
|
|
3397
|
+
/** The root whose value starts the short path of a compiled path. `FULL` takes the full algorithm at once. */
|
|
3398
|
+
const FULL = 0;
|
|
3399
|
+
const FROM_NAMES = 1;
|
|
3400
|
+
const FROM_SELF = 2;
|
|
3401
|
+
const FROM_EVENT = 3;
|
|
3402
|
+
const FROM_WORLD = 4;
|
|
3803
3403
|
/**
|
|
3804
|
-
*
|
|
3805
|
-
*
|
|
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.
|
|
3404
|
+
* A compiled path as an object with fields (PLAN.LEAN). The code of `resolve` is on the class, thus each compiled path
|
|
3405
|
+
* keeps only its fields and makes no closure.
|
|
3812
3406
|
*/
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
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
|
|
3407
|
+
var StaticPath = class {
|
|
3408
|
+
constructor(path, nav, known, from, plain) {
|
|
3409
|
+
this.path = path;
|
|
3410
|
+
this.nav = nav;
|
|
3411
|
+
this.known = known;
|
|
3412
|
+
this.from = from;
|
|
3413
|
+
this.plain = plain;
|
|
3414
|
+
}
|
|
3415
|
+
resolve(ctx) {
|
|
3416
|
+
const from = this.from;
|
|
3417
|
+
if (from !== FULL) {
|
|
3418
|
+
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);
|
|
3419
|
+
if (quick !== void 0) return quick;
|
|
3848
3420
|
}
|
|
3849
|
-
|
|
3421
|
+
return resolveFully$1(this.nav, ctx, this.path, void 0, this.known);
|
|
3422
|
+
}
|
|
3423
|
+
};
|
|
3424
|
+
/**
|
|
3425
|
+
* This function compiles one static path for one navigator. The resolver gives the same thing, error and reason as
|
|
3426
|
+
* `resolve` without hops (PLAN.PATH-SAME). It keeps no value of a context.
|
|
3427
|
+
*
|
|
3428
|
+
* - Some paths take the full algorithm at once, because the short path cannot answer them. A path from `caps` or from
|
|
3429
|
+
* a closed root is one. A path with a step document and each path of a navigator with `adopt` are others.
|
|
3430
|
+
* - Each other path walks the short path from its root, and it takes the full algorithm when the values need it.
|
|
3431
|
+
* - The walker of each step document comes from the ladder one time, here. The navigator and the step document do
|
|
3432
|
+
* not change, thus the answer does not change either.
|
|
3433
|
+
*
|
|
3434
|
+
* An evaluator of a language calls this function in its `compile`, with the field `machine` of the input, and reads the
|
|
3435
|
+
* result with `resolveCompiled` (PLAN.PATH-EXPORT).
|
|
3436
|
+
*
|
|
3437
|
+
* @param nav - The navigator. A plan compiles its paths for its machine.
|
|
3438
|
+
* @param path - The steps. The first step is a root. The compiled path keeps this list, thus the host must not change it.
|
|
3439
|
+
* @returns The compiled path.
|
|
3440
|
+
*/
|
|
3441
|
+
function compilePath(nav, path) {
|
|
3442
|
+
const keyed = keysFrom(path, 1);
|
|
3443
|
+
return new StaticPath(path, nav, keyed ? void 0 : walkersOf(nav, path), startOf(nav, path, keyed), nav.plain === true);
|
|
3444
|
+
}
|
|
3445
|
+
/** This function gives the root that starts the short path of a compiled path, or `FULL`. */
|
|
3446
|
+
function startOf(nav, path, keyed) {
|
|
3447
|
+
const root = path[0];
|
|
3448
|
+
if (!keyed || !quickRoot(root) || nav.adopt !== void 0) return FULL;
|
|
3449
|
+
if (nav.roots !== void 0 && !nav.roots.includes(root)) return FULL;
|
|
3450
|
+
return root === "names" ? FROM_NAMES : root === "self" ? FROM_SELF : root === "event" ? FROM_EVENT : FROM_WORLD;
|
|
3451
|
+
}
|
|
3452
|
+
/**
|
|
3453
|
+
* This function asks the ladder of the verb `step` for each step document of a path. A step whose lookup throws
|
|
3454
|
+
* stays unknown, thus the full algorithm asks the ladder again for it.
|
|
3455
|
+
*/
|
|
3456
|
+
function walkersOf(nav, path) {
|
|
3457
|
+
if (nav.walkers === void 0) return void 0;
|
|
3458
|
+
const out = new Array(path.length);
|
|
3459
|
+
for (let index = 1; index < path.length; index += 1) {
|
|
3460
|
+
const step = path[index];
|
|
3461
|
+
if (isKey(step)) continue;
|
|
3462
|
+
try {
|
|
3463
|
+
out[index] = walkerOf(nav, step) ?? null;
|
|
3464
|
+
} catch {}
|
|
3465
|
+
}
|
|
3466
|
+
return out;
|
|
3850
3467
|
}
|
|
3851
3468
|
/**
|
|
3852
|
-
* This function
|
|
3853
|
-
* each key.
|
|
3469
|
+
* This function resolves a path from a context, and records each hop.
|
|
3854
3470
|
*
|
|
3855
|
-
*
|
|
3856
|
-
*
|
|
3857
|
-
*
|
|
3471
|
+
* 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
|
|
3472
|
+
* of the verb `deref` on the thing that the path reached. A step document is evaluated by the walker that the
|
|
3473
|
+
* ladder of the verb `step` gives, with the thing that the path reached. After each hop, a reference document is
|
|
3474
|
+
* followed until the path reaches something else (collapse), except in a plain navigation.
|
|
3475
|
+
*
|
|
3476
|
+
* The codes of a failure:
|
|
3477
|
+
*
|
|
3478
|
+
* - `#REF!`: the path has no root, or a root that is not open here.
|
|
3479
|
+
* - `#NAME?`: the root `names` has no such name.
|
|
3480
|
+
* - `#N/A`: a step reaches nothing.
|
|
3481
|
+
* - `#STEP?`: a step is not a key and not a step document.
|
|
3482
|
+
* - `#CYCLE!`: the references form a cycle, or the resolution follows more than 64 references. The reason tells
|
|
3483
|
+
* which (DEREF.CHAIN-REASON).
|
|
3484
|
+
*
|
|
3485
|
+
* @param nav - The world and the code of the evaluators.
|
|
3486
|
+
* @param ctx - The context.
|
|
3487
|
+
* @param path - The steps.
|
|
3488
|
+
* @param options - `hops: false` does not record the hops.
|
|
3489
|
+
* @returns What the path reached and each hop, or an error.
|
|
3858
3490
|
*/
|
|
3859
|
-
function
|
|
3860
|
-
if (
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
if (want !== "*" && String(want) !== String(path[index])) return false;
|
|
3491
|
+
function resolve(nav, ctx, path, options = {}) {
|
|
3492
|
+
if (options.hops === false) {
|
|
3493
|
+
const quick = resolveQuick(nav, ctx, path);
|
|
3494
|
+
if (quick !== void 0) return quick;
|
|
3864
3495
|
}
|
|
3865
|
-
return
|
|
3496
|
+
return resolveFully$1(nav, ctx, path, options.hops === false ? void 0 : [], void 0);
|
|
3866
3497
|
}
|
|
3498
|
+
/** The functions of the last navigator that gave a walker its input. A walk with the same navigator makes no new functions. */
|
|
3499
|
+
let lastSteps;
|
|
3867
3500
|
/**
|
|
3868
|
-
* This function
|
|
3869
|
-
*
|
|
3870
|
-
*
|
|
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.
|
|
3501
|
+
* This function gives the functions `deref` and `has` of the input of a walker. They depend only on the navigator,
|
|
3502
|
+
* thus the function keeps the functions of the last navigator (K170).
|
|
3876
3503
|
*/
|
|
3877
|
-
function
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
}
|
|
3890
|
-
count += 1;
|
|
3891
|
-
}
|
|
3892
|
-
}
|
|
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;
|
|
3904
|
-
}
|
|
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);
|
|
3504
|
+
function walkSteps(nav) {
|
|
3505
|
+
if (lastSteps !== void 0 && lastSteps.nav === nav) return lastSteps;
|
|
3506
|
+
const adopt = nav.adopt;
|
|
3507
|
+
lastSteps = {
|
|
3508
|
+
nav,
|
|
3509
|
+
deref: adopt === void 0 ? (thing, key) => derefStep(nav, thing, key)?.thing : (thing, key) => {
|
|
3510
|
+
const reached = derefStep(nav, thing, key);
|
|
3511
|
+
return reached === void 0 ? void 0 : adopt(reached.thing);
|
|
3512
|
+
},
|
|
3513
|
+
has: (thing, key) => derefStep(nav, thing, key) !== void 0
|
|
3514
|
+
};
|
|
3515
|
+
return lastSteps;
|
|
3921
3516
|
}
|
|
3922
3517
|
/**
|
|
3923
|
-
* This function
|
|
3924
|
-
* see. `check`, `conforms` and the plan read the scope rules with it.
|
|
3518
|
+
* This function resolves a path with the full algorithm of `resolve`.
|
|
3925
3519
|
*
|
|
3926
|
-
* @param
|
|
3927
|
-
* @param
|
|
3928
|
-
* @param
|
|
3929
|
-
* @
|
|
3520
|
+
* @param nav - The world and the code of the evaluators.
|
|
3521
|
+
* @param ctx - The context.
|
|
3522
|
+
* @param path - The steps.
|
|
3523
|
+
* @param hops - The list that gets each hop, or `undefined` for no record.
|
|
3524
|
+
* @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.
|
|
3525
|
+
* @returns What the path reached and each hop, or an error.
|
|
3930
3526
|
*/
|
|
3931
|
-
function
|
|
3932
|
-
const
|
|
3933
|
-
const
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
if (
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3527
|
+
function resolveFully$1(nav, ctx, path, hops, known) {
|
|
3528
|
+
const done = hops ?? NO_HOPS$1;
|
|
3529
|
+
const failed = (code, reason) => ({
|
|
3530
|
+
ok: false,
|
|
3531
|
+
code,
|
|
3532
|
+
reason,
|
|
3533
|
+
hops: done
|
|
3534
|
+
});
|
|
3535
|
+
let collapses = 0;
|
|
3536
|
+
let open;
|
|
3537
|
+
const adopt = nav.adopt ?? ((value) => value);
|
|
3538
|
+
const collapse = (thing) => {
|
|
3539
|
+
let here = thing;
|
|
3540
|
+
if (nav.plain === true) return {
|
|
3541
|
+
ok: true,
|
|
3542
|
+
thing: here,
|
|
3543
|
+
hops: done
|
|
3544
|
+
};
|
|
3545
|
+
while (isRef(here)) {
|
|
3546
|
+
if (open?.includes(here) === true) return failed("#CYCLE!", "The references form a cycle.");
|
|
3547
|
+
collapses += 1;
|
|
3548
|
+
if (collapses > MAX_COLLAPSE$1) return failed("#CYCLE!", CHAIN_REASON);
|
|
3549
|
+
open ??= [];
|
|
3550
|
+
open.push(here);
|
|
3551
|
+
const inner = walk(here.value, void 0);
|
|
3552
|
+
open.pop();
|
|
3553
|
+
if (!inner.ok) return inner;
|
|
3554
|
+
here = adopt(inner.thing);
|
|
3555
|
+
hops?.push({
|
|
3556
|
+
step: "collapse",
|
|
3557
|
+
thing: here,
|
|
3558
|
+
by: "collapse"
|
|
3950
3559
|
});
|
|
3951
|
-
continue;
|
|
3952
3560
|
}
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3561
|
+
return {
|
|
3562
|
+
ok: true,
|
|
3563
|
+
thing: here,
|
|
3564
|
+
hops: done
|
|
3565
|
+
};
|
|
3566
|
+
};
|
|
3567
|
+
const walk = (steps, walkers) => {
|
|
3568
|
+
const root = steps[0];
|
|
3569
|
+
if (typeof root !== "string" || !ROOTS.includes(root)) return failed("#REF!", `A path starts with a root: ${ROOTS.join(", ")}.`);
|
|
3570
|
+
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(", ")}.`);
|
|
3571
|
+
let here = adopt(ctx[root]);
|
|
3572
|
+
hops?.push({
|
|
3573
|
+
step: root,
|
|
3574
|
+
thing: here,
|
|
3575
|
+
by: "root"
|
|
3957
3576
|
});
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3577
|
+
const first = collapse(here);
|
|
3578
|
+
if (!first.ok) return first;
|
|
3579
|
+
here = first.thing;
|
|
3580
|
+
for (let index = 1; index < steps.length; index += 1) {
|
|
3581
|
+
const step = steps[index];
|
|
3582
|
+
if (isHostThing(here) && here.resolve !== void 0 && keysFrom(steps, index)) {
|
|
3583
|
+
const keys = steps.slice(index);
|
|
3584
|
+
const reached = here.resolve(keys);
|
|
3585
|
+
if (reached === void 0) return failed("#N/A", `The path ${keys.join(".")} reaches nothing.`);
|
|
3586
|
+
const thing = adopt(reached.thing);
|
|
3587
|
+
hops?.push({
|
|
3588
|
+
step: keys,
|
|
3589
|
+
thing,
|
|
3590
|
+
by: "own"
|
|
3591
|
+
});
|
|
3592
|
+
return collapse(thing);
|
|
3593
|
+
}
|
|
3594
|
+
if (isKey(step)) {
|
|
3595
|
+
const reached = derefStep(nav, here, step);
|
|
3596
|
+
if (reached === void 0) {
|
|
3597
|
+
if (root === "names" && index === 1) return failed("#NAME?", `The context has no name ${String(step)}.`);
|
|
3598
|
+
return failed("#N/A", `The step ${String(step)} reaches nothing.`);
|
|
3599
|
+
}
|
|
3600
|
+
here = adopt(reached.thing);
|
|
3601
|
+
hops?.push({
|
|
3602
|
+
step,
|
|
3603
|
+
thing: here,
|
|
3604
|
+
by: reached.by
|
|
3605
|
+
});
|
|
3606
|
+
} else {
|
|
3607
|
+
const given = walkers?.[index];
|
|
3608
|
+
const walker = given === void 0 ? walkerOf(nav, step) : given ?? void 0;
|
|
3609
|
+
if (walker === void 0) return failed("#STEP?", "A step is a key, or a document of a kind with the verb step.");
|
|
3610
|
+
const envelope = step;
|
|
3611
|
+
const { deref, has } = walkSteps(nav);
|
|
3612
|
+
const result = walker(hops === void 0 ? {
|
|
3613
|
+
data: envelope.value,
|
|
3614
|
+
here,
|
|
3615
|
+
context: ctx,
|
|
3616
|
+
deref,
|
|
3617
|
+
has
|
|
3618
|
+
} : {
|
|
3619
|
+
data: envelope.value,
|
|
3620
|
+
here,
|
|
3621
|
+
context: ctx,
|
|
3622
|
+
deref,
|
|
3623
|
+
has,
|
|
3624
|
+
visit: (key, thing) => hops.push({
|
|
3625
|
+
step: key,
|
|
3626
|
+
thing,
|
|
3627
|
+
by: "step"
|
|
3628
|
+
})
|
|
3629
|
+
});
|
|
3630
|
+
if (!result.ok) return failed(result.code ?? "#N/A", result.reason);
|
|
3631
|
+
here = adopt(result.thing);
|
|
3632
|
+
hops?.push({
|
|
3633
|
+
step: envelope,
|
|
3634
|
+
thing: here,
|
|
3635
|
+
by: "step"
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3638
|
+
const next = collapse(here);
|
|
3639
|
+
if (!next.ok) return next;
|
|
3640
|
+
here = next.thing;
|
|
3641
|
+
}
|
|
3642
|
+
return {
|
|
3643
|
+
ok: true,
|
|
3644
|
+
thing: here,
|
|
3645
|
+
hops: done
|
|
3646
|
+
};
|
|
3962
3647
|
};
|
|
3648
|
+
if (path.length === 0) return failed("#REF!", "A path has at least one step: its root.");
|
|
3649
|
+
return walk(path, known);
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* This function gives the value of a thing: the value that a host thing gives, or else the thing itself.
|
|
3653
|
+
*
|
|
3654
|
+
* @param thing - The thing.
|
|
3655
|
+
* @returns The value.
|
|
3656
|
+
*/
|
|
3657
|
+
function valueOfThing(thing) {
|
|
3658
|
+
return isHostThing(thing) ? thing.toJson() : thing;
|
|
3963
3659
|
}
|
|
3964
3660
|
// src/evaluate.ts
|
|
3965
3661
|
/**
|
|
@@ -4519,14 +4215,14 @@ var Session = class {
|
|
|
4519
4215
|
/**
|
|
4520
4216
|
* This function adds work to the count of the evaluation (WORK.LIMIT). One count is on the runtime of the root, thus
|
|
4521
4217
|
* each equation of a tree adds to it. After the end of the evaluation, each entry from the host starts a new count
|
|
4522
|
-
* (WORK.AFTER).
|
|
4218
|
+
* (WORK.AFTER). An entry is a point with no application of a closure that runs, on any runtime of the evaluation.
|
|
4523
4219
|
*
|
|
4524
4220
|
* @param points - The work.
|
|
4525
4221
|
* @throws {Failure} The error `#WORK!`, when the count is over the limit of the machine.
|
|
4526
4222
|
*/
|
|
4527
4223
|
spend(points) {
|
|
4528
4224
|
const root = this.top ?? this;
|
|
4529
|
-
const work = (root.top === root && (
|
|
4225
|
+
const work = (root.top === root && (root.active ?? 0) === 0 ? 0 : root.work ?? 0) + points;
|
|
4530
4226
|
root.work = work;
|
|
4531
4227
|
const limit = this.machine.maxWork ?? 2e5;
|
|
4532
4228
|
if (work > limit) throw new Failure(workFailure(limit));
|
|
@@ -5905,104 +5601,447 @@ function record(s, result) {
|
|
|
5905
5601
|
};
|
|
5906
5602
|
}
|
|
5907
5603
|
/**
|
|
5908
|
-
* This function evaluates a document, and records each evaluation in a trace.
|
|
5909
|
-
*
|
|
5910
|
-
* The verb of the options goes up the ladder for each document. The default verb is `eval`. The kind of the document
|
|
5911
|
-
* tells where its parts are. The evaluator gets each part sealed: it can evaluate the part, and it cannot read its
|
|
5912
|
-
* value.
|
|
5913
|
-
*
|
|
5914
|
-
* A failure gives an error value, and the function does not throw. The function records each effect in its order,
|
|
5915
|
-
* and the host does not do it. A mock can answer each effect at once (RUN.MOCK).
|
|
5604
|
+
* This function evaluates a document, and records each evaluation in a trace.
|
|
5605
|
+
*
|
|
5606
|
+
* The verb of the options goes up the ladder for each document. The default verb is `eval`. The kind of the document
|
|
5607
|
+
* tells where its parts are. The evaluator gets each part sealed: it can evaluate the part, and it cannot read its
|
|
5608
|
+
* value.
|
|
5609
|
+
*
|
|
5610
|
+
* A failure gives an error value, and the function does not throw. The function records each effect in its order,
|
|
5611
|
+
* and the host does not do it. A mock can answer each effect at once (RUN.MOCK).
|
|
5612
|
+
*
|
|
5613
|
+
* @param machine - The world and the code of the evaluators.
|
|
5614
|
+
* @param doc - The document, as JSON.
|
|
5615
|
+
* @param context - The names and the capabilities at the root.
|
|
5616
|
+
* @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.
|
|
5617
|
+
* @returns The result, the trace and the effects in their order.
|
|
5618
|
+
*/
|
|
5619
|
+
function evaluate(machine, doc, context = makeContext(), options) {
|
|
5620
|
+
const given = typeof options === "string" ? { declaredType: options } : options ?? {};
|
|
5621
|
+
const declaredType = given.declaredType;
|
|
5622
|
+
const plan = prepare(machine, doc, {
|
|
5623
|
+
trace: true,
|
|
5624
|
+
...declaredType === void 0 ? {} : { declaredType },
|
|
5625
|
+
...given.verb === void 0 ? {} : { verb: given.verb },
|
|
5626
|
+
...given.guards === void 0 ? {} : { guards: given.guards }
|
|
5627
|
+
});
|
|
5628
|
+
const ctx = rootContext(machine, context);
|
|
5629
|
+
const s = new Session(machine, ctx.caps, false, true, given.perform, void 0, void 0, readingOf(given.reads, ctx));
|
|
5630
|
+
return record(s, plan.code(ctx, s));
|
|
5631
|
+
}
|
|
5632
|
+
/**
|
|
5633
|
+
* This function runs a document: an evaluation in which the host does each effect. A runner waits for its
|
|
5634
|
+
* parts and for its effects, thus a step can read the result of the step before. The part of the run before the
|
|
5635
|
+
* first wait happens at once, in the call. The run records a trace.
|
|
5636
|
+
*
|
|
5637
|
+
* @param machine - The world, the evaluators and the runners.
|
|
5638
|
+
* @param doc - The document, as JSON.
|
|
5639
|
+
* @param context - The names and the capabilities at the root.
|
|
5640
|
+
* @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.
|
|
5641
|
+
* @returns The result, the trace and the effects in their order, when the run ends.
|
|
5642
|
+
*/
|
|
5643
|
+
async function run(machine, doc, context = makeContext(), options = {}) {
|
|
5644
|
+
const plan = prepare(machine, doc, {
|
|
5645
|
+
trace: true,
|
|
5646
|
+
...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
|
|
5647
|
+
...options.guards === void 0 ? {} : { guards: options.guards },
|
|
5648
|
+
...options.verb === void 0 ? {} : { verb: options.verb }
|
|
5649
|
+
});
|
|
5650
|
+
const ctx = rootContext(machine, context);
|
|
5651
|
+
const s = new Session(machine, ctx.caps, true, true, options.perform, void 0, void 0, readingOf(options.reads, ctx));
|
|
5652
|
+
const result = await driveWaiting(plan.runCode()(ctx, s), options.signal);
|
|
5653
|
+
s.top = s;
|
|
5654
|
+
return record(s, result);
|
|
5655
|
+
}
|
|
5656
|
+
/**
|
|
5657
|
+
* This function finds a node of a trace by its path.
|
|
5658
|
+
*
|
|
5659
|
+
* @param trace - The root of the trace.
|
|
5660
|
+
* @param path - The keys from the root.
|
|
5661
|
+
* @returns The first evaluation at that path, or `undefined` when the document did not evaluate.
|
|
5662
|
+
*/
|
|
5663
|
+
function nodeAt(trace, path) {
|
|
5664
|
+
const want = path.map(String);
|
|
5665
|
+
let node = trace;
|
|
5666
|
+
let at = 0;
|
|
5667
|
+
while (node !== void 0 && at < want.length) {
|
|
5668
|
+
const here = node;
|
|
5669
|
+
node = here.children.find((child) => {
|
|
5670
|
+
const tail = child.path.slice(here.path.length);
|
|
5671
|
+
return tail.length > 0 && tail.every((key, index) => key === want[at + index]);
|
|
5672
|
+
});
|
|
5673
|
+
if (node !== void 0) at += node.path.length - here.path.length;
|
|
5674
|
+
}
|
|
5675
|
+
return node;
|
|
5676
|
+
}
|
|
5677
|
+
/**
|
|
5678
|
+
* This function lists the nodes of a trace in the order of their start.
|
|
5679
|
+
*
|
|
5680
|
+
* @param trace - The root of the trace.
|
|
5681
|
+
* @returns Each node, the root first.
|
|
5682
|
+
*/
|
|
5683
|
+
function flatten(trace) {
|
|
5684
|
+
const out = [];
|
|
5685
|
+
const stack = [trace];
|
|
5686
|
+
while (stack.length > 0) {
|
|
5687
|
+
const node = stack.pop();
|
|
5688
|
+
out.push(node);
|
|
5689
|
+
for (let index = node.children.length - 1; index >= 0; index -= 1) stack.push(node.children[index]);
|
|
5690
|
+
}
|
|
5691
|
+
return out.sort((a, b) => a.enter - b.enter);
|
|
5692
|
+
}
|
|
5693
|
+
/**
|
|
5694
|
+
* This function lists the errors of a trace: each node whose result is an error and whose parts did not fail
|
|
5695
|
+
* the same way. These nodes are where each error started.
|
|
5696
|
+
*
|
|
5697
|
+
* @param trace - The root of the trace.
|
|
5698
|
+
* @returns The errors, in the order of their start.
|
|
5699
|
+
*/
|
|
5700
|
+
function failures(trace) {
|
|
5701
|
+
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);
|
|
5702
|
+
}
|
|
5703
|
+
// src/language.ts
|
|
5704
|
+
const VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
5705
|
+
function numbers$1(version) {
|
|
5706
|
+
const found = VERSION.exec(version);
|
|
5707
|
+
if (found === null) throw new TypeError(`A language version has the form MAJOR.MINOR.PATCH. The text ${JSON.stringify(version)} does not.`);
|
|
5708
|
+
return [
|
|
5709
|
+
Number(found[1]),
|
|
5710
|
+
Number(found[2]),
|
|
5711
|
+
Number(found[3])
|
|
5712
|
+
];
|
|
5713
|
+
}
|
|
5714
|
+
/**
|
|
5715
|
+
* This function tells if a version satisfies a lowest version, by the rules of a caret range of SemVer. The first
|
|
5716
|
+
* number that is not zero stays the same, and the version is not lower.
|
|
5717
|
+
*/
|
|
5718
|
+
function compatible(version, lowest) {
|
|
5719
|
+
const have = numbers$1(version);
|
|
5720
|
+
const want = numbers$1(lowest);
|
|
5721
|
+
const stable = want.findIndex((part) => part !== 0);
|
|
5722
|
+
const fixed = stable < 0 ? 3 : stable + 1;
|
|
5723
|
+
for (let index = 0; index < 3; index += 1) {
|
|
5724
|
+
const [a, b] = [have[index], want[index]];
|
|
5725
|
+
if (a !== b) return index >= fixed && a > b;
|
|
5726
|
+
}
|
|
5727
|
+
return true;
|
|
5728
|
+
}
|
|
5729
|
+
/** This function gives the JSON text of a value with its keys in order. A value that is not JSON is an error. */
|
|
5730
|
+
function canonical(value, path) {
|
|
5731
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
|
|
5732
|
+
if (typeof value === "number" && Number.isFinite(value)) return JSON.stringify(value);
|
|
5733
|
+
if (Array.isArray(value)) return `[${value.map((item, index) => canonical(item, [...path, index])).join(",")}]`;
|
|
5734
|
+
if (!isRecord(value)) throw new TypeError(`The data half of a language is JSON. The value at ${JSON.stringify(path)} is not.`);
|
|
5735
|
+
return `{${Object.keys(value).filter((key) => value[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonical(value[key], [...path, key])}`).join(",")}}`;
|
|
5736
|
+
}
|
|
5737
|
+
function frozen(value) {
|
|
5738
|
+
if (typeof value !== "object" || value === null) return value;
|
|
5739
|
+
for (const item of Object.values(value)) frozen(item);
|
|
5740
|
+
return Object.freeze(value);
|
|
5741
|
+
}
|
|
5742
|
+
/**
|
|
5743
|
+
* This function makes one value of a language. The data half is JSON, thus a host can store it and compare it. The
|
|
5744
|
+
* code half binds the evaluator names of the world.
|
|
5745
|
+
*
|
|
5746
|
+
* The language keeps a frozen copy of its data half, thus a later change to the input changes nothing.
|
|
5747
|
+
*
|
|
5748
|
+
* @param definition - The name, the version, the world, the needed languages and the code.
|
|
5749
|
+
* @returns The language.
|
|
5750
|
+
* @throws {TypeError} A version in the definition is not `MAJOR.MINOR.PATCH`, the name is empty, or the
|
|
5751
|
+
* data half is not JSON.
|
|
5752
|
+
*/
|
|
5753
|
+
function defineLanguage(definition) {
|
|
5754
|
+
if (definition.name === "") throw new TypeError("A language has a name.");
|
|
5755
|
+
numbers$1(definition.version);
|
|
5756
|
+
const requires = definition.requires ?? {};
|
|
5757
|
+
for (const name of Object.keys(requires)) numbers$1(requires[name]);
|
|
5758
|
+
const data = canonical({
|
|
5759
|
+
requires,
|
|
5760
|
+
world: definition.world ?? {}
|
|
5761
|
+
}, []);
|
|
5762
|
+
const copy = frozen(JSON.parse(data));
|
|
5763
|
+
const language = {
|
|
5764
|
+
name: definition.name,
|
|
5765
|
+
version: definition.version,
|
|
5766
|
+
world: copy.world,
|
|
5767
|
+
requires: copy.requires,
|
|
5768
|
+
data
|
|
5769
|
+
};
|
|
5770
|
+
return Object.freeze(definition.code === void 0 ? language : {
|
|
5771
|
+
...language,
|
|
5772
|
+
code: definition.code
|
|
5773
|
+
});
|
|
5774
|
+
}
|
|
5775
|
+
function partOf(language) {
|
|
5776
|
+
const { code, world } = language;
|
|
5777
|
+
return typeof code === "function" ? (prev) => ({
|
|
5778
|
+
...code(prev),
|
|
5779
|
+
world
|
|
5780
|
+
}) : {
|
|
5781
|
+
...code,
|
|
5782
|
+
world
|
|
5783
|
+
};
|
|
5784
|
+
}
|
|
5785
|
+
/**
|
|
5786
|
+
* This function merges languages into one machine, in the order of the arguments, with `mergeMachines`.
|
|
5787
|
+
*
|
|
5788
|
+
* - A language comes after each language that it names in `requires`, at a compatible version (LANG.REQUIRES).
|
|
5789
|
+
* - One language that comes twice counts once. Thus two languages can share a base.
|
|
5790
|
+
* - Two versions of one name, or two data halves under one name and one version, are conflicts (LANG.COMPOSE).
|
|
5791
|
+
*
|
|
5792
|
+
* @param languages - The languages.
|
|
5793
|
+
* @returns The machine.
|
|
5794
|
+
* @throws {MergeError} The languages do not fit, or their merge has a conflict. The error lists each conflict.
|
|
5795
|
+
*/
|
|
5796
|
+
function compose(...languages) {
|
|
5797
|
+
const conflicts = [];
|
|
5798
|
+
const parts = [];
|
|
5799
|
+
const seen = /* @__PURE__ */ new Map();
|
|
5800
|
+
languages.forEach((language, index) => {
|
|
5801
|
+
const earlier = seen.get(language.name);
|
|
5802
|
+
const conflict = (name, other, reason) => {
|
|
5803
|
+
conflicts.push({
|
|
5804
|
+
path: ["languages", name],
|
|
5805
|
+
parts: [Math.min(other, index), Math.max(other, index)],
|
|
5806
|
+
reason
|
|
5807
|
+
});
|
|
5808
|
+
};
|
|
5809
|
+
if (earlier !== void 0) {
|
|
5810
|
+
if (earlier.language.version !== language.version) conflict(language.name, earlier.index, "Two versions of one language.");
|
|
5811
|
+
else if (earlier.language.data !== language.data) conflict(language.name, earlier.index, "Two languages with one name and one version differ.");
|
|
5812
|
+
else if (earlier.language.code !== language.code) parts.push(partOf(language));
|
|
5813
|
+
return;
|
|
5814
|
+
}
|
|
5815
|
+
for (const name of Object.keys(language.requires)) {
|
|
5816
|
+
const needed = language.requires[name];
|
|
5817
|
+
const found = seen.get(name);
|
|
5818
|
+
if (found === void 0) {
|
|
5819
|
+
const later = languages.findIndex((other) => other.name === name);
|
|
5820
|
+
if (later < 0) conflict(name, index, `A language requires ${name}, and the composition does not have it.`);
|
|
5821
|
+
else conflict(name, later, `A language requires ${name}, and ${name} comes after it.`);
|
|
5822
|
+
} else if (!compatible(found.language.version, needed)) conflict(name, found.index, `A language requires ${name} ${needed}, and the composition has ${found.language.version}.`);
|
|
5823
|
+
}
|
|
5824
|
+
seen.set(language.name, {
|
|
5825
|
+
language,
|
|
5826
|
+
index
|
|
5827
|
+
});
|
|
5828
|
+
parts.push(partOf(language));
|
|
5829
|
+
});
|
|
5830
|
+
if (conflicts.length > 0) throw new MergeError(conflicts);
|
|
5831
|
+
return mergeMachines(...parts);
|
|
5832
|
+
}
|
|
5833
|
+
/**
|
|
5834
|
+
* This function makes the language of the boundary kind `lang` (K38, D193). A document of the kind holds the name of a
|
|
5835
|
+
* language and a document in that language: `{ type: "lang", value: { language, doc } }`. The machine of the named
|
|
5836
|
+
* language prepares and evaluates the inner document, as a module of another language (COMPOSE.BOUNDARY).
|
|
5837
|
+
*
|
|
5838
|
+
* The boundary is closed. The inner document gets no names, no capabilities and no node as `self`. Only its result
|
|
5839
|
+
* crosses the boundary. Thus an effect in the inner document fails with `#CAP!`, and the inner machine cannot read the
|
|
5840
|
+
* names of the outer document.
|
|
5841
|
+
*
|
|
5842
|
+
* @param machines - The machine of each language, by the name that a document gives.
|
|
5843
|
+
* @returns The language, for `compose`.
|
|
5844
|
+
*/
|
|
5845
|
+
function boundary(machines) {
|
|
5846
|
+
const plans = /* @__PURE__ */ new Map();
|
|
5847
|
+
const planOf = (name) => {
|
|
5848
|
+
let found = plans.get(name);
|
|
5849
|
+
if (found === void 0 && Object.hasOwn(machines, name)) {
|
|
5850
|
+
found = planner(machines[name]);
|
|
5851
|
+
plans.set(name, found);
|
|
5852
|
+
}
|
|
5853
|
+
return found;
|
|
5854
|
+
};
|
|
5855
|
+
return defineLanguage({
|
|
5856
|
+
name: "boundary",
|
|
5857
|
+
version: "1.0.0",
|
|
5858
|
+
world: { kinds: { lang: {
|
|
5859
|
+
verbs: { eval: "boundary.lang" },
|
|
5860
|
+
summary: "A document in another language. The machine of that language evaluates it, with no names and no capabilities."
|
|
5861
|
+
} } },
|
|
5862
|
+
code: { evaluators: { "boundary.lang": (input) => {
|
|
5863
|
+
const { data, place } = input;
|
|
5864
|
+
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 });
|
|
5865
|
+
const plans = planOf(data["language"]);
|
|
5866
|
+
if (plans === void 0) return fail("#NAME?", `The boundary knows no language ${JSON.stringify(data["language"])}.`, { place });
|
|
5867
|
+
return evaluateWithin(plans(data["doc"]), makeContext(), input[RUNTIME]);
|
|
5868
|
+
} } }
|
|
5869
|
+
});
|
|
5870
|
+
}
|
|
5871
|
+
// src/steps.ts
|
|
5872
|
+
/**
|
|
5873
|
+
* This function makes a ladder of steps, and it checks the declaration (STEPS.LADDER). The list of steps must have one
|
|
5874
|
+
* step or more, with no name two times. The step of each construct must be a step of the list.
|
|
5916
5875
|
*
|
|
5917
|
-
* @param
|
|
5918
|
-
* @param
|
|
5919
|
-
* @
|
|
5920
|
-
* @
|
|
5921
|
-
* @returns The result, the trace and the effects in their order.
|
|
5876
|
+
* @param steps - The names of the steps, from the lowest to the highest.
|
|
5877
|
+
* @param constructs - The step that each construct needs.
|
|
5878
|
+
* @returns The ladder, frozen.
|
|
5879
|
+
* @throws TypeError for a declaration that is not valid, because it is a defect of the language.
|
|
5922
5880
|
*/
|
|
5923
|
-
function
|
|
5924
|
-
|
|
5925
|
-
const
|
|
5926
|
-
const
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5881
|
+
function stepLadder(steps, constructs) {
|
|
5882
|
+
if (steps.length === 0) throw new TypeError("a ladder of steps needs one step or more");
|
|
5883
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5884
|
+
for (const step of steps) {
|
|
5885
|
+
if (typeof step !== "string") throw new TypeError(`the step ${String(step)} is not a name`);
|
|
5886
|
+
if (seen.has(step)) throw new TypeError(`the step "${step}" is in the ladder two times`);
|
|
5887
|
+
seen.add(step);
|
|
5888
|
+
}
|
|
5889
|
+
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`);
|
|
5890
|
+
return Object.freeze({
|
|
5891
|
+
steps: Object.freeze([...steps]),
|
|
5892
|
+
constructs: Object.freeze({ ...constructs })
|
|
5931
5893
|
});
|
|
5932
|
-
const ctx = rootContext(machine, context);
|
|
5933
|
-
const s = new Session(machine, ctx.caps, false, true, given.perform, void 0, void 0, readingOf(given.reads, ctx));
|
|
5934
|
-
return record(s, plan.code(ctx, s));
|
|
5935
5894
|
}
|
|
5936
5895
|
/**
|
|
5937
|
-
* This function
|
|
5938
|
-
* parts and for its effects, thus a step can read the result of the step before. The part of the run before the
|
|
5939
|
-
* first wait happens at once, in the call. The run records a trace.
|
|
5896
|
+
* This function tells if a value is a step of a ladder. A host uses it to check its option for the highest step.
|
|
5940
5897
|
*
|
|
5941
|
-
* @param
|
|
5942
|
-
* @param
|
|
5943
|
-
* @
|
|
5944
|
-
* @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.
|
|
5945
|
-
* @returns The result, the trace and the effects in their order, when the run ends.
|
|
5898
|
+
* @param ladder - The ladder.
|
|
5899
|
+
* @param value - The value.
|
|
5900
|
+
* @returns `true` when the value is the name of a step of the ladder.
|
|
5946
5901
|
*/
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
trace: true,
|
|
5950
|
-
...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
|
|
5951
|
-
...options.guards === void 0 ? {} : { guards: options.guards },
|
|
5952
|
-
...options.verb === void 0 ? {} : { verb: options.verb }
|
|
5953
|
-
});
|
|
5954
|
-
const ctx = rootContext(machine, context);
|
|
5955
|
-
const s = new Session(machine, ctx.caps, true, true, options.perform, void 0, void 0, readingOf(options.reads, ctx));
|
|
5956
|
-
const result = await driveWaiting(plan.runCode()(ctx, s), options.signal);
|
|
5957
|
-
s.top = s;
|
|
5958
|
-
return record(s, result);
|
|
5902
|
+
function isStep(ladder, value) {
|
|
5903
|
+
return typeof value === "string" && ladder.steps.includes(value);
|
|
5959
5904
|
}
|
|
5960
5905
|
/**
|
|
5961
|
-
* This function
|
|
5906
|
+
* This function gives the position of a step in its ladder. The lowest step has the position 0.
|
|
5962
5907
|
*
|
|
5963
|
-
* @param
|
|
5964
|
-
* @param
|
|
5965
|
-
* @returns The
|
|
5908
|
+
* @param ladder - The ladder.
|
|
5909
|
+
* @param step - The step.
|
|
5910
|
+
* @returns The position.
|
|
5911
|
+
* @throws TypeError for a name that is not a step of the ladder.
|
|
5966
5912
|
*/
|
|
5967
|
-
function
|
|
5968
|
-
const
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
});
|
|
5977
|
-
if (node !== void 0) at += node.path.length - here.path.length;
|
|
5978
|
-
}
|
|
5979
|
-
return node;
|
|
5913
|
+
function stepRank(ladder, step) {
|
|
5914
|
+
const rank = ladder.steps.indexOf(step);
|
|
5915
|
+
if (rank < 0) throw new TypeError(`"${String(step)}" is not a step of the ladder. The steps are ${ladder.steps.join(", ")}`);
|
|
5916
|
+
return rank;
|
|
5917
|
+
}
|
|
5918
|
+
function pathOf(visit) {
|
|
5919
|
+
const path = [];
|
|
5920
|
+
for (let v = visit; v?.key !== void 0; v = v.parent) path.push(v.key);
|
|
5921
|
+
return path.reverse();
|
|
5980
5922
|
}
|
|
5981
5923
|
/**
|
|
5982
|
-
* This function
|
|
5924
|
+
* This function gives the lowest step that a document needs, with the reason (STEPS.LOWEST, STEPS.REASON). The step is
|
|
5925
|
+
* the highest step of the constructs of its nodes. The reason is the first node in document order with that step. The
|
|
5926
|
+
* walk uses its own stack, thus a deep document does not overflow (STEPS.LINEAR). It visits a shared node one time,
|
|
5927
|
+
* and it stops at the first node with the highest step of the ladder.
|
|
5983
5928
|
*
|
|
5984
|
-
* @param
|
|
5985
|
-
* @
|
|
5929
|
+
* @param ladder - The ladder of the language.
|
|
5930
|
+
* @param walk - The construct and the child nodes of a node.
|
|
5931
|
+
* @param root - The root node of the document.
|
|
5932
|
+
* @returns The step, and the reason when the step is not the lowest step.
|
|
5986
5933
|
*/
|
|
5987
|
-
function
|
|
5988
|
-
const
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5934
|
+
function stepOf(ladder, walk, root) {
|
|
5935
|
+
const top = ladder.steps.length - 1;
|
|
5936
|
+
let best = 0;
|
|
5937
|
+
let reason;
|
|
5938
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5939
|
+
const todo = [{
|
|
5940
|
+
node: root,
|
|
5941
|
+
key: void 0,
|
|
5942
|
+
parent: void 0
|
|
5943
|
+
}];
|
|
5944
|
+
for (let visit = todo.pop(); visit !== void 0; visit = todo.pop()) {
|
|
5945
|
+
const { node } = visit;
|
|
5946
|
+
if (typeof node === "object" && node !== null) {
|
|
5947
|
+
if (seen.has(node)) continue;
|
|
5948
|
+
seen.add(node);
|
|
5949
|
+
}
|
|
5950
|
+
const construct = walk.construct(node);
|
|
5951
|
+
const step = construct === void 0 || !Object.hasOwn(ladder.constructs, construct) ? void 0 : ladder.constructs[construct];
|
|
5952
|
+
const rank = step === void 0 ? 0 : ladder.steps.indexOf(step);
|
|
5953
|
+
if (rank > best) {
|
|
5954
|
+
best = rank;
|
|
5955
|
+
reason = {
|
|
5956
|
+
construct,
|
|
5957
|
+
step,
|
|
5958
|
+
path: pathOf(visit),
|
|
5959
|
+
node
|
|
5960
|
+
};
|
|
5961
|
+
if (best === top) break;
|
|
5962
|
+
}
|
|
5963
|
+
const kids = [...walk.children(node)];
|
|
5964
|
+
for (let i = kids.length - 1; i >= 0; i--) {
|
|
5965
|
+
const [key, child] = kids[i];
|
|
5966
|
+
todo.push({
|
|
5967
|
+
node: child,
|
|
5968
|
+
key,
|
|
5969
|
+
parent: visit
|
|
5970
|
+
});
|
|
5971
|
+
}
|
|
5994
5972
|
}
|
|
5995
|
-
|
|
5973
|
+
const step = ladder.steps[best];
|
|
5974
|
+
return reason === void 0 ? { step } : {
|
|
5975
|
+
step,
|
|
5976
|
+
reason
|
|
5977
|
+
};
|
|
5996
5978
|
}
|
|
5997
5979
|
/**
|
|
5998
|
-
* This function
|
|
5999
|
-
* the
|
|
5980
|
+
* This function compares the step of a document with the highest step that the host accepts (STEPS.MAX). The limit
|
|
5981
|
+
* changes only which documents the host accepts. The language evaluates an accepted document as before, thus a limit
|
|
5982
|
+
* does not change a value.
|
|
6000
5983
|
*
|
|
6001
|
-
* @param
|
|
6002
|
-
* @
|
|
5984
|
+
* @param ladder - The ladder of the language.
|
|
5985
|
+
* @param need - The step of the document, from `stepOf`.
|
|
5986
|
+
* @param maxStep - The highest step that the host accepts.
|
|
5987
|
+
* @returns `undefined` when the host accepts the document, or the refusal that names the needed step.
|
|
5988
|
+
* @throws TypeError when `maxStep` or the step of `need` is not a step of the ladder.
|
|
6003
5989
|
*/
|
|
6004
|
-
function
|
|
6005
|
-
|
|
5990
|
+
function checkStep(ladder, need, maxStep) {
|
|
5991
|
+
const limit = stepRank(ladder, maxStep);
|
|
5992
|
+
if (stepRank(ladder, need.step) <= limit) return void 0;
|
|
5993
|
+
const head = `the document needs the step ${need.step}, and the host accepts the steps up to ${maxStep}`;
|
|
5994
|
+
const reason = need.reason;
|
|
5995
|
+
if (reason === void 0) return {
|
|
5996
|
+
needed: need.step,
|
|
5997
|
+
maxStep,
|
|
5998
|
+
message: head
|
|
5999
|
+
};
|
|
6000
|
+
const where = reason.path.length === 0 ? "at the root" : `at the path ${JSON.stringify(reason.path)}`;
|
|
6001
|
+
return {
|
|
6002
|
+
needed: need.step,
|
|
6003
|
+
maxStep,
|
|
6004
|
+
reason,
|
|
6005
|
+
message: `${head}. The construct "${reason.construct}" ${where} needs the step ${reason.step}`
|
|
6006
|
+
};
|
|
6007
|
+
}
|
|
6008
|
+
// src/classify.ts
|
|
6009
|
+
function isStrictSuperset(larger, smaller) {
|
|
6010
|
+
return larger.length > smaller.length && smaller.every((name) => larger.includes(name));
|
|
6011
|
+
}
|
|
6012
|
+
/**
|
|
6013
|
+
* This function proposes a kind for a value without a type, from the fields that the value has.
|
|
6014
|
+
* A shape applies when the value has each field of the shape. The most specific shapes are the ones that
|
|
6015
|
+
* no other applicable shape contains. A host uses a classifier when data comes in, and then tags the data.
|
|
6016
|
+
* The ladder does not call a classifier.
|
|
6017
|
+
*
|
|
6018
|
+
* @param shapes - The shapes to examine.
|
|
6019
|
+
* @param value - The value without a type.
|
|
6020
|
+
* @returns The proposed kind, or an error with the candidates.
|
|
6021
|
+
*/
|
|
6022
|
+
function classify(shapes, value) {
|
|
6023
|
+
const applicable = isRecord(value) ? shapes.filter((shape) => shape.fields.every((name) => field(value, name) !== void 0)) : [];
|
|
6024
|
+
const best = applicable.filter((shape) => !applicable.some((other) => isStrictSuperset(other.fields, shape.fields)));
|
|
6025
|
+
const candidates = best.map((shape) => shape.name);
|
|
6026
|
+
const only = best.length === 1 ? best[0] : void 0;
|
|
6027
|
+
if (only !== void 0) return {
|
|
6028
|
+
kind: only.kind,
|
|
6029
|
+
candidates
|
|
6030
|
+
};
|
|
6031
|
+
return {
|
|
6032
|
+
candidates,
|
|
6033
|
+
error: best.length === 0 ? "no-match" : "ambiguous"
|
|
6034
|
+
};
|
|
6035
|
+
}
|
|
6036
|
+
/**
|
|
6037
|
+
* This function puts a value in an envelope with a type. The value does not change.
|
|
6038
|
+
*
|
|
6039
|
+
* @param value - The value.
|
|
6040
|
+
* @param kind - The name of the kind.
|
|
6041
|
+
* @returns The envelope.
|
|
6042
|
+
*/
|
|
6043
|
+
function tag(value, kind) {
|
|
6044
|
+
return typed(kind, value);
|
|
6006
6045
|
}
|
|
6007
6046
|
// src/stdlib.ts
|
|
6008
6047
|
/**
|
|
@@ -8922,71 +8961,12 @@ function indexed(graph, options) {
|
|
|
8922
8961
|
};
|
|
8923
8962
|
}
|
|
8924
8963
|
/**
|
|
8925
|
-
* This function finds the strongly connected components with
|
|
8926
|
-
*
|
|
8927
|
-
* component that its nodes reach: the deepest component comes first.
|
|
8964
|
+
* This function finds the strongly connected components with `strongComponentsCompact` of
|
|
8965
|
+
* `@mark1russell7/collections` (K249). The search keeps its own stack, thus a long chain does not overflow the stack
|
|
8966
|
+
* of the host. Each component comes after each component that its nodes reach: the deepest component comes first.
|
|
8928
8967
|
*/
|
|
8929
8968
|
function strong(graph) {
|
|
8930
|
-
|
|
8931
|
-
const order = new Int32Array(size).fill(-1);
|
|
8932
|
-
const low = new Int32Array(size);
|
|
8933
|
-
const of = new Int32Array(size).fill(-1);
|
|
8934
|
-
const open = new Int32Array(size);
|
|
8935
|
-
const onOpen = new Uint8Array(size);
|
|
8936
|
-
const calls = new Int32Array(size);
|
|
8937
|
-
const next = new Int32Array(size);
|
|
8938
|
-
const list = [];
|
|
8939
|
-
let top = 0;
|
|
8940
|
-
let count = 0;
|
|
8941
|
-
const enter = (node, depth) => {
|
|
8942
|
-
order[node] = count;
|
|
8943
|
-
low[node] = count;
|
|
8944
|
-
count += 1;
|
|
8945
|
-
open[top] = node;
|
|
8946
|
-
top += 1;
|
|
8947
|
-
onOpen[node] = 1;
|
|
8948
|
-
calls[depth] = node;
|
|
8949
|
-
next[depth] = start[node];
|
|
8950
|
-
};
|
|
8951
|
-
for (let root = 0; root < size; root += 1) {
|
|
8952
|
-
if (order[root] !== -1) continue;
|
|
8953
|
-
enter(root, 0);
|
|
8954
|
-
let depth = 1;
|
|
8955
|
-
while (depth > 0) {
|
|
8956
|
-
const node = calls[depth - 1];
|
|
8957
|
-
const edge = next[depth - 1];
|
|
8958
|
-
if (edge < start[node + 1]) {
|
|
8959
|
-
next[depth - 1] = edge + 1;
|
|
8960
|
-
const to = targets[edge];
|
|
8961
|
-
if (order[to] === -1) {
|
|
8962
|
-
enter(to, depth);
|
|
8963
|
-
depth += 1;
|
|
8964
|
-
} else if (onOpen[to] === 1 && order[to] < low[node]) low[node] = order[to];
|
|
8965
|
-
continue;
|
|
8966
|
-
}
|
|
8967
|
-
depth -= 1;
|
|
8968
|
-
if (low[node] === order[node]) {
|
|
8969
|
-
const members = [];
|
|
8970
|
-
let member;
|
|
8971
|
-
do {
|
|
8972
|
-
top -= 1;
|
|
8973
|
-
member = open[top];
|
|
8974
|
-
onOpen[member] = 0;
|
|
8975
|
-
of[member] = list.length;
|
|
8976
|
-
members.push(member);
|
|
8977
|
-
} while (member !== node);
|
|
8978
|
-
list.push(members.sort((a, b) => a - b));
|
|
8979
|
-
}
|
|
8980
|
-
if (depth > 0) {
|
|
8981
|
-
const reader = calls[depth - 1];
|
|
8982
|
-
if (low[node] < low[reader]) low[reader] = low[node];
|
|
8983
|
-
}
|
|
8984
|
-
}
|
|
8985
|
-
}
|
|
8986
|
-
return {
|
|
8987
|
-
of,
|
|
8988
|
-
list
|
|
8989
|
-
};
|
|
8969
|
+
return strongComponentsCompact(graph.size, graph.start, graph.targets);
|
|
8990
8970
|
}
|
|
8991
8971
|
/** This function tells if a component has a cycle: two or more nodes, or one node with an edge to itself. */
|
|
8992
8972
|
function cyclic(graph, members) {
|
|
@@ -12358,7 +12338,9 @@ function formulaCode(profile) {
|
|
|
12358
12338
|
const level = (clock.applying ?? 0) + 1;
|
|
12359
12339
|
if (level > limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
|
|
12360
12340
|
rt.spend?.(1);
|
|
12341
|
+
const root = clock.top ?? clock;
|
|
12361
12342
|
clock.applying = level;
|
|
12343
|
+
root.active = (root.active ?? 0) + 1;
|
|
12362
12344
|
try {
|
|
12363
12345
|
const scope = { ...ctx.names };
|
|
12364
12346
|
names.forEach((name, index) => setOwn$2(scope, name, args[index]));
|
|
@@ -12370,6 +12352,7 @@ function formulaCode(profile) {
|
|
|
12370
12352
|
return result.value;
|
|
12371
12353
|
} finally {
|
|
12372
12354
|
clock.applying = level - 1;
|
|
12355
|
+
root.active = (root.active ?? 1) - 1;
|
|
12373
12356
|
}
|
|
12374
12357
|
};
|
|
12375
12358
|
Object.defineProperty(closure, CLOSURE$3, { value: { params: names } });
|
|
@@ -13185,7 +13168,7 @@ function evaluateRoot(machine, doc, context, options, outer, meter) {
|
|
|
13185
13168
|
*/
|
|
13186
13169
|
function spend(env, points) {
|
|
13187
13170
|
const meter = env.meter;
|
|
13188
|
-
if (meter.ended &&
|
|
13171
|
+
if (meter.ended && meter.active === 0) meter.spent = 0;
|
|
13189
13172
|
meter.spent += points;
|
|
13190
13173
|
if (meter.spent > env.maxWork) throw new Failure(workFailure(env.maxWork));
|
|
13191
13174
|
}
|
|
@@ -13236,7 +13219,8 @@ function envOf(machine, options, running, root, outer, meter) {
|
|
|
13236
13219
|
maxWork: machine.maxWork ?? 2e5,
|
|
13237
13220
|
meter: meter ?? {
|
|
13238
13221
|
spent: 0,
|
|
13239
|
-
ended: false
|
|
13222
|
+
ended: false,
|
|
13223
|
+
active: 0
|
|
13240
13224
|
},
|
|
13241
13225
|
nested: meter !== void 0,
|
|
13242
13226
|
reading: outer ?? (options.reads === void 0 ? void 0 : {
|
|
@@ -13922,13 +13906,15 @@ function formulaDefinitions(profile = {}) {
|
|
|
13922
13906
|
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.");
|
|
13923
13907
|
const names = params;
|
|
13924
13908
|
const body = partNamed$1(parts, "body");
|
|
13925
|
-
const
|
|
13909
|
+
const maker = activeEnvs[activeEnvs.length - 1];
|
|
13910
|
+
const clock = maker ?? {
|
|
13926
13911
|
applying: 0,
|
|
13927
13912
|
maxDepth: 1e3,
|
|
13928
13913
|
maxWork: 2e5,
|
|
13929
13914
|
meter: {
|
|
13930
13915
|
spent: 0,
|
|
13931
|
-
ended: false
|
|
13916
|
+
ended: false,
|
|
13917
|
+
active: 0
|
|
13932
13918
|
}
|
|
13933
13919
|
};
|
|
13934
13920
|
const limit = Math.ceil(clock.maxDepth / 4);
|
|
@@ -13936,18 +13922,21 @@ function formulaDefinitions(profile = {}) {
|
|
|
13936
13922
|
if (clock.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
|
|
13937
13923
|
spend(clock, 1);
|
|
13938
13924
|
clock.applying += 1;
|
|
13925
|
+
clock.meter.active += 1;
|
|
13939
13926
|
try {
|
|
13940
13927
|
const scope = {};
|
|
13941
13928
|
for (const key of Object.keys(context.names)) setField$2(scope, key, context.names[key]);
|
|
13942
13929
|
names.forEach((name, index) => setField$2(scope, name, args[index]));
|
|
13943
|
-
const
|
|
13930
|
+
const scoped = {
|
|
13944
13931
|
...context,
|
|
13945
13932
|
names: scope
|
|
13946
|
-
}
|
|
13933
|
+
};
|
|
13934
|
+
const result = maker === void 0 ? body.evaluate(scoped) : within(maker, () => body.evaluate(scoped));
|
|
13947
13935
|
if (!result.ok) throw new Failure(result.error);
|
|
13948
13936
|
return result.value;
|
|
13949
13937
|
} finally {
|
|
13950
13938
|
clock.applying -= 1;
|
|
13939
|
+
clock.meter.active -= 1;
|
|
13951
13940
|
}
|
|
13952
13941
|
};
|
|
13953
13942
|
Object.defineProperty(closure, CLOSURE$2, { value: { params: names } });
|
|
@@ -14444,6 +14433,11 @@ function apply(p, c, target, args) {
|
|
|
14444
14433
|
}
|
|
14445
14434
|
const limit = Math.ceil(p.maxDepth / 4);
|
|
14446
14435
|
if (c.applying >= limit) return back(c, fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`));
|
|
14436
|
+
p.work += 1;
|
|
14437
|
+
if (p.work > p.maxWork) return back(c, {
|
|
14438
|
+
ok: false,
|
|
14439
|
+
error: workFailure(p.maxWork)
|
|
14440
|
+
});
|
|
14447
14441
|
pushed(c, {
|
|
14448
14442
|
f: "return",
|
|
14449
14443
|
place: closure.place.concat(closure.body.path)
|
|
@@ -14470,6 +14464,9 @@ function hostClosure(p, value, closure) {
|
|
|
14470
14464
|
const fn = (...args) => {
|
|
14471
14465
|
const limit = Math.ceil(p.maxDepth / 4);
|
|
14472
14466
|
if (p.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
|
|
14467
|
+
p.work = (p.ended && p.applying === 0 ? 0 : p.work) + 1;
|
|
14468
|
+
if (p.work > p.maxWork) throw new Failure(workFailure(p.maxWork));
|
|
14469
|
+
const before = p.applying;
|
|
14473
14470
|
p.applying += 1;
|
|
14474
14471
|
try {
|
|
14475
14472
|
const place = closure.place.concat(closure.body.path);
|
|
@@ -14486,7 +14483,7 @@ function hostClosure(p, value, closure) {
|
|
|
14486
14483
|
if (!end.result.ok) throw new Failure(end.result.error);
|
|
14487
14484
|
return forHost(p, end, end.result.value);
|
|
14488
14485
|
} finally {
|
|
14489
|
-
p.applying
|
|
14486
|
+
p.applying = before;
|
|
14490
14487
|
}
|
|
14491
14488
|
};
|
|
14492
14489
|
Object.defineProperty(fn, CLOSURE$1, { value: { params: closure.params } });
|
|
@@ -14817,7 +14814,7 @@ function cause(p, ctx, kind, payload, place) {
|
|
|
14817
14814
|
const count = counts.get(at) ?? 0;
|
|
14818
14815
|
counts.set(at, count + 1);
|
|
14819
14816
|
const effect = {
|
|
14820
|
-
index: effects.length,
|
|
14817
|
+
index: p.before + effects.length,
|
|
14821
14818
|
kind: text,
|
|
14822
14819
|
path: keys,
|
|
14823
14820
|
payload,
|
|
@@ -14923,7 +14920,8 @@ function evaluateDoc(p, c) {
|
|
|
14923
14920
|
} catch (error) {
|
|
14924
14921
|
return back(c, thrown(error, `the evaluator ${name}`));
|
|
14925
14922
|
}
|
|
14926
|
-
const
|
|
14923
|
+
const standard = code === own$1(STD_EVALUATORS, name) ? own$1(STD_DEFINITIONS.evaluators, name) : void 0;
|
|
14924
|
+
const defined = own$1(p.definitions.evaluators, name) ?? standard;
|
|
14927
14925
|
if (defined !== void 0) return hostEvaluator(p, c, name, defined, doc, keys, read.data, read.slots, site);
|
|
14928
14926
|
return back(c, fail("#NOEVAL", `The stepper has no definition of the compiled evaluator ${name}.`));
|
|
14929
14927
|
}
|
|
@@ -15080,7 +15078,11 @@ function programOf(machine, options) {
|
|
|
15080
15078
|
effects: options.effects ?? [],
|
|
15081
15079
|
perform: options.perform,
|
|
15082
15080
|
counts: /* @__PURE__ */ new Map(),
|
|
15083
|
-
|
|
15081
|
+
before: 0,
|
|
15082
|
+
applying: 0,
|
|
15083
|
+
maxWork: machine.maxWork ?? 2e5,
|
|
15084
|
+
work: 0,
|
|
15085
|
+
ended: false
|
|
15084
15086
|
};
|
|
15085
15087
|
}
|
|
15086
15088
|
/**
|
|
@@ -15136,10 +15138,21 @@ function stepperNext(machine, configuration, options = {}) {
|
|
|
15136
15138
|
};
|
|
15137
15139
|
else stack[stack.length - 1] = { ...top };
|
|
15138
15140
|
}
|
|
15139
|
-
|
|
15141
|
+
const p = programOf(machine, options);
|
|
15142
|
+
p.work = configuration.work ?? 0;
|
|
15143
|
+
for (const [at, count] of Object.entries(configuration.counts ?? {})) p.counts.set(at, count);
|
|
15144
|
+
p.before = options.effects === void 0 ? configuration.effected ?? 0 : 0;
|
|
15145
|
+
const next = advance(p, {
|
|
15140
15146
|
...configuration,
|
|
15141
15147
|
stack
|
|
15142
15148
|
});
|
|
15149
|
+
const effected = p.before + p.effects.length;
|
|
15150
|
+
return {
|
|
15151
|
+
...next,
|
|
15152
|
+
...p.work === 0 ? {} : { work: p.work },
|
|
15153
|
+
...p.counts.size === 0 ? {} : { counts: Object.fromEntries(p.counts) },
|
|
15154
|
+
...effected === 0 ? {} : { effected }
|
|
15155
|
+
};
|
|
15143
15156
|
}
|
|
15144
15157
|
/**
|
|
15145
15158
|
* This function evaluates a document with an explicit stack (K95, D158). It gives the result of `reference` for each
|
|
@@ -15157,6 +15170,7 @@ function stepper(machine, doc, context = makeContext(), options = {}) {
|
|
|
15157
15170
|
const p = programOf(machine, options);
|
|
15158
15171
|
try {
|
|
15159
15172
|
const end = drive$1(p, stepperStart(machine, doc, context, options));
|
|
15173
|
+
p.ended = true;
|
|
15160
15174
|
return end.result.ok ? ok(forHost(p, end, end.result.value)) : end.result;
|
|
15161
15175
|
} catch (error) {
|
|
15162
15176
|
return placed(thrown(error, "the stepper"), []);
|
|
@@ -18908,7 +18922,10 @@ function generate(world, options) {
|
|
|
18908
18922
|
value
|
|
18909
18923
|
};
|
|
18910
18924
|
if (header !== void 0) out["name"] = header;
|
|
18911
|
-
if (options.own !== void 0 && options.own.length > 0 && rng.chance(.03))
|
|
18925
|
+
if (options.own !== void 0 && options.own.length > 0 && rng.chance(.03)) {
|
|
18926
|
+
const code = rng.pick(options.own);
|
|
18927
|
+
if ((kindOf(type)?.scope ?? []).length === 0) out["own"] = { eval: code };
|
|
18928
|
+
}
|
|
18912
18929
|
return out;
|
|
18913
18930
|
};
|
|
18914
18931
|
/**
|
|
@@ -22556,6 +22573,6 @@ function samplesAt(values, closed, depth) {
|
|
|
22556
22573
|
function typeFromSamples(values, options = {}) {
|
|
22557
22574
|
return samplesAt(values, options.closed === true, 0);
|
|
22558
22575
|
}
|
|
22559
|
-
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, 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 };
|
|
22576
|
+
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 };
|
|
22560
22577
|
|
|
22561
22578
|
//# sourceMappingURL=index.js.map
|