@mark1russell7/coeval 0.4.1 → 0.4.3

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
@@ -175,9 +175,17 @@ function fromJson(value) {
175
175
  });
176
176
  }
177
177
  /**
178
- * This function tells if two JSON values are equal. Equal values have the same texts, numbers and truth values,
179
- * the same items in the same order, and the same fields. The order of the fields does not matter. It does not use the stack for the
180
- * depth, thus a deep document cannot overflow it.
178
+ * This function tells if two values are equal. Plain JSON compares by its structure. Equal values have the same
179
+ * texts, numbers and truth values, the same items in the same order, and the same fields. The order of the fields
180
+ * does not matter. Each leaf compares with `Object.is`, thus `-0` is not `0`, and `NaN` is `NaN`.
181
+ *
182
+ * Only lists and plain records (`isRecord`) compare by their items and fields. Each other object compares by
183
+ * identity: a date, a map, a function and an instance of a class are equal only to themselves. Thus an early cutoff
184
+ * with this function does not keep a stale host value.
185
+ *
186
+ * The function does not use the stack for the depth, thus a deep document cannot overflow it. A cycle of lists or
187
+ * records does not make it loop. `sameValue` of `agree` uses the same rules, and it adds rules for closures and for
188
+ * a rule of the caller.
181
189
  *
182
190
  * @param a - The first value.
183
191
  * @param b - The second value.
@@ -185,15 +193,23 @@ function fromJson(value) {
185
193
  */
