@mark1russell7/coeval 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -282,7 +282,11 @@ var Failure = class extends Error {
282
282
  * @returns `true` for a stack overflow.
283
283
  */
284
284
  function isStackOverflow(error) {
285
- return error instanceof RangeError && /call stack/i.test(error.message);
285
+ try {
286
+ return error instanceof RangeError && /call stack/i.test(error.message);
287
+ } catch {
288
+ return true;
289
+ }
286
290
  }
287
291
  /**
288
292
  * This function changes an exception into an error value. A `Failure` gives its error value. A stack overflow
@@ -1543,7 +1547,7 @@ function holderNode() {
1543
1547
  };
1544
1548
  }
1545
1549
  /** This function drives steps that cannot wait. */
1546
- function drive(steps) {
1550
+ function drive$1(steps) {
1547
1551
  const step = steps.next();
1548
1552
  if (step.done === true) return step.value;
1549
1553
  step.value.catch(() => void 0);
@@ -1586,7 +1590,10 @@ function isCompiledRunner(runner) {
1586
1590
  return typeof runner === "object" && runner !== null && typeof runner.compileRun === "function";
1587
1591
  }
1588
1592
  function failing(c, meta, place, code, reason) {
1589
- const result = fail(code, reason, { place });
1593
+ return failingWith(c, meta, fail(code, reason, { place }));
1594
+ }
1595
+ /** This function gives the code of a document that fails with one result at each evaluation. */
1596
+ function failingWith(c, meta, result) {
1590
1597
  const plain = () => result;
1591
1598
  return finish(c, meta, plain, function* () {
1592
1599
  return result;
@@ -1752,10 +1759,22 @@ function compileNode(c, value, place, declared, depth, address = false) {
1752
1759
  ...address ? { address: true } : {}
1753
1760
  };
1754
1761
  if (runner !== void 0) {
1755
- const run = placedRun(isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill), place, name);
1762
+ let inner;
1763
+ try {
1764
+ inner = isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill);
1765
+ } catch (error) {
1766
+ return failingWith(c, meta, placed(thrown(error, `the runner ${name}`), place));
1767
+ }
1768
+ const run = placedRun(inner, place, name);
1756
1769
  return finish(c, meta, runnerCode(run, place, kindText), run);
1757
1770
  }
1758
- const code = placedCode(isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill), place, name);
1771
+ let inner;
1772
+ try {
1773
+ inner = isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill);
1774
+ } catch (error) {
1775
+ return failingWith(c, meta, placed(thrown(error, `the evaluator ${name}`), place));
1776
+ }
1777
+ const code = placedCode(inner, place, name);
1759
1778
  return finish(c, meta, code, runOf(code));
1760
1779
  }
1761
1780
  /** This function gives the code of a document: the code of its evaluator, with the place of each error and of each exception. */
@@ -1797,9 +1816,12 @@ function placedRun(inner, place, name) {
1797
1816
  }
1798
1817
  };
1799
1818
  }
1800
- /** This function gives the code of a runner in an evaluation: its steps, which cannot wait. */
1819
+ /**
1820
+ * This function gives the code of a runner in an evaluation: its steps, which cannot wait. A step that waits gives
1821
+ * `#CALC!` at the place of the runner, where the error started (RUN.WAIT).
1822
+ */
1801
1823
  function runnerCode(run, place, kindText) {
1802
- return (ctx, rt) => rt.running ? fail("#CALC!", `${kindText} waits for effects, and its parent cannot wait. Give the parent a runner.`, { place }) : drive(run(ctx, rt));
1824
+ return (ctx, rt) => rt.running ? fail("#CALC!", `${kindText} waits for effects, and its parent cannot wait. Give the parent a runner.`, { place }) : placed(drive$1(run(ctx, rt)), place);
1803
1825
  }
1804
1826
  /** This function gives the steps of a run of an evaluator. The code runs at the first step, and it does not wait. */
