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