186
194
  function docEquals(a, b) {
187
195
  const stack = [[a, b]];
196
+ let seen;
188
197
  while (stack.length > 0) {
189
198
  const [x, y] = stack.pop();
190
199
  if (Object.is(x, y)) continue;
191
- if (typeof x !== "object" || typeof y !== "object" || x === null || y === null) return false;
192
- if (Array.isArray(x) !== Array.isArray(y)) return false;
193
- if (Array.isArray(x)) {
200
+ const list = Array.isArray(x);
201
+ if (list !== Array.isArray(y)) return false;
202
+ if (!list && (!isRecord(x) || !isRecord(y))) return false;
203
+ seen ??= /* @__PURE__ */ new Map();
204
+ const pairs = seen.get(x);
205
+ if (pairs?.has(y) === true) continue;
206
+ if (pairs === void 0) seen.set(x, /* @__PURE__ */ new Set([y]));
207
+ else pairs.add(y);
208
+ if (list) {
209
+ const xs = x;
194
210
  const ys = y;
195
- if (x.length !== ys.length) return false;
196
- for (let index = 0; index < x.length; index += 1) stack.push([x[index], ys[index]]);
211
+ if (xs.length !== ys.length) return false;
212
+ for (let index = 0; index < xs.length; index += 1) stack.push([xs[index], ys[index]]);
197
213
  continue;
198
214
  }
199
215
  const xr = x;
@@ -282,7 +298,11 @@ var Failure = class extends Error {
282
298
  * @returns `true` for a stack overflow.
283
299
  */
284
300
  function isStackOverflow(error) {
285
- return error instanceof RangeError && /call stack/i.test(error.message);
301
+ try {
302
+ return error instanceof RangeError && /call stack/i.test(error.message);
303
+ } catch {
304
+ return true;
305
+ }
286
306
  }
287
307
  /**
288
308
  * This function changes an exception into an error value. A `Failure` gives its error value. A stack overflow
@@ -1036,6 +1056,10 @@ const NO_SLOTS = Object.freeze([]);
1036
1056
  function hasSlots(template) {
1037
1057
  return template.t !== "data";
1038
1058
  }
1059
+ /** This function tells if a shape holds only data: no value of the shape can hold a part. */
1060
+ function isData(shape) {
1061
+ return shape.shape === "none" || shape.shape === "text" || shape.shape === "number" || shape.shape === "one";
1062
+ }
1039
1063
  /** This function gives the reason why a value is not data of a shape, or `undefined` when it is. */
1040
1064
  function dataFault(spec, item) {
1041
1065
  if (spec.shape === "text") return typeof item === "string" ? void 0 : "The value must be a text.";
@@ -1137,9 +1161,13 @@ function splitParts(shape, value) {
1137
1161
  shape: "term",
1138
1162
  ...spec.of === void 0 ? {} : { of: spec.of }
1139
1163
  };
1140
- return {
1164
+ const items = list.map((child, index) => walk(each, child, [...path, index]));
1165
+ return isData(each) ? {
1166
+ t: "data",
1167
+ value: item
1168
+ } : {
1141
1169
  t: "list",
1142
- items: list.map((child, index) => walk(each, child, [...path, index]))
1170
+ items
1143
1171
  };
1144
1172
  }
1145
1173
  if (!isRecord(item)) throw new Bad("The value must be a record.", path);
@@ -1207,6 +1235,54 @@ function splitParts(shape, value) {
1207
1235
  };
1208
1236
  }
1209
1237
  /**
1238
+ * This function reads one document by the contracts of the world. It finds the kind of the type. A bare value gets
1239
+ * the type that its position declares. Then the function splits the value by the shape of the kind. The plan, the
1240
+ * reference interpreter and the static kit read each document with this function. Thus they see the same parts.
1241
+ *
1242
+ * @param world - The world of the kinds.
1243
+ * @param value - The document, or a bare value.
1244
+ * @param declaredType - The type that the position of a bare value declares.
1245
+ * @returns The document, its kind and its parts, or the reason why the value is not a document.
1246
+ */
1247
+ function partsOf(world, value, declaredType) {
1248
+ const envelope = isEnvelope(value) ? value : void 0;
1249
+ if (envelope === void 0 && declaredType === void 0) return {
1250
+ ok: false,
1251
+ code: "#PART?",
1252
+ reason: "The value has no envelope, and its position declares no type."
1253
+ };
1254
+ const doc = envelope ?? {
1255
+ type: declaredType,
1256
+ value
1257
+ };
1258
+ const found = lookupKind(world, doc.type);
1259
+ const kind = found.ok ? found.kind : void 0;
1260
+ const split = splitParts(kind?.parts, doc.value);
1261
+ const typePath = found.ok ? found.path : void 0;
1262
+ if (split.ok) return {
1263
+ ok: true,
1264
+ doc,
1265
+ declared: envelope === void 0,
1266
+ kind,
1267
+ typePath,
1268
+ split
1269
+ };
1270
+ const where = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
1271
+ const reason = `${split.reason}${where} The kind is ${typeName(doc.type)}.`;
1272
+ return {
1273
+ ok: true,
1274
+ doc,
1275
+ declared: envelope === void 0,
1276
+ kind,
1277
+ typePath,
1278
+ split: {
1279
+ ok: false,
1280
+ reason,
1281
+ at: split.at
1282
+ }
1283
+ };
1284
+ }
1285
+ /**
1210
1286
  * This function tells if the path of a part matches a pattern of a scope rule. The key `"*"` of a pattern matches
1211
1287
  * each key.
1212
1288
  *
@@ -1543,7 +1619,7 @@ function holderNode() {
1543
1619
  };
1544
1620
  }
1545
1621
  /** This function drives steps that cannot wait. */
1546
- function drive(steps) {
1622
+ function drive$1(steps) {
1547
1623
  const step = steps.next();
1548
1624
  if (step.done === true) return step.value;
1549
1625
  step.value.catch(() => void 0);
@@ -1586,7 +1662,10 @@ function isCompiledRunner(runner) {
1586
1662
  return typeof runner === "object" && runner !== null && typeof runner.compileRun === "function";
1587
1663
  }
1588
1664
  function failing(c, meta, place, code, reason) {
1589
- const result = fail(code, reason, { place });
1665
+ return failingWith(c, meta, fail(code, reason, { place }));
1666
+ }
1667
+ /** This function gives the code of a document that fails with one result at each evaluation. */
1668
+ function failingWith(c, meta, result) {
1590
1669
  const plain = () => result;
1591
1670
  return finish(c, meta, plain, function* () {
1592
1671
  return result;
@@ -1648,15 +1727,15 @@ function finish(c, meta, code, run) {
1648
1727
  * This function finds the evaluator of the verb `eval` without the record of the rungs, for a compilation without a
1649
1728
  * trace. It gives the same evaluator as `ask`: the own entry, then the kind, then the default of the world.
1650
1729
  */
1651
- function evaluatorOf(world, envelope, found) {
1730
+ function evaluatorOf(world, envelope, kind) {
1652
1731
  const own = envelope?.own;
1653
1732
  const ownName = own !== void 0 && Object.hasOwn(own, "eval") ? own["eval"] : void 0;
1654
1733
  if (ownName !== void 0) return {
1655
1734
  name: ownName,
1656
1735
  unknown: false
1657
1736
  };
1658
- if (!found.ok) return { unknown: true };
1659
- const verbs = found.kind.verbs;
1737
+ if (kind === void 0) return { unknown: true };
1738
+ const verbs = kind.verbs;
1660
1739
  const name = Object.hasOwn(verbs, "eval") ? verbs["eval"] : Object.hasOwn(world.defaults, "eval") ? world.defaults["eval"] : void 0;
1661
1740
  return name === void 0 ? { unknown: false } : {
1662
1741
  name,
@@ -1675,23 +1754,28 @@ const NO_META = Object.freeze({
1675
1754
  side: "derive"
1676
1755
  });
1677
1756
  function compileNode(c, value, place, declared, depth, address = false) {
1678
- const envelope = isEnvelope(value) ? value : void 0;
1679
- const doc = envelope ?? {
1680
- type: declared ?? "?",
1681
- value
1682
- };
1757
+ const world = c.machine.world;
1758
+ const read = partsOf(world, value, declared);
1759
+ if (!read.ok) return failing(c, c.traced ? {
1760
+ path: place.map(String),
1761
+ doc: {
1762
+ type: "?",
1763
+ value
1764
+ },
1765
+ declared: true,
1766
+ answer: NO_ANSWER,
1767
+ side: "derive"
1768
+ } : NO_META, place, read.code, read.reason);
1769
+ const { doc, kind, split } = read;
1770
+ const envelope = read.declared ? void 0 : doc;
1683
1771
  const meta0 = c.traced ? {
1684
1772
  path: place.map(String),
1685
1773
  doc,
1686
- declared: envelope === void 0,
1774
+ declared: read.declared,
1687
1775
  answer: NO_ANSWER,
1688
1776
  side: "derive"
1689
1777
  } : NO_META;
1690
- if (envelope === void 0 && declared === void 0) return failing(c, meta0, place, "#PART?", "The value has no envelope, and its position declares no type.");
1691
1778
  if (depth > c.maxDepth) return failing(c, meta0, place, "#DEPTH!", `The nesting is deeper than ${c.maxDepth} documents.`);
1692
- const world = c.machine.world;
1693
- const found = lookupKind(world, doc.type);
1694
- const kind = found.ok ? found.kind : void 0;
1695
1779
  let meta = meta0;
1696
1780
  let name;
1697
1781
  let unknown;
@@ -1705,7 +1789,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
1705
1789
  name = answer.evaluator;
1706
1790
  unknown = answer.error === "unknown-kind";
1707
1791
  } else {
1708
- const quick = evaluatorOf(world, envelope, found);
1792
+ const quick = evaluatorOf(world, envelope, kind);
1709
1793
  name = quick.name;
1710
1794
  unknown = quick.unknown;
1711
1795
  }
@@ -1715,11 +1799,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
1715
1799
  const runner = name !== void 0 && Object.hasOwn(runners, name) ? runners[name] : void 0;
1716
1800
  const evaluator = name !== void 0 && Object.hasOwn(c.machine.evaluators, name) ? c.machine.evaluators[name] : void 0;
1717
1801
  if (name === void 0 || runner === void 0 && evaluator === void 0) return failing(c, meta, place, "#NOEVAL", `No rung gives an evaluator for ${kindText}.`);
1718
- const split = splitParts(kind?.parts, doc.value);
1719
- if (!split.ok) {
1720
- const at = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
1721
- return failing(c, meta, place, "#VALUE!", `${split.reason}${at} The kind is ${kindText}.`);
1722
- }
1802
+ if (!split.ok) return failing(c, meta, place, "#VALUE!", split.reason);
1723
1803
  const parts = split.parts.map((slot) => {
1724
1804
  const item = slot.item;
1725
1805
  const own = compileNode(c, item, place.concat(slot.path), slot.of, depth + 1, slot.address === true);
@@ -1741,7 +1821,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
1741
1821
  });
1742
1822
  const input = {
1743
1823
  kind: kindText,
1744
- typePath: found.ok ? found.path : [],
1824
+ typePath: read.typePath ?? [],
1745
1825
  doc,
1746
1826
  value: split.parts.length === 0 ? doc.value : split.fill(parts),
1747
1827
  data: split.data,
@@ -1752,10 +1832,22 @@ function compileNode(c, value, place, declared, depth, address = false) {
1752
1832
  ...address ? { address: true } : {}
1753
1833
  };
1754
1834
  if (runner !== void 0) {
1755
- const run = placedRun(isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill), place, name);
1835
+ let inner;
1836
+ try {
1837
+ inner = isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill);
1838
+ } catch (error) {
1839
+ return failingWith(c, meta, placed(thrown(error, `the runner ${name}`), place));
1840
+ }
1841
+ const run = placedRun(inner, place, name);
1756
1842
  return finish(c, meta, runnerCode(run, place, kindText), run);
1757
1843
  }
1758
- const code = placedCode(isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill), place, name);
1844
+ let inner;
1845
+ try {
1846
+ inner = isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill);
1847
+ } catch (error) {
1848
+ return failingWith(c, meta, placed(thrown(error, `the evaluator ${name}`), place));
1849
+ }
1850
+ const code = placedCode(inner, place, name);
1759
1851
  return finish(c, meta, code, runOf(code));
1760
1852
  }
1761
1853
  /** 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 +1889,12 @@ function placedRun(inner, place, name) {
1797
1889
  }
1798
1890
  };
1799
1891
  }
1800
- /** This function gives the code of a runner in an evaluation: its steps, which cannot wait. */
1892
+ /**
1893
+ * This function gives the code of a runner in an evaluation: its steps, which cannot wait. A step that waits gives
1894
+ * `#CALC!` at the place of the runner, where the error started (RUN.WAIT).
1895
+ */
1801
1896
  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));
1897
+ 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
1898
  }
1804
1899
  /** This function gives the steps of a run of an evaluator. The code runs at the first step, and it does not wait. */
1805
1900
  function runOf(code) {
@@ -1891,7 +1986,7 @@ function prepare(machine, doc, options = {}) {
1891
1986
  try {
1892
1987
  root = compileNode(c, doc, [], options.declaredType, 0);
1893
1988
  } catch (error) {
1894
- const result = thrown(error, "the compilation");
1989
+ const result = placed(thrown(error, "the compilation"), []);
1895
1990
  root = {
1896
1991
  code: () => result,
1897
1992
  run: function* () {
@@ -1952,7 +2047,7 @@ function planner(machine, options = {}) {
1952
2047
  return plan;
1953
2048
  };
1954
2049
  }
1955
- function record(s, result) {
2050
+ function record$1(s, result) {
1956
2051
  const root = s.holder?.children[0];
1957
2052
  if (root === void 0) throw new Error("The evaluation made no trace.");
1958
2053
  return {
@@ -1981,7 +2076,7 @@ function evaluate(machine, doc, context = makeContext(), declaredType) {
1981
2076
  ...declaredType === void 0 ? {} : { declaredType }
1982
2077
  });
1983
2078
  const s = new Session(machine, false, true, void 0, void 0, void 0);
1984
- return record(s, plan.root.code(rootContext(machine, context), s));
2079
+ return record$1(s, plan.root.code(rootContext(machine, context), s));
1985
2080
  }
1986
2081
  /**
1987
2082
  * This function runs a document: an evaluation in which the host does each effect. A runner waits for its
@@ -2000,7 +2095,7 @@ async function run(machine, doc, context = makeContext(), options = {}) {
2000
2095
  ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType }
2001
2096
  });
2002
2097
  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));
2098
+ return record$1(s, await driveWaiting(plan.root.run(rootContext(machine, context), s), options.signal));
2004
2099
  }
2005
2100
  /**
2006
2101
  * This function finds a node of a trace by its path.
@@ -2998,40 +3093,32 @@ function walk(world, doc, visit, options = {}) {
2998
3093
  }];
2999
3094
  while (stack.length > 0) {
3000
3095
  const item = stack.pop();
3001
- const envelope = isEnvelope(item.value) ? item.value : void 0;
3002
- if (envelope === void 0 && item.declared === void 0) {
3096
+ const read = partsOf(world, item.value, item.declared);
3097
+ if (!read.ok) {
3003
3098
  options.problem?.({
3004
3099
  place: keysOf(item.place),
3005
3100
  at: keysOf(item.at),
3006
- code: "#PART?",
3007
- reason: "The value has no envelope, and its position declares no type."
3101
+ code: read.code,
3102
+ reason: read.reason
3008
3103
  });
3009
3104
  continue;
3010
3105
  }
3011
- const doc = envelope ?? {
3012
- type: item.declared ?? "?",
3013
- value: item.value
3014
- };
3015
- const found = lookupKind(world, doc.type);
3016
- const kind = found.ok ? found.kind : void 0;
3017
- const here = new Visit(item.place, item.at, doc, envelope === void 0, item.depth, item.names, item.later, item.slot, item.parent, kind, found.ok ? found.path : void 0, item.address ? true : void 0, item.caps);
3106
+ const { doc, kind, split } = read;
3107
+ const here = new Visit(item.place, item.at, doc, read.declared, item.depth, item.names, item.later, item.slot, item.parent, kind, read.typePath, item.address ? true : void 0, item.caps);
3018
3108
  if (visit(here) === "skip" || kind === void 0) continue;
3019
- const split = splitParts(kind.parts, doc.value);
3020
- const base = envelope === void 0 ? item.at : {
3109
+ const base = read.declared ? item.at : {
3021
3110
  up: item.at,
3022
3111
  keys: ["value"]
3023
3112
  };
3024
3113
  if (!split.ok) {
3025
- const at = split.at.length === 0 ? "" : ` (at ${split.at.join(".")})`;
3026
- const where = keysOf({
3027
- up: base,
3028
- keys: split.at
3029
- });
3030
3114
  options.problem?.({
3031
3115
  place: keysOf(item.place),
3032
- at: where,
3116
+ at: keysOf({
3117
+ up: base,
3118
+ keys: split.at
3119
+ }),
3033
3120
  code: "#VALUE!",
3034
- reason: `${split.reason}${at} The kind is ${typeName(doc.type)}.`
3121
+ reason: split.reason
3035
3122
  });
3036
3123
  continue;
3037
3124
  }
@@ -3163,7 +3250,8 @@ function capReason(v, kind) {
3163
3250
  * - `#PART?`: a value without a type.
3164
3251
  * - `#DEPTH!`: too much nesting.
3165
3252
  * - `#REF!` and `#STEP?`: a bad path.
3166
- * - `#NAME?`: a name that nothing binds.
3253
+ * - `#NAME?`: a name that nothing binds. With the hook `known` of the machine, also a name that the language does not
3254
+ * have, for example an operation.
3167
3255
  * - `#CAP!`: an effect that the capabilities of its document do not permit. A kind around the document can narrow them.
3168
3256
  *
3169
3257
  * @param machine - The world and the code of the evaluators.
@@ -3205,6 +3293,15 @@ function check(machine, doc, options = {}) {
3205
3293
  reason: `No rung gives an evaluator for ${typeName(v.doc.type)}.`,
3206
3294
  at: v.at
3207
3295
  });
3296
+ else if (machine.known !== void 0) {
3297
+ const known = machine.known(v.typePath ?? [], name);
3298
+ if (known !== true) issues.push({
3299
+ code: "#NAME?",
3300
+ place: v.place,
3301
+ reason: known,
3302
+ at: v.at
3303
+ });
3304
+ }
3208
3305
  const caps = v.caps;
3209
3306
  if (caps !== void 0 && v.kind?.effects !== void 0) {
3210
3307
  const kinds = v.kind.effects === "type" ? [v.typePath ?? []] : v.kind.effects.map((kind) => kind.split("."));
@@ -3237,7 +3334,7 @@ function check(machine, doc, options = {}) {
3237
3334
  reason: `A path starts with a root: ${ROOTS.join(", ")}.`,
3238
3335
  at: stepAt(0)
3239
3336
  });
3240
- return "skip";
3337
+ return;
3241
3338
  }
3242
3339
  if (!roots.includes(root)) issues.push({
3243
3340
  code: "#REF!",
@@ -3290,7 +3387,7 @@ var Held = class {
3290
3387
  this.error = error;
3291
3388
  }
3292
3389
  };
3293
- const CLOSURE = Symbol.for("coeval.closure");
3390
+ const CLOSURE$2 = Symbol.for("coeval.closure");
3294
3391
  /**
3295
3392
  * This function tells if a value is a function that the construct `fn` made.
3296
3393
  *
@@ -3298,7 +3395,7 @@ const CLOSURE = Symbol.for("coeval.closure");
3298
3395
  * @returns `true` for a closure.
3299
3396
  */
3300
3397
  function isClosure(value) {
3301
- return typeof value === "function" && value[CLOSURE] !== void 0;
3398
+ return typeof value === "function" && value[CLOSURE$2] !== void 0;
3302
3399
  }
3303
3400
  /** The standard extensions: the values that JSON cannot write. */
3304
3401
  const STD_EXT = {
@@ -3344,7 +3441,7 @@ function valuesOf(parts, ctx, rt) {
3344
3441
  }
3345
3442
  return values;
3346
3443
  }
3347
- function partsOf(value) {
3444
+ function partsOf$1(value) {
3348
3445
  return isRecord(value) ? value : {};
3349
3446
  }
3350
3447
  const LIT_SUMMARY = "A literal: its value is the result.";
@@ -3408,7 +3505,14 @@ function formulaKinds() {
3408
3505
  verbs: { eval: "formula.fn" },
3409
3506
  parts: {
3410
3507
  shape: "record",
3411
- fields: { body: term },
3508
+ fields: {
3509
+ params: {
3510
+ shape: "list",
3511
+ item: { shape: "text" },
3512
+ distinct: true
3513
+ },
3514
+ body: term
3515
+ },
3412
3516
  required: ["params", "body"]
3413
3517
  },
3414
3518
  scope: [{
@@ -3531,18 +3635,19 @@ function formulaEvaluators(profile = {}) {
3531
3635
  if (missing !== void 0 && missing(reached)) return fail("#N/A", "The path reaches no value.");
3532
3636
  return ok(reached);
3533
3637
  };
3534
- const computed = parts.length > 0;
3638
+ const held = (ctx) => {
3639
+ if (head === void 0 || !Object.hasOwn(ctx.names, head)) return void 0;
3640
+ const bound = ctx.names[head];
3641
+ return bound instanceof Held ? {
3642
+ ok: false,
3643
+ error: bound.error
3644
+ } : void 0;
3645
+ };
3646
+ if (parts.length === 0) return (ctx, rt) => held(ctx) ?? give(rt.resolve(ctx, path));
3535
3647
  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
3648
  const steps = valuesOf(parts, ctx, rt);
3545
- return Array.isArray(steps) ? give(rt.resolve(ctx, fill(steps))) : steps;
3649
+ if (!Array.isArray(steps)) return steps;
3650
+ return held(ctx) ?? give(rt.resolve(ctx, fill(steps)));
3546
3651
  };
3547
3652
  }),
3548
3653
  "formula.step": compiled(({ doc, parts, fill }) => {
@@ -3559,7 +3664,7 @@ function formulaEvaluators(profile = {}) {
3559
3664
  };
3560
3665
  }),
3561
3666
  "formula.record": compiled(({ value }) => {
3562
- const fields = partsOf(value);
3667
+ const fields = partsOf$1(value);
3563
3668
  const keys = Object.keys(fields);
3564
3669
  const codes = keys.map((key) => fields[key].code);
3565
3670
  if (combine !== void 0) {
@@ -3592,8 +3697,8 @@ function formulaEvaluators(profile = {}) {
3592
3697
  return Array.isArray(values) ? ok(values) : values;
3593
3698
  }),
3594
3699
  "formula.let": compiled(({ value }) => {
3595
- const record = partsOf(value);
3596
- const bindings = Object.entries(partsOf(record["bind"]));
3700
+ const record = partsOf$1(value);
3701
+ const bindings = Object.entries(partsOf$1(record["bind"]));
3597
3702
  const body = record["body"];
3598
3703
  return (ctx, rt) => {
3599
3704
  const names = { ...ctx.names };
@@ -3614,7 +3719,7 @@ function formulaEvaluators(profile = {}) {
3614
3719
  return () => bad;
3615
3720
  }
3616
3721
  const names = params;
3617
- const body = partsOf(value)["body"];
3722
+ const body = partsOf$1(value)["body"];
3618
3723
  return (ctx, rt) => {
3619
3724
  const closure = (...args) => {
3620
3725
  const scope = { ...ctx.names };
@@ -3626,12 +3731,12 @@ function formulaEvaluators(profile = {}) {
3626
3731
  if (!result.ok) throw new Failure(result.error);
3627
3732
  return result.value;
3628
3733
  };
3629
- Object.defineProperty(closure, CLOSURE, { value: { params: names } });
3734
+ Object.defineProperty(closure, CLOSURE$2, { value: { params: names } });
3630
3735
  return ok(closure);
3631
3736
  };
3632
3737
  }),
3633
3738
  "formula.call": compiled(({ value }) => {
3634
- const record = partsOf(value);
3739
+ const record = partsOf$1(value);
3635
3740
  const fnPart = record["fn"];
3636
3741
  const args = Array.isArray(record["args"]) ? record["args"] : [];
3637
3742
  return (ctx, rt) => {
@@ -3652,7 +3757,7 @@ function formulaEvaluators(profile = {}) {
3652
3757
  };
3653
3758
  }),
3654
3759
  "formula.if": compiled(({ value }) => {
3655
- const record = partsOf(value);
3760
+ const record = partsOf$1(value);
3656
3761
  const test = record["test"];
3657
3762
  const then = record["then"];
3658
3763
  const other = record["else"];
@@ -3771,14 +3876,52 @@ function formulaEvaluators(profile = {}) {
3771
3876
  };
3772
3877
  }
3773
3878
  /**
3879
+ * This function makes the hook `known` of the formula kit for one profile (STATIC.KNOWN). The evaluator
3880
+ * `formula.op` knows an operation of `lazy` or of `ops`. A profile whose `ops` is a function answers through a call
3881
+ * of that function. A function that throws counts as an answer, because the run then gives `#CALC!`. The evaluator
3882
+ * `formula.ext` knows an extension of `ext` and each standard extension. The hook knows each name of the other
3883
+ * evaluators.
3884
+ *
3885
+ * @param profile - The operations and the extensions of the language.
3886
+ * @returns The hook: `true`, or the reason of the `#NAME?` that the evaluator gives in a run.
3887
+ */
3888
+ function formulaKnown(profile = {}) {
3889
+ const hasOp = (name) => {
3890
+ if (profile.lazy !== void 0 && Object.hasOwn(profile.lazy, name)) return true;
3891
+ const ops = profile.ops;
3892
+ if (ops === void 0) return false;
3893
+ if (typeof ops !== "function") return Object.hasOwn(ops, name);
3894
+ try {
3895
+ return ops(name) !== void 0;
3896
+ } catch {
3897
+ return true;
3898
+ }
3899
+ };
3900
+ const hasExt = (name) => profile.ext !== void 0 && Object.hasOwn(profile.ext, name) || Object.hasOwn(STD_EXT, name);
3901
+ return (path, evaluator) => {
3902
+ if (evaluator !== "formula.op" && evaluator !== "formula.ext") return true;
3903
+ const name = path.slice(1).join(".");
3904
+ if (evaluator === "formula.op") return hasOp(name) ? true : `The language has no operation ${name}.`;
3905
+ return hasExt(name) ? true : `The language has no extension ${name}.`;
3906
+ };
3907
+ }
3908
+ /**
3774
3909
  * This function makes a machine for a formula language. The machine has the kinds and the evaluators of the
3775
- * formula kit. It also has the kinds, the evaluators and the walkers that the language adds.
3910
+ * formula kit. It also has the kinds, the evaluators and the walkers that the language adds. Its hook `known` comes
3911
+ * from the profile (`formulaKnown`). A hook `known` of the language answers each name that the kit knows.
3776
3912
  *
3777
3913
  * @param profile - The operations and the rules of the language.
3778
3914
  * @param more - The parts of a machine that the language adds. Its kinds win over the kinds of the kit.
3779
3915
  * @returns The machine.
3780
3916
  */
3781
3917
  function formulaMachine(profile = {}, more = {}) {
3918
+ const kit = formulaKnown(profile);
3919
+ const replaced = (name) => more.evaluators !== void 0 && Object.hasOwn(more.evaluators, name) || more.runners !== void 0 && Object.hasOwn(more.runners, name);
3920
+ const theirs = more.known;
3921
+ const known = (path, evaluator) => {
3922
+ const answer = replaced(evaluator) ? true : kit(path, evaluator);
3923
+ return answer === true && theirs !== void 0 ? theirs(path, evaluator) : answer;
3924
+ };
3782
3925
  return {
3783
3926
  ...more,
3784
3927
  world: {
@@ -3791,10 +3934,1072 @@ function formulaMachine(profile = {}, more = {}) {
3791
3934
  evaluators: {
3792
3935
  ...formulaEvaluators(profile),
3793
3936
  ...more.evaluators
3937
+ },
3938
+ known
3939
+ };
3940
+ }
3941
+ //#endregion
3942
+ //#region src/reference.ts
3943
+ function own(table, name) {
3944
+ return table !== void 0 && Object.hasOwn(table, name) ? table[name] : void 0;
3945
+ }
3946
+ /** This function finds the code of an evaluator name. A runner wins over an evaluator of the same name. */
3947
+ function choose(env, name) {
3948
+ const runner = own(env.machine.runners, name);
3949
+ if (runner !== void 0) {
3950
+ const defined = own(env.definitions.runners, name);
3951
+ if (defined !== void 0) return { runner: defined };
3952
+ return typeof runner === "function" ? { runner } : { gap: `The reference has no definition of the compiled runner ${name}.` };
3953
+ }
3954
+ const evaluator = own(env.machine.evaluators, name);
3955
+ if (evaluator === void 0) return void 0;
3956
+ const defined = own(env.definitions.evaluators, name);
3957
+ if (defined !== void 0) return { evaluator: defined };
3958
+ return typeof evaluator === "function" ? { evaluator } : { gap: `The reference has no definition of the compiled evaluator ${name}.` };
3959
+ }
3960
+ /**
3961
+ * This function reads one document by the rules, in their order. First come an envelope or a declared type
3962
+ * (EVAL.ERRORS) and the limit of the depth (PLAN.DEPTH). Then come the ladder (LADDER.*), an evaluator and the shape
3963
+ * of the parts (SHAPE.*).
3964
+ */
3965
+ function examine(env, at) {
3966
+ const { place, declared } = at;
3967
+ const world = env.machine.world;
3968
+ const read = partsOf(world, at.value, declared);
3969
+ if (!read.ok) return fail(read.code, read.reason, { place });
3970
+ if (at.depth > env.maxDepth) return fail("#DEPTH!", `The nesting is deeper than ${env.maxDepth} documents.`, { place });
3971
+ const { doc, kind, split } = read;
3972
+ const kindText = typeName(doc.type);
3973
+ const answer = ask(world, read.declared ? {} : doc, "eval", declared === void 0 ? {} : { declaredType: declared });
3974
+ if (answer.error === "unknown-kind") return fail("#KIND?", `The world has no kind ${kindText}.`, { place });
3975
+ const name = answer.evaluator;
3976
+ const chosen = name === void 0 ? void 0 : choose(env, name);
3977
+ if (name === void 0 || chosen === void 0) return fail("#NOEVAL", `No rung gives an evaluator for ${kindText}.`, { place });
3978
+ if (!split.ok) return fail("#VALUE!", split.reason, { place });
3979
+ return {
3980
+ doc,
3981
+ kindText,
3982
+ typePath: read.typePath ?? [],
3983
+ kind,
3984
+ name,
3985
+ chosen,
3986
+ split
3987
+ };
3988
+ }
3989
+ /** This function gives the capabilities that the rules of a kind give one part (D14, CAP.CONTRACT, CAP.ONLY). */
3990
+ function capsOfPart(rules, path, caps) {
3991
+ let out = caps;
3992
+ for (const rule of rules ?? []) {
3993
+ if (rule.in !== void 0 && !rule.in.some((pattern) => pathMatches(path, pattern))) continue;
3994
+ if (rule.rule === "mask") return [];
3995
+ if (rule.rule === "only") out = intersectCaps(out, rule.caps);
3996
+ }
3997
+ return out;
3998
+ }
3999
+ /**
4000
+ * This function gives the context of a part. A context that the evaluator gives keeps only the capabilities of the
4001
+ * parent (CAP.NARROW). Then the rules of the kind narrow it (CAP.CONTRACT).
4002
+ */
4003
+ function contextOfPart(seen, slot, parent, given) {
4004
+ const base = given === void 0 || given === parent ? parent : {
4005
+ ...given,
4006
+ caps: given.caps.filter((cap) => permits(parent.caps, cap))
4007
+ };
4008
+ const caps = capsOfPart(seen.kind?.caps, slot.path, base.caps);
4009
+ return caps === base.caps ? base : {
4010
+ ...base,
4011
+ caps
4012
+ };
4013
+ }
4014
+ function headerOf(item) {
4015
+ return isEnvelope(item) && typeof item.name === "string" ? item.name : void 0;
4016
+ }
4017
+ function partAt(seen, at, slot, given) {
4018
+ return {
4019
+ value: slot.item,
4020
+ place: at.place.concat(slot.path),
4021
+ declared: slot.of,
4022
+ depth: at.depth + 1,
4023
+ address: slot.address === true,
4024
+ ctx: contextOfPart(seen, slot, at.ctx, given)
4025
+ };
4026
+ }
4027
+ /** This function resolves a path with the full algorithm of `resolve`, not with its short path (DEREF.QUICK). */
4028
+ function resolveFully(machine, ctx, path, options) {
4029
+ const found = resolve(machine, ctx, path, { hops: true });
4030
+ return options?.hops === true ? found : {
4031
+ ...found,
4032
+ hops: []
4033
+ };
4034
+ }
4035
+ /** This function records an effect when the capabilities permit it (RUN.CAP, CAP.HOOK). */
4036
+ function record(env, ctx, kind, payload, place) {
4037
+ const keys = typeof kind === "string" ? kind.split(".") : kind;
4038
+ const text = keys.join(".");
4039
+ const machine = env.machine;
4040
+ 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 });
4041
+ env.effects.push({
4042
+ index: env.effects.length,
4043
+ kind: text,
4044
+ path: keys,
4045
+ payload,
4046
+ node: -1,
4047
+ at: 0,
4048
+ place,
4049
+ context: ctx
4050
+ });
4051
+ }
4052
+ /** This function evaluates a document. Each error gets the place of the document where it started (K5). */
4053
+ function evaluateAt(env, at) {
4054
+ const seen = examine(env, at);
4055
+ if (!("doc" in seen)) return seen;
4056
+ return evaluateSeen(env, seen, at);
4057
+ }
4058
+ function evaluateSeen(env, seen, at) {
4059
+ const { chosen } = seen;
4060
+ const { place } = at;
4061
+ if ("gap" in chosen) return fail("#NOEVAL", chosen.gap, { place });
4062
+ if ("runner" in chosen) return drive(runSeen(env, seen, at, chosen.runner), place);
4063
+ const input = evalInput(env, seen, at);
4064
+ try {
4065
+ return placed(chosen.evaluator(input), place);
4066
+ } catch (error) {
4067
+ return placed(thrown(error, `the evaluator ${seen.name}`), place);
4068
+ }
4069
+ }
4070
+ /** This function gives the steps of a document for a runner. Nothing happens before the first step. */
4071
+ function* stepsAt(env, at) {
4072
+ const seen = examine(env, at);
4073
+ if (!("doc" in seen)) return seen;
4074
+ if ("runner" in seen.chosen) return yield* runSeen(env, seen, at, seen.chosen.runner);
4075
+ return evaluateSeen(env, seen, at);
4076
+ }
4077
+ function* runSeen(env, seen, at, runner) {
4078
+ try {
4079
+ return placed(yield* runner(runInput(env, seen, at)), at.place);
4080
+ } catch (error) {
4081
+ return placed(thrown(error, `the runner ${seen.name}`), at.place);
4082
+ }
4083
+ }
4084
+ /** This function drives steps that cannot wait. A step that waits gives `#CALC!` at the document (RUN.WAIT). */
4085
+ function drive(steps, place) {
4086
+ const step = steps.next();
4087
+ if (step.done === true) return step.value;
4088
+ step.value.catch(() => void 0);
4089
+ const waited = fail("#CALC!", "A part waited, and its parent cannot wait.", { place });
4090
+ steps.return(waited);
4091
+ return waited;
4092
+ }
4093
+ function evalInput(env, seen, at) {
4094
+ const { split, doc } = seen;
4095
+ const parts = split.parts.map((slot) => {
4096
+ const name = headerOf(slot.item);
4097
+ return {
4098
+ key: slot.key,
4099
+ path: slot.path,
4100
+ ...name === void 0 ? {} : { name },
4101
+ evaluate: (given) => evaluateAt(env, partAt(seen, at, slot, given))
4102
+ };
4103
+ });
4104
+ const fill = (items) => split.parts.length === 0 ? doc.value : split.fill(items);
4105
+ return {
4106
+ kind: seen.kindText,
4107
+ typePath: seen.typePath,
4108
+ doc,
4109
+ value: fill(parts),
4110
+ data: split.data,
4111
+ parts,
4112
+ context: at.ctx,
4113
+ place: at.place,
4114
+ ...at.address ? { address: true } : {},
4115
+ resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
4116
+ effect: (kind, payload) => record(env, at.ctx, kind, payload, at.place) ?? ok(payload),
4117
+ fill
4118
+ };
4119
+ }
4120
+ function runInput(env, seen, at) {
4121
+ const { split, doc } = seen;
4122
+ const parts = split.parts.map((slot) => {
4123
+ const name = headerOf(slot.item);
4124
+ return {
4125
+ key: slot.key,
4126
+ path: slot.path,
4127
+ ...name === void 0 ? {} : { name },
4128
+ evaluate: (given) => stepsAt(env, partAt(seen, at, slot, given))
4129
+ };
4130
+ });
4131
+ const fill = (items) => split.parts.length === 0 ? doc.value : split.fill(items);
4132
+ return {
4133
+ kind: seen.kindText,
4134
+ typePath: seen.typePath,
4135
+ doc,
4136
+ value: fill(parts),
4137
+ data: split.data,
4138
+ parts,
4139
+ context: at.ctx,
4140
+ place: at.place,
4141
+ resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
4142
+ effect: function* (kind, payload) {
4143
+ return record(env, at.ctx, kind, payload, at.place) ?? ok(payload);
4144
+ },
4145
+ all: (list, options) => together(list, options),
4146
+ fill
4147
+ };
4148
+ }
4149
+ /**
4150
+ * This function evaluates parts for `all` (RUN.ALL). The parts start in their order, up to the limit, and each part
4151
+ * goes on until it ends or waits. In an evaluation, a part that waits does not end, thus it keeps its place in the
4152
+ * limit. With `failFast`, the first failure stops the parts that wait, and the later parts do not start
4153
+ * (RUN.FAIL-FAST). When no part failed and a part waits, the steps wait, and the drive gives `#CALC!`.
4154
+ */
4155
+ function* together(list, options = {}) {
4156
+ const limit = Math.max(1, options.concurrency ?? list.length);
4157
+ const results = list.map(() => void 0);
4158
+ const waiting = [];
4159
+ let failed = false;
4160
+ for (let index = 0; index < list.length && !failed && waiting.length < limit; index += 1) {
4161
+ let result;
4162
+ try {
4163
+ const steps = list[index].evaluate();
4164
+ const step = steps.next();
4165
+ if (step.done === true) result = step.value;
4166
+ else waiting.push({
4167
+ steps,
4168
+ promise: step.value
4169
+ });
4170
+ } catch (error) {
4171
+ result = thrown(error, "a part");
3794
4172
  }
4173
+ results[index] = result;
4174
+ if (result !== void 0 && options.failFast === true && !result.ok) failed = true;
4175
+ }
4176
+ if (failed) {
4177
+ const stopped = fail("#ABORT", "The part stopped: a part before it failed, and the parts run with failFast.");
4178
+ for (const item of waiting) try {
4179
+ item.steps.return(stopped);
4180
+ } catch {}
4181
+ return results.map((result) => result ?? stopped);
4182
+ }
4183
+ if (waiting.length > 0) yield Promise.race(waiting.map((item) => item.promise));
4184
+ return results;
4185
+ }
4186
+ /**
4187
+ * This function evaluates a document by the rules, without a compilation. It is the reference of the plans: a plan,
4188
+ * a traced plan and the second tier of a language must give its results. It covers evaluations, not runs: an effect
4189
+ * gives its payload, and a part that waits gives `#CALC!`.
4190
+ *
4191
+ * @param machine - The world and the code of the evaluators.
4192
+ * @param doc - The document.
4193
+ * @param context - The names and the capabilities at the root.
4194
+ * @param options - The type of a bare root value, the definitions of compiled code, and a list for the effects.
4195
+ * @returns The result.
4196
+ */
4197
+ function reference(machine, doc, context = makeContext(), options = {}) {
4198
+ const env = {
4199
+ machine,
4200
+ definitions: options.definitions ?? {},
4201
+ effects: options.effects ?? [],
4202
+ maxDepth: machine.maxDepth ?? 1e3
3795
4203
  };
4204
+ const ctx = context.world === null ? {
4205
+ ...context,
4206
+ world: worldThing(machine.world)
4207
+ } : context;
4208
+ try {
4209
+ return evaluateAt(env, {
4210
+ value: doc,
4211
+ place: [],
4212
+ declared: options.declaredType,
4213
+ depth: 0,
4214
+ address: false,
4215
+ ctx
4216
+ });
4217
+ } catch (error) {
4218
+ return placed(thrown(error, "the reference"), []);
4219
+ }
4220
+ }
4221
+ const CLOSURE$1 = Symbol.for("coeval.closure");
4222
+ /** This function sets an own field, also the field `__proto__` (SHAPE.PROTO). */
4223
+ function setField(target, key, value) {
4224
+ Object.defineProperty(target, key, {
4225
+ value,
4226
+ enumerable: true,
4227
+ writable: true,
4228
+ configurable: true
4229
+ });
4230
+ }
4231
+ function partNamed(parts, key) {
4232
+ return parts.find((part) => part.path.length === 1 && part.path[0] === key);
4233
+ }
4234
+ function partsUnder(parts, key) {
4235
+ return parts.filter((part) => part.path.length === 2 && part.path[0] === key);
4236
+ }
4237
+ /**
4238
+ * This function gives the definitions of the formula kit for one profile. Each construct is a function evaluator in
4239
+ * the most direct style. It shares no code with the compilers of `formulaEvaluators`, thus the two readings of the
4240
+ * rules can disagree, and a test finds it.
4241
+ *
4242
+ * @param profile - The operations and the rules of the language.
4243
+ * @returns The definitions, by evaluator name.
4244
+ */
4245
+ function formulaDefinitions(profile = {}) {
4246
+ const truthy = profile.truthy ?? ((value) => typeof value === "boolean" ? value : void 0);
4247
+ const opOf = (name) => typeof profile.ops === "function" ? profile.ops(name) : own(profile.ops, name);
4248
+ const noTruth = (what) => fail("#VALUE!", `The ${what} must give a truth value.`);
4249
+ /** FORMULA.LIST, FORMULA.OPS and FORMULA.COMBINE: the values of parts in order, or the error. */
4250
+ const valuesOf = (parts, skip) => {
4251
+ const values = [];
4252
+ const errors = [];
4253
+ for (const part of parts) {
4254
+ const result = part.evaluate();
4255
+ if (result.ok) values.push(result.value);
4256
+ else if (skip?.(result.error) === true) values.push(SKIP);
4257
+ else if (profile.combine === void 0) return result;
4258
+ else errors.push(result.error);
4259
+ }
4260
+ if (errors.length === 0 || profile.combine === void 0) return { values };
4261
+ return {
4262
+ ok: false,
4263
+ error: errors.length === 1 ? errors[0] : profile.combine(errors)
4264
+ };
4265
+ };
4266
+ const lit = ({ doc }) => ok(doc.value);
4267
+ const ref = ({ doc, parts, fill, address, context, resolve: walk }) => {
4268
+ const path = doc.value;
4269
+ 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\"].");
4270
+ let steps = path;
4271
+ if (parts.length > 0) {
4272
+ const all = valuesOfStrict(parts);
4273
+ if (!("values" in all)) return all;
4274
+ steps = fill(all.values);
4275
+ }
4276
+ const head = path[0] === "names" && typeof path[1] === "string" ? path[1] : void 0;
4277
+ const bound = head === void 0 ? void 0 : own(context.names, head);
4278
+ if (bound instanceof Held) return {
4279
+ ok: false,
4280
+ error: bound.error
4281
+ };
4282
+ const found = walk(steps);
4283
+ if (!found.ok) return fail(found.code, found.reason);
4284
+ if (address === true) return ok(found.thing);
4285
+ const reached = valueOfThing(found.thing);
4286
+ if (reached instanceof Held) return {
4287
+ ok: false,
4288
+ error: reached.error
4289
+ };
4290
+ if (profile.missing?.(reached) === true) return fail("#N/A", "The path reaches no value.");
4291
+ return ok(reached);
4292
+ };
4293
+ const step = ({ doc, parts, fill }) => {
4294
+ if (parts.length === 0) return ok(doc);
4295
+ const all = valuesOfStrict(parts);
4296
+ return "values" in all ? ok({
4297
+ ...doc,
4298
+ value: fill(all.values)
4299
+ }) : all;
4300
+ };
4301
+ const record = ({ parts }) => {
4302
+ const all = valuesOf(parts, profile.omit);
4303
+ if (!("values" in all)) return all;
4304
+ const out = {};
4305
+ parts.forEach((part, index) => {
4306
+ const value = all.values[index];
4307
+ if (value !== SKIP) setField(out, String(part.path[0]), value);
4308
+ });
4309
+ return ok(out);
4310
+ };
4311
+ const list = ({ parts }) => {
4312
+ const all = valuesOf(parts);
4313
+ return "values" in all ? ok([...all.values]) : all;
4314
+ };
4315
+ const letIn = ({ parts, context }) => {
4316
+ const names = {};
4317
+ for (const key of Object.keys(context.names)) setField(names, key, context.names[key]);
4318
+ for (const binding of partsUnder(parts, "bind")) {
4319
+ const result = binding.evaluate();
4320
+ setField(names, String(binding.path[1]), result.ok ? result.value : new Held(result.error));
4321
+ }
4322
+ return partNamed(parts, "body").evaluate({
4323
+ ...context,
4324
+ names
4325
+ });
4326
+ };
4327
+ const fn = ({ data, parts, context }) => {
4328
+ const params = isRecord(data) ? data["params"] : void 0;
4329
+ 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.");
4330
+ const names = params;
4331
+ const body = partNamed(parts, "body");
4332
+ const closure = (...args) => {
4333
+ const scope = {};
4334
+ for (const key of Object.keys(context.names)) setField(scope, key, context.names[key]);
4335
+ names.forEach((name, index) => setField(scope, name, args[index]));
4336
+ const result = body.evaluate({
4337
+ ...context,
4338
+ names: scope
4339
+ });
4340
+ if (!result.ok) throw new Failure(result.error);
4341
+ return result.value;
4342
+ };
4343
+ Object.defineProperty(closure, CLOSURE$1, { value: { params: names } });
4344
+ return ok(closure);
4345
+ };
4346
+ const call = ({ parts }) => {
4347
+ const target = partNamed(parts, "fn").evaluate();
4348
+ if (!target.ok) return target;
4349
+ if (typeof target.value !== "function") return fail("#VALUE!", "The fn of call must give a function.");
4350
+ const all = valuesOfStrict(partsUnder(parts, "args"));
4351
+ if (!("values" in all)) return all;
4352
+ try {
4353
+ return ok(target.value(...all.values));
4354
+ } catch (error) {
4355
+ return thrown(error, "the function of call");
4356
+ }
4357
+ };
4358
+ const choice = ({ parts }) => {
4359
+ const test = partNamed(parts, "test").evaluate();
4360
+ if (!test.ok) return test;
4361
+ const truth = truthy(test.value);
4362
+ if (truth === void 0) return noTruth("test of if");
4363
+ if (truth) return partNamed(parts, "then").evaluate();
4364
+ const other = partNamed(parts, "else");
4365
+ if (other !== void 0) return other.evaluate();
4366
+ return ok(Object.hasOwn(profile, "otherwise") ? profile.otherwise : null);
4367
+ };
4368
+ /** FORMULA.LOGIC: `and` stops at the first false term, and `or` at the first true term. */
4369
+ const logic = (stopAt, what) => ({ parts }) => {
4370
+ let last = ok(!stopAt);
4371
+ for (const part of parts) {
4372
+ last = part.evaluate();
4373
+ if (!last.ok) return last;
4374
+ const truth = truthy(last.value);
4375
+ if (truth === void 0) return noTruth(what);
4376
+ if (truth === stopAt) return profile.logic === "value" ? last : ok(stopAt);
4377
+ }
4378
+ return profile.logic === "value" ? last : ok(!stopAt);
4379
+ };
4380
+ const op = ({ typePath, parts }) => {
4381
+ const name = typePath.slice(1).join(".");
4382
+ const lazy = own(profile.lazy, name);
4383
+ if (lazy !== void 0) try {
4384
+ return lazy(parts.map((part) => () => part.evaluate()));
4385
+ } catch (error) {
4386
+ return thrown(error, `the operation ${name}`);
4387
+ }
4388
+ const apply = opOf(name);
4389
+ if (apply === void 0) return fail("#NAME?", `The language has no operation ${name}.`);
4390
+ const all = valuesOf(parts);
4391
+ if (!("values" in all)) return all;
4392
+ try {
4393
+ const out = apply(...all.values);
4394
+ return profile.check?.(out, name) ?? ok(out);
4395
+ } catch (error) {
4396
+ return thrown(error, `the operation ${name}`);
4397
+ }
4398
+ };
4399
+ const ext = ({ typePath, doc, context }) => {
4400
+ const name = typePath.slice(1).join(".");
4401
+ const handler = own(profile.ext, name) ?? own(STD_EXT, name);
4402
+ if (handler === void 0) return fail("#NAME?", `The language has no extension ${name}.`);
4403
+ try {
4404
+ return handler(doc.value, context);
4405
+ } catch (error) {
4406
+ return thrown(error, `the extension ${name}`);
4407
+ }
4408
+ };
4409
+ return { evaluators: {
4410
+ "formula.lit": lit,
4411
+ "formula.ref": ref,
4412
+ "formula.step": step,
4413
+ "formula.record": record,
4414
+ "formula.list": list,
4415
+ "formula.let": letIn,
4416
+ "formula.fn": fn,
4417
+ "formula.call": call,
4418
+ "formula.if": choice,
4419
+ "formula.and": logic(false, "term of and"),
4420
+ "formula.or": logic(true, "term of or"),
4421
+ "formula.op": op,
4422
+ "formula.ext": ext
4423
+ } };
4424
+ }
4425
+ /** The mark of a field that the profile leaves out of a record (FORMULA.RECORD). */
4426
+ const SKIP = Symbol("skip");
4427
+ /** The values of parts in order. The first error stops them, also with `combine` (FORMULA.STEPS, FORMULA.FN). */
4428
+ function valuesOfStrict(parts) {
4429
+ const values = [];
4430
+ for (const part of parts) {
4431
+ const result = part.evaluate();
4432
+ if (!result.ok) return result;
4433
+ values.push(result.value);
4434
+ }
4435
+ return { values };
4436
+ }
4437
+ //#endregion
4438
+ //#region src/agree.ts
4439
+ /**
4440
+ * This function tells if two values are the same for `agree`. Lists and plain records compare item by item and field
4441
+ * by field, and the order of the fields does not matter. Each other leaf compares with `Object.is`, thus `-0` is not
4442
+ * `0`, and `NaN` is `NaN`. The identity of a list or of a plain record is not compared.
4443
+ *
4444
+ * Two closures of `fn` are the same when they have the same parameters. Two `Held` values are the same when their
4445
+ * errors have the same code and place. Each other object is the same only as itself, unless the rule of the caller
4446
+ * tells otherwise.
4447
+ *
4448
+ * `docEquals` uses the same rules for lists, plain records and the other objects. It has no rules for closures, for
4449
+ * `Held` values and for a rule of the caller. Thus two closures are equal there only when they are the same function.
4450
+ *
4451
+ * @param a - The first value.
4452
+ * @param b - The second value.
4453
+ * @param equal - The rule of the caller for other values. It answers first, and `undefined` gives the rules above.
4454
+ * @returns `true` when the values are the same.
4455
+ */
4456
+ function sameValue(a, b, equal) {
4457
+ const stack = [[a, b]];
4458
+ const seen = /* @__PURE__ */ new Map();
4459
+ while (stack.length > 0) {
4460
+ const [x, y] = stack.pop();
4461
+ if (Object.is(x, y)) continue;
4462
+ const told = equal?.(x, y);
4463
+ if (told !== void 0) {
4464
+ if (told) continue;
4465
+ return false;
4466
+ }
4467
+ if (typeof x !== "object" && typeof x !== "function") return false;
4468
+ if (typeof y !== "object" && typeof y !== "function") return false;
4469
+ if (x === null || y === null) return false;
4470
+ const pairs = seen.get(x) ?? /* @__PURE__ */ new Set();
4471
+ if (pairs.has(y)) continue;
4472
+ pairs.add(y);
4473
+ seen.set(x, pairs);
4474
+ if (isClosure(x) || isClosure(y)) {
4475
+ if (!(isClosure(x) && isClosure(y))) return false;
4476
+ stack.push([closureParams(x), closureParams(y)]);
4477
+ continue;
4478
+ }
4479
+ if (x instanceof Held || y instanceof Held) {
4480
+ if (!(x instanceof Held && y instanceof Held) || errorDiffers(x.error, y.error, false) !== void 0) return false;
4481
+ continue;
4482
+ }
4483
+ if (Array.isArray(x) || Array.isArray(y)) {
4484
+ if (!Array.isArray(x) || !Array.isArray(y) || x.length !== y.length) return false;
4485
+ for (let index = 0; index < x.length; index += 1) stack.push([x[index], y[index]]);
4486
+ continue;
4487
+ }
4488
+ if (!isRecord(x) || !isRecord(y)) return false;
4489
+ const keys = Object.keys(x);
4490
+ if (keys.length !== Object.keys(y).length) return false;
4491
+ for (const key of keys) {
4492
+ if (!Object.hasOwn(y, key)) return false;
4493
+ stack.push([x[key], y[key]]);
4494
+ }
4495
+ }
4496
+ return true;
4497
+ }
4498
+ const CLOSURE = Symbol.for("coeval.closure");
4499
+ function closureParams(fn) {
4500
+ return fn[CLOSURE]?.params;
4501
+ }
4502
+ function codeAndPlace(error) {
4503
+ return error.place === void 0 ? error.code : `${error.code} at [${error.place.join(", ")}]`;
4504
+ }
4505
+ /** This function gives the difference of two errors, or `undefined` when they agree. */
4506
+ function errorDiffers(a, b, strict) {
4507
+ if (a.code !== b.code) return `The plan gives ${codeAndPlace(a)}, and the tier gives ${codeAndPlace(b)}.`;
4508
+ if (strict && (a.place === void 0 || b.place === void 0)) return `An error ${a.code} has no place.`;
4509
+ 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.`;
4510
+ if (strict && a.reason !== b.reason) return `The error ${a.code} has another reason in the tier: "${b.reason}" for "${a.reason}".`;
4511
+ }
4512
+ /** A host stack overflow is the one permitted difference (VALUE.DEPTH): the tiers use different numbers of frames. */
4513
+ function overflowed(result) {
4514
+ return !result.ok && result.error.code === "#DEPTH!" && isStackOverflow(result.error.cause);
4515
+ }
4516
+ /** This function gives the difference of two results, or `undefined` when they agree. */
4517
+ function resultDiffers(a, b, options) {
4518
+ if (a.ok && b.ok) return sameValue(a.value, b.value, options.equal) ? void 0 : "The plan and the tier give different values.";
4519
+ if (!a.ok && !b.ok) return errorDiffers(a.error, b.error, options.strict === true);
4520
+ 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.`;
4521
+ }
4522
+ /** This function gives the difference of two lists of effects, or `undefined` when they agree (EFFECT.ORDER). */
4523
+ function effectsDiffer(a, b, options) {
4524
+ if (a.length !== b.length) return `The plan causes ${a.length} effects, and the tier causes ${b.length}.`;
4525
+ for (let index = 0; index < a.length; index += 1) {
4526
+ const x = a[index];
4527
+ const y = b[index];
4528
+ 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.`;
4529
+ }
4530
+ }
4531
+ /**
4532
+ * This function evaluates a document with a plan and with other tiers, and compares the results (PLAN.AGREES). Two
4533
+ * results agree when they have the same value by `sameValue`, or errors with the same code, and the same place when
4534
+ * both have one. The effects must have the same kinds, places and payloads, in the same order. A language gives its
4535
+ * own tier with the option `other`.
4536
+ *
4537
+ * @param machine - The world and the code of the evaluators.
4538
+ * @param doc - The document.
4539
+ * @param context - The names and the capabilities at the root.
4540
+ * @param options - The tiers, the definitions for the reference, the rules of the comparison and the second tier.
4541
+ * @returns The result of the plan, or the first tier that disagrees and the reason.
4542
+ */
4543
+ function agree(machine, doc, context = makeContext(), options = {}) {
4544
+ const declared = options.declaredType === void 0 ? {} : { declaredType: options.declaredType };
4545
+ const observe = options.observe;
4546
+ observe?.();
4547
+ const plan = prepare(machine, doc, declared);
4548
+ const effects = [];
4549
+ const result = plan.evaluate(context, { effects });
4550
+ const saw = observe?.();
4551
+ const differs = (other, otherEffects) => {
4552
+ if (overflowed(result) || overflowed(other)) return void 0;
4553
+ const why = resultDiffers(result, other, options) ?? (otherEffects === void 0 ? void 0 : effectsDiffer(effects, otherEffects, options));
4554
+ if (why !== void 0 || observe === void 0) return why;
4555
+ return sameValue(saw, observe(), options.equal) ? void 0 : "The host saw other calls in the tier.";
4556
+ };
4557
+ for (const tier of options.tiers ?? [
4558
+ "reference",
4559
+ "traced",
4560
+ "again"
4561
+ ]) {
4562
+ let other;
4563
+ let otherEffects = [];
4564
+ if (tier === "reference") other = reference(machine, doc, context, {
4565
+ ...declared,
4566
+ effects: otherEffects,
4567
+ ...options.definitions === void 0 ? {} : { definitions: options.definitions }
4568
+ });
4569
+ else if (tier === "traced") {
4570
+ const traced = evaluate(machine, doc, context, options.declaredType);
4571
+ other = traced.result;
4572
+ otherEffects = [...traced.effects];
4573
+ } else other = plan.evaluate(context, { effects: otherEffects });
4574
+ const why = differs(other, otherEffects);
4575
+ if (why !== void 0) return {
4576
+ ok: false,
4577
+ tier,
4578
+ plan: result,
4579
+ other,
4580
+ reason: why
4581
+ };
4582
+ }
4583
+ if (options.other !== void 0) {
4584
+ let given;
4585
+ try {
4586
+ given = options.other(doc, context);
4587
+ } catch (error) {
4588
+ given = thrown(error, "the tier");
4589
+ }
4590
+ const other = "result" in given ? given.result : given;
4591
+ const why = differs(other, "result" in given ? given.effects : void 0);
4592
+ if (why !== void 0) return {
4593
+ ok: false,
4594
+ tier: "other",
4595
+ plan: result,
4596
+ other,
4597
+ reason: why
4598
+ };
4599
+ }
4600
+ return {
4601
+ ok: true,
4602
+ result,
4603
+ effects
4604
+ };
4605
+ }
4606
+ //#endregion
4607
+ //#region src/generate.ts
4608
+ /**
4609
+ * This function makes a source of random numbers with a seed (the algorithm mulberry32). It needs no package.
4610
+ *
4611
+ * @param seed - The seed: a whole number.
4612
+ * @returns The source.
4613
+ */
4614
+ function random(seed) {
4615
+ let state = seed >>> 0;
4616
+ const next = () => {
4617
+ state = state + 1831565813 >>> 0;
4618
+ let t = state;
4619
+ t = Math.imul(t ^ t >>> 15, t | 1);
4620
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
4621
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
4622
+ };
4623
+ const int = (below) => Math.floor(next() * below);
4624
+ return {
4625
+ next,
4626
+ int,
4627
+ chance: (p) => next() < p,
4628
+ pick: (items) => items[int(items.length)]
4629
+ };
4630
+ }
4631
+ /**
4632
+ * This function lists the types of a world: each kind and each alias, also in a namespace. A namespace with a
4633
+ * fallback gives no types, because each key names a kind.
4634
+ *
4635
+ * @param world - The world.
4636
+ * @returns The keys of each type.
4637
+ */
4638
+ function typesOf(world) {
4639
+ const out = [];
4640
+ const visit = (entries, prefix) => {
4641
+ for (const key of Object.keys(entries)) {
4642
+ const entry = entries[key];
4643
+ if (isKind(entry) || isAlias(entry)) out.push([...prefix, key]);
4644
+ else if (isNamespace(entry)) visit(entry.kinds, [...prefix, key]);
4645
+ }
4646
+ };
4647
+ visit(world.kinds, []);
4648
+ return out;
4649
+ }
4650
+ const NAMES = [
4651
+ "a",
4652
+ "b",
4653
+ "x",
4654
+ "n",
4655
+ "last",
4656
+ "__proto__"
4657
+ ];
4658
+ const FIELDS = [
4659
+ "a",
4660
+ "b",
4661
+ "c",
4662
+ "1",
4663
+ "__proto__"
4664
+ ];
4665
+ const KEYS = [
4666
+ "a",
4667
+ "b",
4668
+ "x",
4669
+ 0,
4670
+ 1,
4671
+ "0",
4672
+ "length",
4673
+ "type",
4674
+ "value",
4675
+ "parent"
4676
+ ];
4677
+ /** This function tells if a kind can be a leaf: it needs no part. */
4678
+ function leafKind(kind) {
4679
+ const shape = kind?.parts;
4680
+ return shape === void 0 || shape.shape === "none" || shape.shape === "list" || shape.shape === "map" || shape.shape === "text" || shape.shape === "number" || shape.shape === "one";
4681
+ }
4682
+ /**
4683
+ * This function builds a random document for a world from the contracts of its kinds. It reads the shapes of the
4684
+ * parts, the declared types, the permitted kinds and the names that the scope rules bind. Some choices are malformed
4685
+ * on purpose, for example an unknown kind or an unknown name under a namespace with a fallback. Other examples are a
4686
+ * value without its shape, a bare value without a type and a name that nothing binds. The depth and the size have
4687
+ * limits.
4688
+ *
4689
+ * @param world - The world.
4690
+ * @param options - The seed, the types, the limits and the data of the leaves.
4691
+ * @returns The document, as JSON.
4692
+ */
4693
+ function generate(world, options) {
4694
+ const rng = random(options.seed);
4695
+ const types = options.types ?? typesOf(world);
4696
+ const maxDepth = options.maxDepth ?? 4;
4697
+ const maxSize = options.maxSize ?? 24;
4698
+ const malformed = options.malformed ?? .05;
4699
+ const keys = options.keys ?? KEYS;
4700
+ const stepTypes = types.filter((type) => {
4701
+ const found = lookupKind(world, type);
4702
+ return found.ok && Object.hasOwn(found.kind.verbs, "step");
4703
+ });
4704
+ const unknownNames = Object.keys(world.kinds).filter((key) => {
4705
+ const entry = world.kinds[key];
4706
+ return isNamespace(entry) && entry.fallback !== void 0;
4707
+ }).map((key) => [key, "nope"]);
4708
+ let size = 0;
4709
+ const kindOf = (type) => {
4710
+ const found = lookupKind(world, type);
4711
+ return found.ok ? found.kind : void 0;
4712
+ };
4713
+ const anyJson = (depth = 0) => {
4714
+ const roll = rng.int(depth > 1 ? 6 : 8);
4715
+ if (roll === 0) return null;
4716
+ if (roll === 1) return rng.chance(.5);
4717
+ if (roll === 2) return rng.pick([
4718
+ 0,
4719
+ 1,
4720
+ 2,
4721
+ -1,
4722
+ .5,
4723
+ 1e21
4724
+ ]);
4725
+ if (roll === 3) return rng.pick([
4726
+ "",
4727
+ "a",
4728
+ "text",
4729
+ "0"
4730
+ ]);
4731
+ if (roll === 4) return rng.int(10);
4732
+ if (roll === 5) return rng.pick(NAMES);
4733
+ if (roll === 6) return Array.from({ length: rng.int(3) }, () => anyJson(depth + 1));
4734
+ const out = {};
4735
+ for (let index = rng.int(3); index > 0; index -= 1) Object.defineProperty(out, rng.pick(FIELDS), {
4736
+ value: anyJson(depth + 1),
4737
+ enumerable: true,
4738
+ writable: true,
4739
+ configurable: true
4740
+ });
4741
+ return out;
4742
+ };
4743
+ const dataOf = (type) => options.data?.(type, rng) ?? anyJson();
4744
+ const renderType = (type) => {
4745
+ const roll = rng.next();
4746
+ if (roll < .06) return {
4747
+ type: "ref",
4748
+ value: ["world", ...type]
4749
+ };
4750
+ if (type.length === 1 && roll < .8) return type[0];
4751
+ return [...type];
4752
+ };
4753
+ const permitted = (type, kinds) => kinds === void 0 || kinds.some((kind) => kind.length <= type.length && kind.every((key, index) => String(key) === String(type[index])));
4754
+ const pickName = (names) => names.length === 0 || rng.chance(malformed) ? rng.pick(["unbound", "zz"]) : rng.pick(names);
4755
+ const someNames = () => {
4756
+ const out = /* @__PURE__ */ new Set();
4757
+ for (let index = 1 + rng.int(2); index > 0; index -= 1) out.add(rng.pick(NAMES));
4758
+ return [...out];
4759
+ };
4760
+ const envelope = (type, value, header) => {
4761
+ const out = {
4762
+ type: renderType(type),
4763
+ value
4764
+ };
4765
+ if (header !== void 0) out["name"] = header;
4766
+ if (options.own !== void 0 && options.own.length > 0 && rng.chance(.03)) out["own"] = { eval: rng.pick(options.own) };
4767
+ return out;
4768
+ };
4769
+ /** A path from a root (D10). It uses the names in scope, and sometimes a step document. */
4770
+ const pathFor = (pos, refKind) => {
4771
+ if (rng.chance(malformed)) return rng.pick([
4772
+ "names",
4773
+ [],
4774
+ { names: "a" },
4775
+ ["nowhere", "a"]
4776
+ ]);
4777
+ const root = pos.names.length > 0 && rng.chance(.75) ? "names" : rng.pick(ROOTS.filter((name) => name !== "names"));
4778
+ const path = [root];
4779
+ if (root === "names") path.push(pickName(pos.names));
4780
+ if (root === "world") path.push(String(rng.pick(types)[0]));
4781
+ for (let index = rng.int(3); index > 0; index -= 1) if (stepTypes.length > 0 && rng.chance(.2)) {
4782
+ const type = rng.pick(stepTypes);
4783
+ const kind = kindOf(type);
4784
+ const value = refKind?.parts?.shape === "deep" && kind?.parts !== void 0 ? valueOf(kind.parts, [], {
4785
+ ...pos,
4786
+ depth: pos.depth + 1
4787
+ }, emptyScope()) : dataOf(type);
4788
+ path.push({
4789
+ type: renderType(type),
4790
+ value
4791
+ });
4792
+ } else path.push(rng.pick(keys));
4793
+ return path;
4794
+ };
4795
+ const emptyScope = () => ({
4796
+ rules: [],
4797
+ names: [],
4798
+ covered: [],
4799
+ sources: /* @__PURE__ */ new Map()
4800
+ });
4801
+ /** This function decides the names of the scope rules before the parts, so that each part knows what it sees. */
4802
+ const scopeOf = (kind) => {
4803
+ const rules = kind.scope ?? [];
4804
+ const scope = {
4805
+ rules,
4806
+ names: [],
4807
+ covered: rules.map(() => 0),
4808
+ sources: /* @__PURE__ */ new Map()
4809
+ };
4810
+ for (const rule of rules) {
4811
+ const source = rule.names;
4812
+ let names = [];
4813
+ if ("fixed" in source) names = [...source.fixed];
4814
+ else if ("keysAt" in source) {
4815
+ names = someNames();
4816
+ scope.sources.set(source.keysAt.join("."), { keys: names });
4817
+ } else if ("listAt" in source) {
4818
+ names = someNames();
4819
+ scope.sources.set(source.listAt.join("."), { list: rng.chance(malformed) ? [...names, ...names] : names });
4820
+ } else if ("textAt" in source) {
4821
+ names = [rng.pick(NAMES)];
4822
+ scope.sources.set(source.textAt.join("."), { text: names[0] });
4823
+ }
4824
+ scope.names.push(names);
4825
+ }
4826
+ return scope;
4827
+ };
4828
+ /** The names that a part sees from the scope rules of its parent. A rule `sequential` shows only earlier names. */
4829
+ const seenBy = (scope, path) => {
4830
+ const names = [];
4831
+ let headers = false;
4832
+ scope.rules.forEach((rule, index) => {
4833
+ if (!rule.in.some((pattern) => pathMatches(path, pattern))) return;
4834
+ const ruleNames = scope.names[index] ?? [];
4835
+ if ("headers" in rule.names) headers = true;
4836
+ if (rule.sequential !== true || "headers" in rule.names || (scope.covered[index] ?? 0) > 0) names.push(...ruleNames);
4837
+ });
4838
+ return {
4839
+ names,
4840
+ headers
4841
+ };
4842
+ };
4843
+ /** This function records the part at a path, and the header name that it got, for the rules that cover it. */
4844
+ const saw = (scope, path, part) => {
4845
+ const header = isEnvelope(part) && typeof part.name === "string" ? part.name : void 0;
4846
+ scope.rules.forEach((rule, index) => {
4847
+ if (!rule.in.some((pattern) => pathMatches(path, pattern))) return;
4848
+ scope.covered[index] = (scope.covered[index] ?? 0) + 1;
4849
+ if ("headers" in rule.names && header !== void 0) scope.names[index]?.push(header);
4850
+ });
4851
+ };
4852
+ const partAt = (pos, scope, path, spec, parentType) => {
4853
+ const seen = seenBy(scope, path);
4854
+ const header = seen.headers && rng.chance(.5) ? rng.pick(NAMES) : void 0;
4855
+ const part = docAt({
4856
+ declared: spec.of,
4857
+ kinds: "kinds" in spec ? spec.kinds : void 0,
4858
+ names: seen.names.length === 0 ? pos.names : [...pos.names, ...seen.names],
4859
+ depth: pos.depth + 1,
4860
+ hint: parentType === void 0 ? void 0 : options.hints?.(parentType, path)
4861
+ }, header);
4862
+ saw(scope, path, part);
4863
+ return part;
4864
+ };
4865
+ /** This function builds a value of a shape (SHAPE.*). A part is a document at the next depth. */
4866
+ const valueOf = (shape, path, pos, scope, type) => {
4867
+ const source = scope.sources.get(path.join("."));
4868
+ if (source !== void 0 && "list" in source) return [...source.list];
4869
+ if (source !== void 0 && "text" in source) return source.text;
4870
+ const term = (of) => of === void 0 ? { shape: "term" } : {
4871
+ shape: "term",
4872
+ of
4873
+ };
4874
+ const small = () => pos.depth >= maxDepth ? 0 : size >= maxSize ? rng.int(2) : rng.int(4);
4875
+ if (shape === void 0 || shape.shape === "none") return path.length === 0 && type !== void 0 ? dataOf(type) : anyJson();
4876
+ switch (shape.shape) {
4877
+ case "term": return partAt(pos, scope, path, shape, type);
4878
+ case "list": {
4879
+ const items = Array.from({ length: small() }, (_, index) => valueOf(shape.item ?? term(shape.of), [...path, index], pos, scope, type));
4880
+ if (shape.distinct !== true || rng.chance(malformed)) return items;
4881
+ return items.filter((item, index) => !items.slice(0, index).some((before) => docEquals(before, item)));
4882
+ }
4883
+ case "map": {
4884
+ const out = {};
4885
+ const names = source !== void 0 && "keys" in source ? source.keys : Array.from({ length: small() }, () => rng.pick(FIELDS));
4886
+ for (const key of names) Object.defineProperty(out, key, {
4887
+ value: valueOf(shape.item ?? term(shape.of), [...path, key], pos, scope, type),
4888
+ enumerable: true,
4889
+ writable: true,
4890
+ configurable: true
4891
+ });
4892
+ return out;
4893
+ }
4894
+ case "record": {
4895
+ const named = Array.isArray(shape.fields) ? Object.fromEntries(shape.fields.map((name) => [name, term(shape.of)])) : shape.fields;
4896
+ const fieldKeys = /* @__PURE__ */ new Set([...shape.required ?? [], ...Object.keys(named).filter(() => rng.chance(.75))]);
4897
+ if (shape.closed !== true && shape.rest === void 0 && rng.chance(.15)) fieldKeys.add("extra");
4898
+ const ordered = rng.chance(.2) ? [...fieldKeys].reverse() : [...fieldKeys];
4899
+ const out = {};
4900
+ for (const key of ordered) {
4901
+ if (rng.chance(malformed / 2) && (shape.required ?? []).includes(key)) continue;
4902
+ const fieldShape = Object.hasOwn(named, key) ? named[key] : shape.rest;
4903
+ Object.defineProperty(out, key, {
4904
+ value: valueOf(fieldShape, [...path, key], pos, scope, type),
4905
+ enumerable: true,
4906
+ writable: true,
4907
+ configurable: true
4908
+ });
4909
+ }
4910
+ if (shape.closed === true && rng.chance(malformed)) out["stray"] = 1;
4911
+ return out;
4912
+ }
4913
+ case "deep": return rng.chance(.5) ? [partAt(pos, scope, [...path, 0], term(shape.of), type), anyJson()] : {
4914
+ at: partAt(pos, scope, [...path, "at"], term(shape.of), type),
4915
+ data: anyJson()
4916
+ };
4917
+ case "text": return rng.chance(malformed) ? 1 : rng.pick([
4918
+ "",
4919
+ "a",
4920
+ "label"
4921
+ ]);
4922
+ case "number": {
4923
+ if (rng.chance(malformed)) return "1";
4924
+ const value = (shape.min ?? -2) + rng.int(5) + (shape.whole === true ? 0 : rng.pick([0, .5]));
4925
+ return shape.max !== void 0 && value > shape.max ? shape.max : value;
4926
+ }
4927
+ case "one": return rng.chance(malformed) ? "other" : rng.pick(shape.values);
4928
+ }
4929
+ };
4930
+ /**
4931
+ * A malformed document: an unknown kind, or an unknown name under a namespace with a fallback. It can also be a
4932
+ * bad shape, a bare value without a type, or a bad reference.
4933
+ */
4934
+ const brokenAt = (pos) => {
4935
+ const roll = rng.int(5);
4936
+ if (roll === 0 && unknownNames.length > 0 && rng.chance(.5)) {
4937
+ const type = rng.pick(unknownNames);
4938
+ const kind = kindOf(type);
4939
+ return envelope(type, kind?.parts === void 0 ? dataOf(type) : valueOf(kind.parts, [], pos, scopeOf(kind), type));
4940
+ }
4941
+ if (roll === 0) return {
4942
+ type: rng.pick(["nothing", ["no", "such"]]),
4943
+ value: 1
4944
+ };
4945
+ if (roll === 1) return pos.declared === void 0 ? rng.pick([
4946
+ 7,
4947
+ "bare",
4948
+ [1]
4949
+ ]) : {
4950
+ type: "ref",
4951
+ value: ["names", "unbound"]
4952
+ };
4953
+ if (roll === 2) {
4954
+ const shaped = types.filter((type) => kindOf(type)?.parts !== void 0);
4955
+ if (shaped.length > 0) return envelope(rng.pick(shaped), rng.pick([
4956
+ 7,
4957
+ "x",
4958
+ null
4959
+ ]));
4960
+ }
4961
+ if (roll === 3) return {
4962
+ type: "ref",
4963
+ value: rng.pick([
4964
+ ["names", "unbound"],
4965
+ ["nowhere"],
4966
+ "names"
4967
+ ])
4968
+ };
4969
+ return {
4970
+ type: rng.pick(types),
4971
+ value: anyJson()
4972
+ };
4973
+ };
4974
+ const docAt = (pos, header) => {
4975
+ size += 1;
4976
+ const leaf = pos.depth >= maxDepth || size >= maxSize;
4977
+ if (rng.chance(malformed)) return brokenAt(pos);
4978
+ if (pos.declared !== void 0 && rng.chance(leaf ? .7 : .3)) {
4979
+ const bare = dataOf([pos.declared]);
4980
+ if (!isEnvelope(bare) || permitted(typePath(bare.type) ?? [], pos.kinds)) return bare;
4981
+ }
4982
+ let candidates = types.filter((type) => permitted(type, pos.kinds) && (!leaf || leafKind(kindOf(type))));
4983
+ if (pos.hint !== void 0 && rng.chance(.6)) {
4984
+ const hinted = candidates.filter((type) => pos.hint?.some((hint) => hint.length === type.length && hint.every((key, index) => key === type[index])));
4985
+ if (hinted.length > 0) candidates = hinted;
4986
+ }
4987
+ if (candidates.length === 0) candidates = [...types];
4988
+ const type = rng.pick(candidates);
4989
+ const kind = kindOf(type);
4990
+ if (type.length === 1 && type[0] === "ref") return envelope(type, pathFor(pos, kind), header);
4991
+ const value = kind === void 0 ? dataOf(type) : valueOf(kind.parts, [], pos, scopeOf(kind), type);
4992
+ return envelope(type, value, header);
4993
+ };
4994
+ return docAt({
4995
+ declared: options.declaredType,
4996
+ kinds: void 0,
4997
+ names: options.names ?? [],
4998
+ depth: 0,
4999
+ hint: void 0
5000
+ });
3796
5001
  }
3797
5002
  //#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 };
5003
+ 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, formulaKnown, 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, partsOf, 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
5004
 
3800
5005
  //# sourceMappingURL=index.js.map