1805
1827
  function runOf(code) {
@@ -1891,7 +1913,7 @@ function prepare(machine, doc, options = {}) {
1891
1913
  try {
1892
1914
  root = compileNode(c, doc, [], options.declaredType, 0);
1893
1915
  } catch (error) {
1894
- const result = thrown(error, "the compilation");
1916
+ const result = placed(thrown(error, "the compilation"), []);
1895
1917
  root = {
1896
1918
  code: () => result,
1897
1919
  run: function* () {
@@ -1952,7 +1974,7 @@ function planner(machine, options = {}) {
1952
1974
  return plan;
1953
1975
  };
1954
1976
  }
1955
- function record(s, result) {
1977
+ function record$1(s, result) {
1956
1978
  const root = s.holder?.children[0];
1957
1979
  if (root === void 0) throw new Error("The evaluation made no trace.");
1958
1980
  return {
@@ -1981,7 +2003,7 @@ function evaluate(machine, doc, context = makeContext(), declaredType) {
1981
2003
  ...declaredType === void 0 ? {} : { declaredType }
1982
2004
  });
1983
2005
  const s = new Session(machine, false, true, void 0, void 0, void 0);
1984
- return record(s, plan.root.code(rootContext(machine, context), s));
2006
+ return record$1(s, plan.root.code(rootContext(machine, context), s));
1985
2007
  }
1986
2008
  /**
1987
2009
  * This function runs a document: an evaluation in which the host does each effect. A runner waits for its
@@ -2000,7 +2022,7 @@ async function run(machine, doc, context = makeContext(), options = {}) {
2000
2022
  ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType }
2001
2023
  });
2002
2024
  const s = new Session(machine, true, true, options.perform, options.signal, void 0);
2003
- return record(s, await driveWaiting(plan.root.run(rootContext(machine, context), s), options.signal));
2025
+ return record$1(s, await driveWaiting(plan.root.run(rootContext(machine, context), s), options.signal));
2004
2026
  }
2005
2027
  /**
2006
2028
  * This function finds a node of a trace by its path.
@@ -3290,7 +3312,7 @@ var Held = class {
3290
3312
  this.error = error;
3291
3313
  }
3292
3314
  };
3293
- const CLOSURE = Symbol.for("coeval.closure");
3315
+ const CLOSURE$2 = Symbol.for("coeval.closure");
3294
3316
  /**
3295
3317
  * This function tells if a value is a function that the construct `fn` made.
3296
3318
  *
@@ -3298,7 +3320,7 @@ const CLOSURE = Symbol.for("coeval.closure");
3298
3320
  * @returns `true` for a closure.
3299
3321
  */
3300
3322
  function isClosure(value) {
3301
- return typeof value === "function" && value[CLOSURE] !== void 0;
3323
+ return typeof value === "function" && value[CLOSURE$2] !== void 0;
3302
3324
  }
3303
3325
  /** The standard extensions: the values that JSON cannot write. */
3304
3326
  const STD_EXT = {
@@ -3531,18 +3553,19 @@ function formulaEvaluators(profile = {}) {
3531
3553
  if (missing !== void 0 && missing(reached)) return fail("#N/A", "The path reaches no value.");
3532
3554
  return ok(reached);
3533
3555
  };
3534
- const computed = parts.length > 0;
3556
+ const held = (ctx) => {
3557
+ if (head === void 0 || !Object.hasOwn(ctx.names, head)) return void 0;
3558
+ const bound = ctx.names[head];
3559
+ return bound instanceof Held ? {
3560
+ ok: false,
3561
+ error: bound.error
3562
+ } : void 0;
3563
+ };
3564
+ if (parts.length === 0) return (ctx, rt) => held(ctx) ?? give(rt.resolve(ctx, path));
3535
3565
  return (ctx, rt) => {
3536
- if (head !== void 0 && Object.hasOwn(ctx.names, head)) {
3537
- const bound = ctx.names[head];
3538
- if (bound instanceof Held) return {
3539
- ok: false,
3540
- error: bound.error
3541
- };
3542
- }
3543
- if (!computed) return give(rt.resolve(ctx, path));
3544
3566
  const steps = valuesOf(parts, ctx, rt);
3545
- return Array.isArray(steps) ? give(rt.resolve(ctx, fill(steps))) : steps;
3567
+ if (!Array.isArray(steps)) return steps;
3568
+ return held(ctx) ?? give(rt.resolve(ctx, fill(steps)));
3546
3569
  };
3547
3570
  }),
3548
3571
  "formula.step": compiled(({ doc, parts, fill }) => {
@@ -3626,7 +3649,7 @@ function formulaEvaluators(profile = {}) {
3626
3649
  if (!result.ok) throw new Failure(result.error);
3627
3650
  return result.value;
3628
3651
  };
3629
- Object.defineProperty(closure, CLOSURE, { value: { params: names } });
3652
+ Object.defineProperty(closure, CLOSURE$2, { value: { params: names } });
3630
3653
  return ok(closure);
3631
3654
  };
3632
3655
  }),
@@ -3795,6 +3818,1054 @@ function formulaMachine(profile = {}, more = {}) {
3795
3818
  };
3796
3819
  }
3797
3820
  //#endregion
3798
- export { CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, ask, capKeys, check, checkSteps, classify, context, dataEdges, derefStep, describe, docEquals, effectEdges, entriesAsJson, evaluate, fail, failures, field, flatten, formulaEvaluators, formulaKinds, formulaMachine, fromJson, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, narrow, nearestWalker, nodeAt, ok, partCaps, pathMatches, permits, placed, planner, prepare, ref, refsOf, resolve, run, splitParts, stored, tag, thrown, toJson, typeName, typePath, typed, valueOfThing, walk, worldThing };
3821
+ //#region src/reference.ts
3822
+ function own(table, name) {
3823
+ return table !== void 0 && Object.hasOwn(table, name) ? table[name] : void 0;
3824
+ }
3825
+ /** This function finds the code of an evaluator name. A runner wins over an evaluator of the same name. */
3826
+ function choose(env, name) {
3827
+ const runner = own(env.machine.runners, name);
3828
+ if (runner !== void 0) {
3829
+ const defined = own(env.definitions.runners, name);
3830
+ if (defined !== void 0) return { runner: defined };
3831
+ return typeof runner === "function" ? { runner } : { gap: `The reference has no definition of the compiled runner ${name}.` };
3832
+ }
3833
+ const evaluator = own(env.machine.evaluators, name);
3834
+ if (evaluator === void 0) return void 0;
3835
+ const defined = own(env.definitions.evaluators, name);
3836
+ if (defined !== void 0) return { evaluator: defined };
3837
+ return typeof evaluator === "function" ? { evaluator } : { gap: `The reference has no definition of the compiled evaluator ${name}.` };
3838
+ }
3839
+ /**
3840
+ * This function reads one document by the rules, in their order. First come an envelope or a declared type
3841
+ * (EVAL.ERRORS) and the limit of the depth (PLAN.DEPTH). Then come the ladder (LADDER.*), an evaluator and the shape
3842
+ * of the parts (SHAPE.*).
3843
+ */
3844
+ function examine(env, at) {
3845
+ const { place, declared } = at;
3846
+ const envelope = isEnvelope(at.value) ? at.value : void 0;
3847
+ if (envelope === void 0 && declared === void 0) return fail("#PART?", "The value has no envelope, and its position declares no type.", { place });
3848
+ if (at.depth > env.maxDepth) return fail("#DEPTH!", `The nesting is deeper than ${env.maxDepth} documents.`, { place });
3849
+ const doc = envelope ?? {
3850
+ type: declared,
3851
+ value: at.value
3852
+ };
3853
+ const kindText = typeName(doc.type);
3854
+ const world = env.machine.world;
3855
+ const answer = ask(world, envelope ?? {}, "eval", declared === void 0 ? {} : { declaredType: declared });
3856
+ if (answer.error === "unknown-kind") return fail("#KIND?", `The world has no kind ${kindText}.`, { place });
3857
+ const name = answer.evaluator;
3858
+ const chosen = name === void 0 ? void 0 : choose(env, name);
3859
+ if (name === void 0 || chosen === void 0) return fail("#NOEVAL", `No rung gives an evaluator for ${kindText}.`, { place });
3860
+ const found = lookupKind(world, doc.type);
3861
+ const kind = found.ok ? found.kind : void 0;
3862
+ const split = splitParts(kind?.parts, doc.value);
3863
+ if (!split.ok) {
3864
+ const where = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
3865
+ return fail("#VALUE!", `${split.reason}${where} The kind is ${kindText}.`, { place });
3866
+ }
3867
+ return {
3868
+ doc,
3869
+ kindText,
3870
+ typePath: found.ok ? found.path : [],
3871
+ kind,
3872
+ name,
3873
+ chosen,
3874
+ split
3875
+ };
3876
+ }
3877
+ /** This function gives the capabilities that the rules of a kind give one part (D14, CAP.CONTRACT, CAP.ONLY). */
3878
+ function capsOfPart(rules, path, caps) {
3879
+ let out = caps;
3880
+ for (const rule of rules ?? []) {
3881
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(path, pattern))) continue;
3882
+ if (rule.rule === "mask") return [];
3883
+ if (rule.rule === "only") out = intersectCaps(out, rule.caps);
3884
+ }
3885
+ return out;
3886
+ }
3887
+ /**
3888
+ * This function gives the context of a part. A context that the evaluator gives keeps only the capabilities of the
3889
+ * parent (CAP.NARROW). Then the rules of the kind narrow it (CAP.CONTRACT).
3890
+ */
3891
+ function contextOfPart(seen, slot, parent, given) {
3892
+ const base = given === void 0 || given === parent ? parent : {
3893
+ ...given,
3894
+ caps: given.caps.filter((cap) => permits(parent.caps, cap))
3895
+ };
3896
+ const caps = capsOfPart(seen.kind?.caps, slot.path, base.caps);
3897
+ return caps === base.caps ? base : {
3898
+ ...base,
3899
+ caps
3900
+ };
3901
+ }
3902
+ function headerOf(item) {
3903
+ return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
3904
+ }
3905
+ function partAt(seen, at, slot, given) {
3906
+ return {
3907
+ value: slot.item,
3908
+ place: at.place.concat(slot.path),
3909
+ declared: slot.of,
3910
+ depth: at.depth + 1,
3911
+ address: slot.address === true,
3912
+ ctx: contextOfPart(seen, slot, at.ctx, given)
3913
+ };
3914
+ }
3915
+ /** This function resolves a path with the full algorithm of `resolve`, not with its short path (DEREF.QUICK). */
3916
+ function resolveFully(machine, ctx, path, options) {
3917
+ const found = resolve(machine, ctx, path, { hops: true });
3918
+ return options?.hops === true ? found : {
3919
+ ...found,
3920
+ hops: []
3921
+ };
3922
+ }
3923
+ /** This function records an effect when the capabilities permit it (RUN.CAP, CAP.HOOK). */
3924
+ function record(env, ctx, kind, payload, place) {
3925
+ const keys = typeof kind === "string" ? kind.split(".") : kind;
3926
+ const text = keys.join(".");
3927
+ const machine = env.machine;
3928
+ if (!(machine.permits === void 0 ? permits(ctx.caps, keys) : machine.permits(ctx.caps, keys, ctx))) return fail("#CAP!", `The context has no capability for the effect ${text}.`, { place });
3929
+ env.effects.push({
3930
+ index: env.effects.length,
3931
+ kind: text,
3932
+ path: keys,
3933
+ payload,
3934
+ node: -1,
3935
+ at: 0,
3936
+ place,
3937
+ context: ctx
3938
+ });
3939
+ }
3940
+ /** This function evaluates a document. Each error gets the place of the document where it started (K5). */
3941
+ function evaluateAt(env, at) {
3942
+ const seen = examine(env, at);
3943
+ if (!("doc" in seen)) return seen;
3944
+ return evaluateSeen(env, seen, at);
3945
+ }
3946
+ function evaluateSeen(env, seen, at) {
3947
+ const { chosen } = seen;
3948
+ const { place } = at;
3949
+ if ("gap" in chosen) return fail("#NOEVAL", chosen.gap, { place });
3950
+ if ("runner" in chosen) return drive(runSeen(env, seen, at, chosen.runner), place);
3951
+ const input = evalInput(env, seen, at);
3952
+ try {
3953
+ return placed(chosen.evaluator(input), place);
3954
+ } catch (error) {
3955
+ return placed(thrown(error, `the evaluator ${seen.name}`), place);
3956
+ }
3957
+ }
3958
+ /** This function gives the steps of a document for a runner. Nothing happens before the first step. */
3959
+ function* stepsAt(env, at) {
3960
+ const seen = examine(env, at);
3961
+ if (!("doc" in seen)) return seen;
3962
+ if ("runner" in seen.chosen) return yield* runSeen(env, seen, at, seen.chosen.runner);
3963
+ return evaluateSeen(env, seen, at);
3964
+ }
3965
+ function* runSeen(env, seen, at, runner) {
3966
+ try {
3967
+ return placed(yield* runner(runInput(env, seen, at)), at.place);
3968
+ } catch (error) {
3969
+ return placed(thrown(error, `the runner ${seen.name}`), at.place);
3970
+ }
3971
+ }
3972
+ /** This function drives steps that cannot wait. A step that waits gives `#CALC!` at the document (RUN.WAIT). */
3973
+ function drive(steps, place) {
3974
+ const step = steps.next();
3975
+ if (step.done === true) return step.value;
3976
+ step.value.catch(() => void 0);
3977
+ const waited = fail("#CALC!", "A part waited, and its parent cannot wait.", { place });
3978
+ steps.return(waited);
3979
+ return waited;
3980
+ }
3981
+ function evalInput(env, seen, at) {
3982
+ const { split, doc } = seen;
3983
+ const parts = split.parts.map((slot) => {
3984
+ const name = headerOf(slot.item);
3985
+ return {
3986
+ key: slot.key,
3987
+ path: slot.path,
3988
+ ...name === void 0 ? {} : { name },
3989
+ evaluate: (given) => evaluateAt(env, partAt(seen, at, slot, given))
3990
+ };
3991
+ });
3992
+ const fill = (items) => split.parts.length === 0 ? doc.value : split.fill(items);
3993
+ return {
3994
+ kind: seen.kindText,
3995
+ typePath: seen.typePath,
3996
+ doc,
3997
+ value: fill(parts),
3998
+ data: split.data,
3999
+ parts,
4000
+ context: at.ctx,
4001
+ place: at.place,
4002
+ ...at.address ? { address: true } : {},
4003
+ resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
4004
+ effect: (kind, payload) => record(env, at.ctx, kind, payload, at.place) ?? ok(payload),
4005
+ fill
4006
+ };
4007
+ }
4008
+ function runInput(env, seen, at) {
4009
+ const { split, doc } = seen;
4010
+ const parts = split.parts.map((slot) => {
4011
+ const name = headerOf(slot.item);
4012
+ return {
4013
+ key: slot.key,
4014
+ path: slot.path,
4015
+ ...name === void 0 ? {} : { name },
4016
+ evaluate: (given) => stepsAt(env, partAt(seen, at, slot, given))
4017
+ };
4018
+ });
4019
+ const fill = (items) => split.parts.length === 0 ? doc.value : split.fill(items);
4020
+ return {
4021
+ kind: seen.kindText,
4022
+ typePath: seen.typePath,
4023
+ doc,
4024
+ value: fill(parts),
4025
+ data: split.data,
4026
+ parts,
4027
+ context: at.ctx,
4028
+ place: at.place,
4029
+ resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
4030
+ effect: function* (kind, payload) {
4031
+ return record(env, at.ctx, kind, payload, at.place) ?? ok(payload);
4032
+ },
4033
+ all: (list, options) => together(list, options),
4034
+ fill
4035
+ };
4036
+ }
4037
+ /**
4038
+ * This function evaluates parts for `all` (RUN.ALL). The parts start in their order, up to the limit, and each part
4039
+ * goes on until it ends or waits. In an evaluation, a part that waits does not end, thus it keeps its place in the
4040
+ * limit. With `failFast`, the first failure stops the parts that wait, and the later parts do not start
4041
+ * (RUN.FAIL-FAST). When no part failed and a part waits, the steps wait, and the drive gives `#CALC!`.
4042
+ */
4043
+ function* together(list, options = {}) {
4044
+ const limit = Math.max(1, options.concurrency ?? list.length);
4045
+ const results = list.map(() => void 0);
4046
+ const waiting = [];
4047
+ let failed = false;
4048
+ for (let index = 0; index < list.length && !failed && waiting.length < limit; index += 1) {
4049
+ let result;
4050
+ try {
4051
+ const steps = list[index].evaluate();
4052
+ const step = steps.next();
4053
+ if (step.done === true) result = step.value;
4054
+ else waiting.push({
4055
+ steps,
4056
+ promise: step.value
4057
+ });
4058
+ } catch (error) {
4059
+ result = thrown(error, "a part");
4060
+ }
4061
+ results[index] = result;
4062
+ if (result !== void 0 && options.failFast === true && !result.ok) failed = true;
4063
+ }
4064
+ if (failed) {
4065
+ const stopped = fail("#ABORT", "The part stopped: a part before it failed, and the parts run with failFast.");
4066
+ for (const item of waiting) try {
4067
+ item.steps.return(stopped);
4068
+ } catch {}
4069
+ return results.map((result) => result ?? stopped);
4070
+ }
4071
+ if (waiting.length > 0) yield Promise.race(waiting.map((item) => item.promise));
4072
+ return results;
4073
+ }
4074
+ /**
4075
+ * This function evaluates a document by the rules, without a compilation. It is the reference of the plans: a plan,
4076
+ * a traced plan and the second tier of a language must give its results. It covers evaluations, not runs: an effect
4077
+ * gives its payload, and a part that waits gives `#CALC!`.
4078
+ *
4079
+ * @param machine - The world and the code of the evaluators.
4080
+ * @param doc - The document.
4081
+ * @param context - The names and the capabilities at the root.
4082
+ * @param options - The type of a bare root value, the definitions of compiled code, and a list for the effects.
4083
+ * @returns The result.
4084
+ */
4085
+ function reference(machine, doc, context = makeContext(), options = {}) {
4086
+ const env = {
4087
+ machine,
4088
+ definitions: options.definitions ?? {},
4089
+ effects: options.effects ?? [],
4090
+ maxDepth: machine.maxDepth ?? 1e3
4091
+ };
4092
+ const ctx = context.world === null ? {
4093
+ ...context,
4094
+ world: worldThing(machine.world)
4095
+ } : context;
4096
+ try {
4097
+ return evaluateAt(env, {
4098
+ value: doc,
4099
+ place: [],
4100
+ declared: options.declaredType,
4101
+ depth: 0,
4102
+ address: false,
4103
+ ctx
4104
+ });
4105
+ } catch (error) {
4106
+ return placed(thrown(error, "the reference"), []);
4107
+ }
4108
+ }
4109
+ const CLOSURE$1 = Symbol.for("coeval.closure");
4110
+ /** This function sets an own field, also the field `__proto__` (SHAPE.PROTO). */
4111
+ function setField(target, key, value) {
4112
+ Object.defineProperty(target, key, {
4113
+ value,
4114
+ enumerable: true,
4115
+ writable: true,
4116
+ configurable: true
4117
+ });
4118
+ }
4119
+ function partNamed(parts, key) {
4120
+ return parts.find((part) => part.path.length === 1 && part.path[0] === key);
4121
+ }
4122
+ function partsUnder(parts, key) {
4123
+ return parts.filter((part) => part.path.length === 2 && part.path[0] === key);
4124
+ }
4125
+ /**
4126
+ * This function gives the definitions of the formula kit for one profile. Each construct is a function evaluator in
4127
+ * the most direct style. It shares no code with the compilers of `formulaEvaluators`, thus the two readings of the
4128
+ * rules can disagree, and a test finds it.
4129
+ *
4130
+ * @param profile - The operations and the rules of the language.
4131
+ * @returns The definitions, by evaluator name.
4132
+ */
4133
+ function formulaDefinitions(profile = {}) {
4134
+ const truthy = profile.truthy ?? ((value) => typeof value === "boolean" ? value : void 0);
4135
+ const opOf = (name) => typeof profile.ops === "function" ? profile.ops(name) : own(profile.ops, name);
4136
+ const noTruth = (what) => fail("#VALUE!", `The ${what} must give a truth value.`);
4137
+ /** FORMULA.LIST, FORMULA.OPS and FORMULA.COMBINE: the values of parts in order, or the error. */
4138
+ const valuesOf = (parts, skip) => {
4139
+ const values = [];
4140
+ const errors = [];
4141
+ for (const part of parts) {
4142
+ const result = part.evaluate();
4143
+ if (result.ok) values.push(result.value);
4144
+ else if (skip?.(result.error) === true) values.push(SKIP);
4145
+ else if (profile.combine === void 0) return result;
4146
+ else errors.push(result.error);
4147
+ }
4148
+ if (errors.length === 0 || profile.combine === void 0) return { values };
4149
+ return {
4150
+ ok: false,
4151
+ error: errors.length === 1 ? errors[0] : profile.combine(errors)
4152
+ };
4153
+ };
4154
+ const lit = ({ doc }) => ok(doc.value);
4155
+ const ref = ({ doc, parts, fill, address, context, resolve: walk }) => {
4156
+ const path = doc.value;
4157
+ if (!Array.isArray(path) || path.length === 0) return fail("#VALUE!", "The value of ref is a path: a list that starts with a root, for example [\"names\", \"a\"].");
4158
+ let steps = path;
4159
+ if (parts.length > 0) {
4160
+ const all = valuesOfStrict(parts);
4161
+ if (!("values" in all)) return all;
4162
+ steps = fill(all.values);
4163
+ }
4164
+ const head = path[0] === "names" && typeof path[1] === "string" ? path[1] : void 0;
4165
+ const bound = head === void 0 ? void 0 : own(context.names, head);
4166
+ if (bound instanceof Held) return {
4167
+ ok: false,
4168
+ error: bound.error
4169
+ };
4170
+ const found = walk(steps);
4171
+ if (!found.ok) return fail(found.code, found.reason);
4172
+ if (address === true) return ok(found.thing);
4173
+ const reached = valueOfThing(found.thing);
4174
+ if (reached instanceof Held) return {
4175
+ ok: false,
4176
+ error: reached.error
4177
+ };
4178
+ if (profile.missing?.(reached) === true) return fail("#N/A", "The path reaches no value.");
4179
+ return ok(reached);
4180
+ };
4181
+ const step = ({ doc, parts, fill }) => {
4182
+ if (parts.length === 0) return ok(doc);
4183
+ const all = valuesOfStrict(parts);
4184
+ return "values" in all ? ok({
4185
+ ...doc,
4186
+ value: fill(all.values)
4187
+ }) : all;
4188
+ };
4189
+ const record = ({ parts }) => {
4190
+ const all = valuesOf(parts, profile.omit);
4191
+ if (!("values" in all)) return all;
4192
+ const out = {};
4193
+ parts.forEach((part, index) => {
4194
+ const value = all.values[index];
4195
+ if (value !== SKIP) setField(out, String(part.path[0]), value);
4196
+ });
4197
+ return ok(out);
4198
+ };
4199
+ const list = ({ parts }) => {
4200
+ const all = valuesOf(parts);
4201
+ return "values" in all ? ok([...all.values]) : all;
4202
+ };
4203
+ const letIn = ({ parts, context }) => {
4204
+ const names = {};
4205
+ for (const key of Object.keys(context.names)) setField(names, key, context.names[key]);
4206
+ for (const binding of partsUnder(parts, "bind")) {
4207
+ const result = binding.evaluate();
4208
+ setField(names, String(binding.path[1]), result.ok ? result.value : new Held(result.error));
4209
+ }
4210
+ return partNamed(parts, "body").evaluate({
4211
+ ...context,
4212
+ names
4213
+ });
4214
+ };
4215
+ const fn = ({ data, parts, context }) => {
4216
+ const params = isRecord(data) ? data["params"] : void 0;
4217
+ 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.");
4218
+ const names = params;
4219
+ const body = partNamed(parts, "body");
4220
+ const closure = (...args) => {
4221
+ const scope = {};
4222
+ for (const key of Object.keys(context.names)) setField(scope, key, context.names[key]);
4223
+ names.forEach((name, index) => setField(scope, name, args[index]));
4224
+ const result = body.evaluate({
4225
+ ...context,
4226
+ names: scope
4227
+ });
4228
+ if (!result.ok) throw new Failure(result.error);
4229
+ return result.value;
4230
+ };
4231
+ Object.defineProperty(closure, CLOSURE$1, { value: { params: names } });
4232
+ return ok(closure);
4233
+ };
4234
+ const call = ({ parts }) => {
4235
+ const target = partNamed(parts, "fn").evaluate();
4236
+ if (!target.ok) return target;
4237
+ if (typeof target.value !== "function") return fail("#VALUE!", "The fn of call must give a function.");
4238
+ const all = valuesOfStrict(partsUnder(parts, "args"));
4239
+ if (!("values" in all)) return all;
4240
+ try {
4241
+ return ok(target.value(...all.values));
4242
+ } catch (error) {
4243
+ return thrown(error, "the function of call");
4244
+ }
4245
+ };
4246
+ const choice = ({ parts }) => {
4247
+ const test = partNamed(parts, "test").evaluate();
4248
+ if (!test.ok) return test;
4249
+ const truth = truthy(test.value);
4250
+ if (truth === void 0) return noTruth("test of if");
4251
+ if (truth) return partNamed(parts, "then").evaluate();
4252
+ const other = partNamed(parts, "else");
4253
+ if (other !== void 0) return other.evaluate();
4254
+ return ok(Object.hasOwn(profile, "otherwise") ? profile.otherwise : null);
4255
+ };
4256
+ /** FORMULA.LOGIC: `and` stops at the first false term, and `or` at the first true term. */
4257
+ const logic = (stopAt, what) => ({ parts }) => {
4258
+ let last = ok(!stopAt);
4259
+ for (const part of parts) {
4260
+ last = part.evaluate();
4261
+ if (!last.ok) return last;
4262
+ const truth = truthy(last.value);
4263
+ if (truth === void 0) return noTruth(what);
4264
+ if (truth === stopAt) return profile.logic === "value" ? last : ok(stopAt);
4265
+ }
4266
+ return profile.logic === "value" ? last : ok(!stopAt);
4267
+ };
4268
+ const op = ({ typePath, parts }) => {
4269
+ const name = typePath.slice(1).join(".");
4270
+ const lazy = own(profile.lazy, name);
4271
+ if (lazy !== void 0) try {
4272
+ return lazy(parts.map((part) => () => part.evaluate()));
4273
+ } catch (error) {
4274
+ return thrown(error, `the operation ${name}`);
4275
+ }
4276
+ const apply = opOf(name);
4277
+ if (apply === void 0) return fail("#NAME?", `The language has no operation ${name}.`);
4278
+ const all = valuesOf(parts);
4279
+ if (!("values" in all)) return all;
4280
+ try {
4281
+ const out = apply(...all.values);
4282
+ return profile.check?.(out, name) ?? ok(out);
4283
+ } catch (error) {
4284
+ return thrown(error, `the operation ${name}`);
4285
+ }
4286
+ };
4287
+ const ext = ({ typePath, doc, context }) => {
4288
+ const name = typePath.slice(1).join(".");
4289
+ const handler = own(profile.ext, name) ?? own(STD_EXT, name);
4290
+ if (handler === void 0) return fail("#NAME?", `The language has no extension ${name}.`);
4291
+ try {
4292
+ return handler(doc.value, context);
4293
+ } catch (error) {
4294
+ return thrown(error, `the extension ${name}`);
4295
+ }
4296
+ };
4297
+ return { evaluators: {
4298
+ "formula.lit": lit,
4299
+ "formula.ref": ref,
4300
+ "formula.step": step,
4301
+ "formula.record": record,
4302
+ "formula.list": list,
4303
+ "formula.let": letIn,
4304
+ "formula.fn": fn,
4305
+ "formula.call": call,
4306
+ "formula.if": choice,
4307
+ "formula.and": logic(false, "term of and"),
4308
+ "formula.or": logic(true, "term of or"),
4309
+ "formula.op": op,
4310
+ "formula.ext": ext
4311
+ } };
4312
+ }
4313
+ /** The mark of a field that the profile leaves out of a record (FORMULA.RECORD). */
4314
+ const SKIP = Symbol("skip");
4315
+ /** The values of parts in order. The first error stops them, also with `combine` (FORMULA.STEPS, FORMULA.FN). */
4316
+ function valuesOfStrict(parts) {
4317
+ const values = [];
4318
+ for (const part of parts) {
4319
+ const result = part.evaluate();
4320
+ if (!result.ok) return result;
4321
+ values.push(result.value);
4322
+ }
4323
+ return { values };
4324
+ }
4325
+ //#endregion
4326
+ //#region src/agree.ts
4327
+ /**
4328
+ * This function tells if two values are the same for `agree`. Lists and plain records compare item by item and field
4329
+ * by field, and the order of the fields does not matter. Each other leaf compares with `Object.is`, thus `-0` is not
4330
+ * `0`, and `NaN` is `NaN`. Two closures of `fn` are the same when they have the same parameters. Two `Held` values
4331
+ * are the same when their errors have the same code and place. Identity is not compared.
4332
+ *
4333
+ * @param a - The first value.
4334
+ * @param b - The second value.
4335
+ * @param equal - The rule of the caller for other values. It answers first, and `undefined` gives the rules above.
4336
+ * @returns `true` when the values are the same.
4337
+ */
4338
+ function sameValue(a, b, equal) {
4339
+ const stack = [[a, b]];
4340
+ const seen = /* @__PURE__ */ new Map();
4341
+ while (stack.length > 0) {
4342
+ const [x, y] = stack.pop();
4343
+ if (Object.is(x, y)) continue;
4344
+ const told = equal?.(x, y);
4345
+ if (told !== void 0) {
4346
+ if (told) continue;
4347
+ return false;
4348
+ }
4349
+ if (typeof x !== "object" && typeof x !== "function") return false;
4350
+ if (typeof y !== "object" && typeof y !== "function") return false;
4351
+ if (x === null || y === null) return false;
4352
+ const pairs = seen.get(x) ?? /* @__PURE__ */ new Set();
4353
+ if (pairs.has(y)) continue;
4354
+ pairs.add(y);
4355
+ seen.set(x, pairs);
4356
+ if (isClosure(x) || isClosure(y)) {
4357
+ if (!(isClosure(x) && isClosure(y))) return false;
4358
+ stack.push([closureParams(x), closureParams(y)]);
4359
+ continue;
4360
+ }
4361
+ if (x instanceof Held || y instanceof Held) {
4362
+ if (!(x instanceof Held && y instanceof Held) || errorDiffers(x.error, y.error, false) !== void 0) return false;
4363
+ continue;
4364
+ }
4365
+ if (Array.isArray(x) || Array.isArray(y)) {
4366
+ if (!Array.isArray(x) || !Array.isArray(y) || x.length !== y.length) return false;
4367
+ for (let index = 0; index < x.length; index += 1) stack.push([x[index], y[index]]);
4368
+ continue;
4369
+ }
4370
+ if (!isRecord(x) || !isRecord(y)) return false;
4371
+ const keys = Object.keys(x);
4372
+ if (keys.length !== Object.keys(y).length) return false;
4373
+ for (const key of keys) {
4374
+ if (!Object.hasOwn(y, key)) return false;
4375
+ stack.push([x[key], y[key]]);
4376
+ }
4377
+ }
4378
+ return true;
4379
+ }
4380
+ const CLOSURE = Symbol.for("coeval.closure");
4381
+ function closureParams(fn) {
4382
+ return fn[CLOSURE]?.params;
4383
+ }
4384
+ function codeAndPlace(error) {
4385
+ return error.place === void 0 ? error.code : `${error.code} at [${error.place.join(", ")}]`;
4386
+ }
4387
+ /** This function gives the difference of two errors, or `undefined` when they agree. */
4388
+ function errorDiffers(a, b, strict) {
4389
+ if (a.code !== b.code) return `The plan gives ${codeAndPlace(a)}, and the tier gives ${codeAndPlace(b)}.`;
4390
+ if (strict && (a.place === void 0 || b.place === void 0)) return `An error ${a.code} has no place.`;
4391
+ if (a.place !== void 0 && b.place !== void 0 && !docEquals(a.place, b.place)) return `The error ${a.code} has the place [${a.place.join(", ")}] in the plan, and [${b.place.join(", ")}] in the tier.`;
4392
+ if (strict && a.reason !== b.reason) return `The error ${a.code} has another reason in the tier: "${b.reason}" for "${a.reason}".`;
4393
+ }
4394
+ /** A host stack overflow is the one permitted difference (VALUE.DEPTH): the tiers use different numbers of frames. */
4395
+ function overflowed(result) {
4396
+ return !result.ok && result.error.code === "#DEPTH!" && isStackOverflow(result.error.cause);
4397
+ }
4398
+ /** This function gives the difference of two results, or `undefined` when they agree. */
4399
+ function resultDiffers(a, b, options) {
4400
+ if (a.ok && b.ok) return sameValue(a.value, b.value, options.equal) ? void 0 : "The plan and the tier give different values.";
4401
+ if (!a.ok && !b.ok) return errorDiffers(a.error, b.error, options.strict === true);
4402
+ return a.ok ? `The plan gives a value, and the tier gives ${codeAndPlace(b.error)}.` : `The plan gives ${codeAndPlace(a.error)}, and the tier gives a value.`;
4403
+ }
4404
+ /** This function gives the difference of two lists of effects, or `undefined` when they agree (EFFECT.ORDER). */
4405
+ function effectsDiffer(a, b, options) {
4406
+ if (a.length !== b.length) return `The plan causes ${a.length} effects, and the tier causes ${b.length}.`;
4407
+ for (let index = 0; index < a.length; index += 1) {
4408
+ const x = a[index];
4409
+ const y = b[index];
4410
+ if (x.kind !== y.kind || !docEquals(x.place, y.place) || !sameValue(x.payload, y.payload, options.equal)) return `The effect ${index} differs: ${x.kind} at [${x.place.join(", ")}] in the plan, and ${y.kind} at [${y.place.join(", ")}] in the tier.`;
4411
+ }
4412
+ }
4413
+ /**
4414
+ * This function evaluates a document with a plan and with other tiers, and compares the results (PLAN.AGREES). Two
4415
+ * results agree when they have the same value by `sameValue`, or errors with the same code, and the same place when
4416
+ * both have one. The effects must have the same kinds, places and payloads, in the same order. A language gives its
4417
+ * own tier with the option `other`.
4418
+ *
4419
+ * @param machine - The world and the code of the evaluators.
4420
+ * @param doc - The document.
4421
+ * @param context - The names and the capabilities at the root.
4422
+ * @param options - The tiers, the definitions for the reference, the rules of the comparison and the second tier.
4423
+ * @returns The result of the plan, or the first tier that disagrees and the reason.
4424
+ */
4425
+ function agree(machine, doc, context = makeContext(), options = {}) {
4426
+ const declared = options.declaredType === void 0 ? {} : { declaredType: options.declaredType };
4427
+ const observe = options.observe;
4428
+ observe?.();
4429
+ const plan = prepare(machine, doc, declared);
4430
+ const effects = [];
4431
+ const result = plan.evaluate(context, { effects });
4432
+ const saw = observe?.();
4433
+ const differs = (other, otherEffects) => {
4434
+ if (overflowed(result) || overflowed(other)) return void 0;
4435
+ const why = resultDiffers(result, other, options) ?? (otherEffects === void 0 ? void 0 : effectsDiffer(effects, otherEffects, options));
4436
+ if (why !== void 0 || observe === void 0) return why;
4437
+ return sameValue(saw, observe(), options.equal) ? void 0 : "The host saw other calls in the tier.";
4438
+ };
4439
+ for (const tier of options.tiers ?? [
4440
+ "reference",
4441
+ "traced",
4442
+ "again"
4443
+ ]) {
4444
+ let other;
4445
+ let otherEffects = [];
4446
+ if (tier === "reference") other = reference(machine, doc, context, {
4447
+ ...declared,
4448
+ effects: otherEffects,
4449
+ ...options.definitions === void 0 ? {} : { definitions: options.definitions }
4450
+ });
4451
+ else if (tier === "traced") {
4452
+ const traced = evaluate(machine, doc, context, options.declaredType);
4453
+ other = traced.result;
4454
+ otherEffects = [...traced.effects];
4455
+ } else other = plan.evaluate(context, { effects: otherEffects });
4456
+ const why = differs(other, otherEffects);
4457
+ if (why !== void 0) return {
4458
+ ok: false,
4459
+ tier,
4460
+ plan: result,
4461
+ other,
4462
+ reason: why
4463
+ };
4464
+ }
4465
+ if (options.other !== void 0) {
4466
+ let given;
4467
+ try {
4468
+ given = options.other(doc, context);
4469
+ } catch (error) {
4470
+ given = thrown(error, "the tier");
4471
+ }
4472
+ const other = "result" in given ? given.result : given;
4473
+ const why = differs(other, "result" in given ? given.effects : void 0);
4474
+ if (why !== void 0) return {
4475
+ ok: false,
4476
+ tier: "other",
4477
+ plan: result,
4478
+ other,
4479
+ reason: why
4480
+ };
4481
+ }
4482
+ return {
4483
+ ok: true,
4484
+ result,
4485
+ effects
4486
+ };
4487
+ }
4488
+ //#endregion
4489
+ //#region src/generate.ts
4490
+ /**
4491
+ * This function makes a source of random numbers with a seed (the algorithm mulberry32). It needs no package.
4492
+ *
4493
+ * @param seed - The seed: a whole number.
4494
+ * @returns The source.
4495
+ */
4496
+ function random(seed) {
4497
+ let state = seed >>> 0;
4498
+ const next = () => {
4499
+ state = state + 1831565813 >>> 0;
4500
+ let t = state;
4501
+ t = Math.imul(t ^ t >>> 15, t | 1);
4502
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
4503
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
4504
+ };
4505
+ const int = (below) => Math.floor(next() * below);
4506
+ return {
4507
+ next,
4508
+ int,
4509
+ chance: (p) => next() < p,
4510
+ pick: (items) => items[int(items.length)]
4511
+ };
4512
+ }
4513
+ /**
4514
+ * This function lists the types of a world: each kind and each alias, also in a namespace. A namespace with a
4515
+ * fallback gives no types, because each key names a kind.
4516
+ *
4517
+ * @param world - The world.
4518
+ * @returns The keys of each type.
4519
+ */
4520
+ function typesOf(world) {
4521
+ const out = [];
4522
+ const visit = (entries, prefix) => {
4523
+ for (const key of Object.keys(entries)) {
4524
+ const entry = entries[key];
4525
+ if (isKind(entry) || isAlias(entry)) out.push([...prefix, key]);
4526
+ else if (isNamespace(entry)) visit(entry.kinds, [...prefix, key]);
4527
+ }
4528
+ };
4529
+ visit(world.kinds, []);
4530
+ return out;
4531
+ }
4532
+ const NAMES = [
4533
+ "a",
4534
+ "b",
4535
+ "x",
4536
+ "n",
4537
+ "last",
4538
+ "__proto__"
4539
+ ];
4540
+ const FIELDS = [
4541
+ "a",
4542
+ "b",
4543
+ "c",
4544
+ "1",
4545
+ "__proto__"
4546
+ ];
4547
+ const KEYS = [
4548
+ "a",
4549
+ "b",
4550
+ "x",
4551
+ 0,
4552
+ 1,
4553
+ "0",
4554
+ "length",
4555
+ "type",
4556
+ "value",
4557
+ "parent"
4558
+ ];
4559
+ /** This function tells if a kind can be a leaf: it needs no part. */
4560
+ function leafKind(kind) {
4561
+ const shape = kind?.parts;
4562
+ return shape === void 0 || shape.shape === "none" || shape.shape === "list" || shape.shape === "map" || shape.shape === "text" || shape.shape === "number" || shape.shape === "one";
4563
+ }
4564
+ /**
4565
+ * This function builds a random document for a world from the contracts of its kinds. It reads the shapes of the
4566
+ * parts, the declared types, the permitted kinds and the names that the scope rules bind. Some choices are malformed
4567
+ * on purpose. Examples are an unknown kind, a value without its shape, a bare value without a type and a name that
4568
+ * nothing binds. The depth and the size have limits.
4569
+ *
4570
+ * @param world - The world.
4571
+ * @param options - The seed, the types, the limits and the data of the leaves.
4572
+ * @returns The document, as JSON.
4573
+ */
4574
+ function generate(world, options) {
4575
+ const rng = random(options.seed);
4576
+ const types = options.types ?? typesOf(world);
4577
+ const maxDepth = options.maxDepth ?? 4;
4578
+ const maxSize = options.maxSize ?? 24;
4579
+ const malformed = options.malformed ?? .05;
4580
+ const keys = options.keys ?? KEYS;
4581
+ const stepTypes = types.filter((type) => {
4582
+ const found = lookupKind(world, type);
4583
+ return found.ok && Object.hasOwn(found.kind.verbs, "step");
4584
+ });
4585
+ let size = 0;
4586
+ const kindOf = (type) => {
4587
+ const found = lookupKind(world, type);
4588
+ return found.ok ? found.kind : void 0;
4589
+ };
4590
+ const anyJson = (depth = 0) => {
4591
+ const roll = rng.int(depth > 1 ? 6 : 8);
4592
+ if (roll === 0) return null;
4593
+ if (roll === 1) return rng.chance(.5);
4594
+ if (roll === 2) return rng.pick([
4595
+ 0,
4596
+ 1,
4597
+ 2,
4598
+ -1,
4599
+ .5,
4600
+ 1e21
4601
+ ]);
4602
+ if (roll === 3) return rng.pick([
4603
+ "",
4604
+ "a",
4605
+ "text",
4606
+ "0"
4607
+ ]);
4608
+ if (roll === 4) return rng.int(10);
4609
+ if (roll === 5) return rng.pick(NAMES);
4610
+ if (roll === 6) return Array.from({ length: rng.int(3) }, () => anyJson(depth + 1));
4611
+ const out = {};
4612
+ for (let index = rng.int(3); index > 0; index -= 1) Object.defineProperty(out, rng.pick(FIELDS), {
4613
+ value: anyJson(depth + 1),
4614
+ enumerable: true,
4615
+ writable: true,
4616
+ configurable: true
4617
+ });
4618
+ return out;
4619
+ };
4620
+ const dataOf = (type) => options.data?.(type, rng) ?? anyJson();
4621
+ const renderType = (type) => {
4622
+ const roll = rng.next();
4623
+ if (roll < .06) return {
4624
+ type: "ref",
4625
+ value: ["world", ...type]
4626
+ };
4627
+ if (type.length === 1 && roll < .8) return type[0];
4628
+ return [...type];
4629
+ };
4630
+ const permitted = (type, kinds) => kinds === void 0 || kinds.some((kind) => kind.length <= type.length && kind.every((key, index) => String(key) === String(type[index])));
4631
+ const pickName = (names) => names.length === 0 || rng.chance(malformed) ? rng.pick(["unbound", "zz"]) : rng.pick(names);
4632
+ const someNames = () => {
4633
+ const out = /* @__PURE__ */ new Set();
4634
+ for (let index = 1 + rng.int(2); index > 0; index -= 1) out.add(rng.pick(NAMES));
4635
+ return [...out];
4636
+ };
4637
+ const envelope = (type, value, header) => {
4638
+ const out = {
4639
+ type: renderType(type),
4640
+ value
4641
+ };
4642
+ if (header !== void 0) out["name"] = header;
4643
+ if (options.own !== void 0 && options.own.length > 0 && rng.chance(.03)) out["own"] = { eval: rng.pick(options.own) };
4644
+ return out;
4645
+ };
4646
+ /** A path from a root (D10). It uses the names in scope, and sometimes a step document. */
4647
+ const pathFor = (pos, refKind) => {
4648
+ if (rng.chance(malformed)) return rng.pick([
4649
+ "names",
4650
+ [],
4651
+ { names: "a" },
4652
+ ["nowhere", "a"]
4653
+ ]);
4654
+ const root = pos.names.length > 0 && rng.chance(.75) ? "names" : rng.pick(ROOTS.filter((name) => name !== "names"));
4655
+ const path = [root];
4656
+ if (root === "names") path.push(pickName(pos.names));
4657
+ if (root === "world") path.push(String(rng.pick(types)[0]));
4658
+ for (let index = rng.int(3); index > 0; index -= 1) if (stepTypes.length > 0 && rng.chance(.2)) {
4659
+ const type = rng.pick(stepTypes);
4660
+ const kind = kindOf(type);
4661
+ const value = refKind?.parts?.shape === "deep" && kind?.parts !== void 0 ? valueOf(kind.parts, [], {
4662
+ ...pos,
4663
+ depth: pos.depth + 1
4664
+ }, emptyScope()) : dataOf(type);
4665
+ path.push({
4666
+ type: renderType(type),
4667
+ value
4668
+ });
4669
+ } else path.push(rng.pick(keys));
4670
+ return path;
4671
+ };
4672
+ const emptyScope = () => ({
4673
+ rules: [],
4674
+ names: [],
4675
+ covered: [],
4676
+ sources: /* @__PURE__ */ new Map()
4677
+ });
4678
+ /** This function decides the names of the scope rules before the parts, so that each part knows what it sees. */
4679
+ const scopeOf = (kind) => {
4680
+ const rules = kind.scope ?? [];
4681
+ const scope = {
4682
+ rules,
4683
+ names: [],
4684
+ covered: rules.map(() => 0),
4685
+ sources: /* @__PURE__ */ new Map()
4686
+ };
4687
+ for (const rule of rules) {
4688
+ const source = rule.names;
4689
+ let names = [];
4690
+ if ("fixed" in source) names = [...source.fixed];
4691
+ else if ("keysAt" in source) {
4692
+ names = someNames();
4693
+ scope.sources.set(source.keysAt.join("."), { keys: names });
4694
+ } else if ("listAt" in source) {
4695
+ names = someNames();
4696
+ scope.sources.set(source.listAt.join("."), { list: rng.chance(malformed) ? [...names, ...names] : names });
4697
+ } else if ("textAt" in source) {
4698
+ names = [rng.pick(NAMES)];
4699
+ scope.sources.set(source.textAt.join("."), { text: names[0] });
4700
+ }
4701
+ scope.names.push(names);
4702
+ }
4703
+ return scope;
4704
+ };
4705
+ /** The names that a part sees from the scope rules of its parent. A rule `sequential` shows only earlier names. */
4706
+ const seenBy = (scope, path) => {
4707
+ const names = [];
4708
+ let headers = false;
4709
+ scope.rules.forEach((rule, index) => {
4710
+ if (!rule.in.some((pattern) => pathMatches(path, pattern))) return;
4711
+ const ruleNames = scope.names[index] ?? [];
4712
+ if ("headers" in rule.names) headers = true;
4713
+ if (rule.sequential !== true || "headers" in rule.names || (scope.covered[index] ?? 0) > 0) names.push(...ruleNames);
4714
+ });
4715
+ return {
4716
+ names,
4717
+ headers
4718
+ };
4719
+ };
4720
+ /** This function records the part at a path, and the header name that it got, for the rules that cover it. */
4721
+ const saw = (scope, path, part) => {
4722
+ const header = isEnvelope(part) && typeof part.name === "string" ? part.name : void 0;
4723
+ scope.rules.forEach((rule, index) => {
4724
+ if (!rule.in.some((pattern) => pathMatches(path, pattern))) return;
4725
+ scope.covered[index] = (scope.covered[index] ?? 0) + 1;
4726
+ if ("headers" in rule.names && header !== void 0) scope.names[index]?.push(header);
4727
+ });
4728
+ };
4729
+ const partAt = (pos, scope, path, spec, parentType) => {
4730
+ const seen = seenBy(scope, path);
4731
+ const header = seen.headers && rng.chance(.5) ? rng.pick(NAMES) : void 0;
4732
+ const part = docAt({
4733
+ declared: spec.of,
4734
+ kinds: "kinds" in spec ? spec.kinds : void 0,
4735
+ names: seen.names.length === 0 ? pos.names : [...pos.names, ...seen.names],
4736
+ depth: pos.depth + 1,
4737
+ hint: parentType === void 0 ? void 0 : options.hints?.(parentType, path)
4738
+ }, header);
4739
+ saw(scope, path, part);
4740
+ return part;
4741
+ };
4742
+ /** This function builds a value of a shape (SHAPE.*). A part is a document at the next depth. */
4743
+ const valueOf = (shape, path, pos, scope, type) => {
4744
+ const source = scope.sources.get(path.join("."));
4745
+ if (source !== void 0 && "list" in source) return [...source.list];
4746
+ if (source !== void 0 && "text" in source) return source.text;
4747
+ const term = (of) => of === void 0 ? { shape: "term" } : {
4748
+ shape: "term",
4749
+ of
4750
+ };
4751
+ const small = () => pos.depth >= maxDepth ? 0 : size >= maxSize ? rng.int(2) : rng.int(4);
4752
+ if (shape === void 0 || shape.shape === "none") return path.length === 0 && type !== void 0 ? dataOf(type) : anyJson();
4753
+ switch (shape.shape) {
4754
+ case "term": return partAt(pos, scope, path, shape, type);
4755
+ case "list": {
4756
+ const items = Array.from({ length: small() }, (_, index) => valueOf(shape.item ?? term(shape.of), [...path, index], pos, scope, type));
4757
+ if (shape.distinct !== true || rng.chance(malformed)) return items;
4758
+ return items.filter((item, index) => !items.slice(0, index).some((before) => docEquals(before, item)));
4759
+ }
4760
+ case "map": {
4761
+ const out = {};
4762
+ const names = source !== void 0 && "keys" in source ? source.keys : Array.from({ length: small() }, () => rng.pick(FIELDS));
4763
+ for (const key of names) Object.defineProperty(out, key, {
4764
+ value: valueOf(shape.item ?? term(shape.of), [...path, key], pos, scope, type),
4765
+ enumerable: true,
4766
+ writable: true,
4767
+ configurable: true
4768
+ });
4769
+ return out;
4770
+ }
4771
+ case "record": {
4772
+ const named = Array.isArray(shape.fields) ? Object.fromEntries(shape.fields.map((name) => [name, term(shape.of)])) : shape.fields;
4773
+ const fieldKeys = /* @__PURE__ */ new Set([...shape.required ?? [], ...Object.keys(named).filter(() => rng.chance(.75))]);
4774
+ if (shape.closed !== true && shape.rest === void 0 && rng.chance(.15)) fieldKeys.add("extra");
4775
+ const ordered = rng.chance(.2) ? [...fieldKeys].reverse() : [...fieldKeys];
4776
+ const out = {};
4777
+ for (const key of ordered) {
4778
+ if (rng.chance(malformed / 2) && (shape.required ?? []).includes(key)) continue;
4779
+ const fieldShape = Object.hasOwn(named, key) ? named[key] : shape.rest;
4780
+ Object.defineProperty(out, key, {
4781
+ value: valueOf(fieldShape, [...path, key], pos, scope, type),
4782
+ enumerable: true,
4783
+ writable: true,
4784
+ configurable: true
4785
+ });
4786
+ }
4787
+ if (shape.closed === true && rng.chance(malformed)) out["stray"] = 1;
4788
+ return out;
4789
+ }
4790
+ case "deep": return rng.chance(.5) ? [partAt(pos, scope, [...path, 0], term(shape.of), type), anyJson()] : {
4791
+ at: partAt(pos, scope, [...path, "at"], term(shape.of), type),
4792
+ data: anyJson()
4793
+ };
4794
+ case "text": return rng.chance(malformed) ? 1 : rng.pick([
4795
+ "",
4796
+ "a",
4797
+ "label"
4798
+ ]);
4799
+ case "number": {
4800
+ if (rng.chance(malformed)) return "1";
4801
+ const value = (shape.min ?? -2) + rng.int(5) + (shape.whole === true ? 0 : rng.pick([0, .5]));
4802
+ return shape.max !== void 0 && value > shape.max ? shape.max : value;
4803
+ }
4804
+ case "one": return rng.chance(malformed) ? "other" : rng.pick(shape.values);
4805
+ }
4806
+ };
4807
+ /** A malformed document: an unknown kind, a bad shape, a bare value without a type, or a bad reference. */
4808
+ const brokenAt = (pos) => {
4809
+ const roll = rng.int(5);
4810
+ if (roll === 0) return {
4811
+ type: rng.pick(["nothing", ["no", "such"]]),
4812
+ value: 1
4813
+ };
4814
+ if (roll === 1) return pos.declared === void 0 ? rng.pick([
4815
+ 7,
4816
+ "bare",
4817
+ [1]
4818
+ ]) : {
4819
+ type: "ref",
4820
+ value: ["names", "unbound"]
4821
+ };
4822
+ if (roll === 2) {
4823
+ const shaped = types.filter((type) => kindOf(type)?.parts !== void 0);
4824
+ if (shaped.length > 0) return envelope(rng.pick(shaped), rng.pick([
4825
+ 7,
4826
+ "x",
4827
+ null
4828
+ ]));
4829
+ }
4830
+ if (roll === 3) return {
4831
+ type: "ref",
4832
+ value: rng.pick([
4833
+ ["names", "unbound"],
4834
+ ["nowhere"],
4835
+ "names"
4836
+ ])
4837
+ };
4838
+ return {
4839
+ type: rng.pick(types),
4840
+ value: anyJson()
4841
+ };
4842
+ };
4843
+ const docAt = (pos, header) => {
4844
+ size += 1;
4845
+ const leaf = pos.depth >= maxDepth || size >= maxSize;
4846
+ if (rng.chance(malformed)) return brokenAt(pos);
4847
+ if (pos.declared !== void 0 && rng.chance(leaf ? .7 : .3)) return dataOf([pos.declared]);
4848
+ let candidates = types.filter((type) => permitted(type, pos.kinds) && (!leaf || leafKind(kindOf(type))));
4849
+ if (pos.hint !== void 0 && rng.chance(.6)) {
4850
+ const hinted = candidates.filter((type) => pos.hint?.some((hint) => hint.length === type.length && hint.every((key, index) => key === type[index])));
4851
+ if (hinted.length > 0) candidates = hinted;
4852
+ }
4853
+ if (candidates.length === 0) candidates = [...types];
4854
+ const type = rng.pick(candidates);
4855
+ const kind = kindOf(type);
4856
+ if (type.length === 1 && type[0] === "ref") return envelope(type, pathFor(pos, kind), header);
4857
+ const value = kind === void 0 ? dataOf(type) : valueOf(kind.parts, [], pos, scopeOf(kind), type);
4858
+ return envelope(type, value, header);
4859
+ };
4860
+ return docAt({
4861
+ declared: options.declaredType,
4862
+ kinds: void 0,
4863
+ names: options.names ?? [],
4864
+ depth: 0,
4865
+ hint: void 0
4866
+ });
4867
+ }
4868
+ //#endregion
4869
+ export { CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, agree, ask, capKeys, check, checkSteps, classify, context, dataEdges, derefStep, describe, docEquals, effectEdges, entriesAsJson, evaluate, fail, failures, field, flatten, formulaDefinitions, formulaEvaluators, formulaKinds, formulaMachine, fromJson, generate, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, narrow, nearestWalker, nodeAt, ok, partCaps, pathMatches, permits, placed, planner, prepare, random, ref, reference, refsOf, resolve, run, sameValue, splitParts, stored, tag, thrown, toJson, typeName, typePath, typed, typesOf, valueOfThing, walk, worldThing };
3799
4870
 
3800
4871
  //# sourceMappingURL=index.js.map