@mark1russell7/coeval 0.24.0 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -1568,7 +1568,7 @@ const MAX_TEXT_VALUES = 8;
1568
1568
  /** The most characters of one JSON value in the text of a type. */
1569
1569
  const MAX_TEXT_VALUE = 40;
1570
1570
  /** This function gives a short text of a JSON value for the text of a type. */
1571
- function valueText$1(value) {
1571
+ function valueText$2(value) {
1572
1572
  let text;
1573
1573
  try {
1574
1574
  text = JSON.stringify(value) ?? String(value);
@@ -1590,7 +1590,7 @@ function textAt(type, depth, wrap) {
1590
1590
  if (term === "one") {
1591
1591
  if (!Array.isArray(type["one"])) return "unknown";
1592
1592
  const values = type["one"];
1593
- const shown = values.slice(0, MAX_TEXT_VALUES).map(valueText$1);
1593
+ const shown = values.slice(0, MAX_TEXT_VALUES).map(valueText$2);
1594
1594
  return group(values.length > MAX_TEXT_VALUES ? [...shown, `… ${values.length - MAX_TEXT_VALUES} more`] : shown);
1595
1595
  }
1596
1596
  if (term === "fn") {
@@ -4812,7 +4812,8 @@ function compileNode(c, value, place, declared, depth, address = false) {
4812
4812
  } catch (error) {
4813
4813
  return failingWith(c, meta, placed(thrown(error, `the runner ${name}`), place));
4814
4814
  }
4815
- const run = placedRun(inner, place, name);
4815
+ const guard = guardOf(c, place);
4816
+ const run = placedRun(guard === void 0 ? inner : guardRun(inner, guard, c.machine.domains), place, name);
4816
4817
  return finish$1(c, meta, runnerCode(run, place, kindText), run);
4817
4818
  }
4818
4819
  let inner;
@@ -4821,7 +4822,8 @@ function compileNode(c, value, place, declared, depth, address = false) {
4821
4822
  } catch (error) {
4822
4823
  return failingWith(c, meta, placed(thrown(error, `the evaluator ${name}`), place));
4823
4824
  }
4824
- const done = finish$1(c, meta, TOTAL.has(inner) ? inner : placedCode(inner, place, name), void 0);
4825
+ const guard = guardOf(c, place);
4826
+ const done = finish$1(c, meta, guard !== void 0 ? placedCode(guardCode(inner, guard, c.machine.domains), place, name) : TOTAL.has(inner) ? inner : placedCode(inner, place, name), void 0);
4825
4827
  if (frees === void 0 || kind === void 0 || !pureCode(c, envelope, kind, typePath, name, quick)) return done;
4826
4828
  const free = freeOf(doc, kind, split.parts, frees);
4827
4829
  if (free === void 0) return done;
@@ -5217,6 +5219,29 @@ function gated(rules, part) {
5217
5219
  * This function gives the steps of a runner, with the place of each error and of each exception. The steps get the
5218
5220
  * context that its grant permits (CAP.NARROW-CODE).
5219
5221
  */
5222
+ /** This function gives the key of a place in the guards of a plan. */
5223
+ function guardKey(place) {
5224
+ return JSON.stringify(place.map(String));
5225
+ }
5226
+ /** This function gives the type of the boundary at a place, when the plan has one (PLAN.GUARD). */
5227
+ function guardOf(c, place) {
5228
+ return c.guards?.get(guardKey(place));
5229
+ }
5230
+ /** This function gives the result of a part of a boundary: a value that is not a member gives `#VALUE!` (PLAN.GUARD). */
5231
+ function guarded(result, type, domains) {
5232
+ if (!result.ok || member(result.value, type, domains)) return result;
5233
+ return fail("#VALUE!", `The value is not a member of ${typeText(type)}, the type of its boundary.`);
5234
+ }
5235
+ /** This function adds the test of a boundary to the code of a part. */
5236
+ function guardCode(inner, type, domains) {
5237
+ return (ctx, rt) => guarded(inner(ctx, rt), type, domains);
5238
+ }
5239
+ /** This function adds the test of a boundary to the steps of a part. */
5240
+ function guardRun(inner, type, domains) {
5241
+ return function* (ctx, rt) {
5242
+ return guarded(yield* inner(ctx, rt), type, domains);
5243
+ };
5244
+ }
5220
5245
  function placedRun(inner, place, name) {
5221
5246
  return function* (ctx, rt) {
5222
5247
  try {
@@ -5417,6 +5442,7 @@ function prepare(machine, doc, options = {}) {
5417
5442
  const traced = options.trace === true;
5418
5443
  const fold = !traced && options.fold !== false;
5419
5444
  const fixed = fold ? fixedNamesOf(options.fixed?.names) : void 0;
5445
+ const guards = options.guards === void 0 || options.guards.length === 0 ? void 0 : new Map(options.guards.map((each) => [guardKey(each.place), each.type]));
5420
5446
  const c = {
5421
5447
  machine,
5422
5448
  traced,
@@ -5424,7 +5450,8 @@ function prepare(machine, doc, options = {}) {
5424
5450
  verb,
5425
5451
  noAnswer,
5426
5452
  fold,
5427
- fixed
5453
+ fixed,
5454
+ guards
5428
5455
  };
5429
5456
  let root;
5430
5457
  try {
@@ -5537,7 +5564,8 @@ function evaluate(machine, doc, context = makeContext(), options) {
5537
5564
  const plan = prepare(machine, doc, {
5538
5565
  trace: true,
5539
5566
  ...declaredType === void 0 ? {} : { declaredType },
5540
- ...given.verb === void 0 ? {} : { verb: given.verb }
5567
+ ...given.verb === void 0 ? {} : { verb: given.verb },
5568
+ ...given.guards === void 0 ? {} : { guards: given.guards }
5541
5569
  });
5542
5570
  const ctx = rootContext(machine, context);
5543
5571
  const s = new Session(machine, ctx.caps, false, true, given.perform, void 0, void 0, readingOf(given.reads, ctx));
@@ -5558,6 +5586,7 @@ async function run(machine, doc, context = makeContext(), options = {}) {
5558
5586
  const plan = prepare(machine, doc, {
5559
5587
  trace: true,
5560
5588
  ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
5589
+ ...options.guards === void 0 ? {} : { guards: options.guards },
5561
5590
  ...options.verb === void 0 ? {} : { verb: options.verb }
5562
5591
  });
5563
5592
  const ctx = rootContext(machine, context);
@@ -5928,7 +5957,8 @@ const STD_WORLD = {
5928
5957
  * A literal in a place that takes a document gets its data envelope (K159, D65). Such a place is a part of `if`,
5929
5958
  * `list`, `seq` or `pure`, the value of `write`, or the whole text. The document after a header name is such a place
5930
5959
  * too. Thus `list(1, "a")` evaluates to `[1, "a"]`. The forms `add`, `multiply` and `greater` write an operator document that its operator
5931
- * does not write, for example `add(5)` (K163).
5960
+ * does not write, for example `add(5)` (K163). The field `with` of `handle` is a field of data, thus each clause is a
5961
+ * record between braces in a list between brackets (D177).
5932
5962
  *
5933
5963
  * A host with more kinds spreads this profile and adds its forms to `calls.forms`. `STD_SYNTAX` stays the profile of
5934
5964
  * the formula kit.
@@ -6068,6 +6098,18 @@ const WORLD_SYNTAX = /* @__PURE__ */ Object.freeze({
6068
6098
  kind: "tree.quote",
6069
6099
  args: "literal"
6070
6100
  },
6101
+ {
6102
+ name: "handle",
6103
+ kind: "handle",
6104
+ args: "named",
6105
+ fields: [
6106
+ "with",
6107
+ "return",
6108
+ "body"
6109
+ ],
6110
+ data: ["with"],
6111
+ wrap: ["return", "body"]
6112
+ },
6071
6113
  {
6072
6114
  name: "add",
6073
6115
  kind: "add"
@@ -6524,6 +6566,7 @@ function leaderOnHost(n, key, rule, host) {
6524
6566
  /**
6525
6567
  * This function gives an attribute of a node with circular attributes, or an attribute in an open fixed point (D113).
6526
6568
  * The memo and the marks of the node do not hold the attribute. An open fixed point does not use the cells of the host.
6569
+ * With the cells of a host, only a circular attribute comes here outside a fixed point. A plain attribute takes its cell.
6527
6570
  */
6528
6571
  function circularRead(n, key) {
6529
6572
  const rule = circularRule(n.tree, key);
@@ -6938,7 +6981,7 @@ function treeThing(input, place, build, outer, host) {
6938
6981
  const text = attributeText(key, type, place);
6939
6982
  if (marks.has(key)) return busyAt(state, key);
6940
6983
  if (tree === void 0 && up?.tree === void 0 && !parts.some((item) => item.key === key)) return void 0;
6941
- if (circular || openPoint !== void 0) return circularRead(state, key);
6984
+ if (openPoint !== void 0 || circular && circularRule(tree, key) !== void 0) return circularRead(state, key);
6942
6985
  marks.set(key, BUSY);
6943
6986
  demands.push({
6944
6987
  cells: marks,
@@ -7270,6 +7313,26 @@ function isOp(value) {
7270
7313
  return typeof value === "string" || Array.isArray(value) && value.every(isKey);
7271
7314
  }
7272
7315
  /**
7316
+ * This function gives the runner of an `if` with its own truth (RUN.IF-TRUTH). A branch can wait for the host, thus a
7317
+ * language with the function `truthy` of a profile does not need a copy of `if`. A missing test and a test without a
7318
+ * truth give `#VALUE!`, a failed test gives its failure, and a missing branch gives `null`.
7319
+ *
7320
+ * @param truth - The function that gives the truth of a value, or `undefined` for a value without a truth.
7321
+ * @returns The runner.
7322
+ */
7323
+ function ifRunner(truth) {
7324
+ return function* ({ parts }) {
7325
+ const test = parts.find((part) => part.key === "test");
7326
+ if (test === void 0) return fail("#VALUE!", "if needs a test.");
7327
+ const chosen = yield* test.evaluate();
7328
+ if (!chosen.ok) return chosen;
7329
+ const held = truth(chosen.value);
7330
+ if (held === void 0) return fail("#VALUE!", "The test of if must give a truth value.");
7331
+ const branch = parts.find((part) => part.key === (held ? "then" : "else"));
7332
+ return branch === void 0 ? ok(null) : yield* branch.evaluate();
7333
+ };
7334
+ }
7335
+ /**
7273
7336
  * The runners of the standard world, by name: the kinds that can hold effects. Each one evaluates its parts in
7274
7337
  * order. In a run, an effect ends before the next step starts.
7275
7338
  */
@@ -7337,15 +7400,7 @@ const STD_RUNNERS = {
7337
7400
  }
7338
7401
  });
7339
7402
  },
7340
- "control.if": function* ({ parts }) {
7341
- const test = parts.find((part) => part.key === "test");
7342
- if (test === void 0) return fail("#VALUE!", "if needs a test.");
7343
- const chosen = yield* test.evaluate();
7344
- if (!chosen.ok) return chosen;
7345
- if (typeof chosen.value !== "boolean") return fail("#VALUE!", "The test of if must give a truth value.");
7346
- const branch = parts.find((part) => part.key === (chosen.value === true ? "then" : "else"));
7347
- return branch === void 0 ? ok(null) : yield* branch.evaluate();
7348
- },
7403
+ "control.if": /* @__PURE__ */ ifRunner((value) => typeof value === "boolean" ? value : void 0),
7349
7404
  "list.all": function* ({ parts }) {
7350
7405
  const all = yield* inOrder(parts);
7351
7406
  return "error" in all ? all.error : ok(all.values);
@@ -7768,6 +7823,26 @@ const CONSTRUCTS = [
7768
7823
  * narrows the capabilities for each part, thus the host does not give this type.
7769
7824
  */
7770
7825
  const CAPS_TYPE = { list: { union: ["text", { list: { union: ["text", "number"] } }] } };
7826
+ /**
7827
+ * This function gives the boundaries of a check. A part with an imprecise type at a position that needs a type is a
7828
+ * boundary. A read of a known type is a boundary too, because the check trusts the root types (PLAN.GUARD-BOUNDARY).
7829
+ *
7830
+ * @param typing - The places of a check of types.
7831
+ * @param domains - The domains of the machine.
7832
+ * @returns The boundaries, in the order of the document.
7833
+ */
7834
+ function boundariesOf(typing, domains) {
7835
+ const found = [];
7836
+ for (const item of typing.places) if (item.expected !== void 0 && item.expected !== "unknown" && !isPrecise(item.type, domains)) found.push({
7837
+ place: item.place,
7838
+ type: item.expected
7839
+ });
7840
+ else if (item.read === true && item.type !== "unknown") found.push({
7841
+ place: item.place,
7842
+ type: item.type
7843
+ });
7844
+ return found;
7845
+ }
7771
7846
  /** The roots that can change, as a rule gives them in `PartType.roots`. */
7772
7847
  const CHANGING = [
7773
7848
  "self",
@@ -7787,7 +7862,7 @@ function pathKey(path) {
7787
7862
  function ruleOf(machine, name) {
7788
7863
  if (name === void 0 || machine.runners !== void 0 && Object.hasOwn(machine.runners, name)) return void 0;
7789
7864
  const evaluator = Object.hasOwn(machine.evaluators, name) ? machine.evaluators[name] : void 0;
7790
- const rule = typeof evaluator === "object" && evaluator !== null ? evaluator.type : void 0;
7865
+ const rule = typeof evaluator === "object" && evaluator !== null || typeof evaluator === "function" ? evaluator.type : void 0;
7791
7866
  return typeof rule === "object" && rule !== null && typeof rule.synth === "function" ? rule : void 0;
7792
7867
  }
7793
7868
  /** This function gives the order of the parts of a document: first the parts that give the names of a rule `keysAt`. */
@@ -7968,9 +8043,11 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
7968
8043
  }
7969
8044
  const places = nodes.map((node, index) => {
7970
8045
  const want = needed[index];
8046
+ const read = !node.marked && ruleOf(machine, node.evaluator)?.read === true;
7971
8047
  const entry = {
7972
8048
  type: types[index] ?? "unknown",
7973
- ...want === void 0 ? {} : { expected: want }
8049
+ ...want === void 0 ? {} : { expected: want },
8050
+ ...read ? { read } : {}
7974
8051
  };
7975
8052
  Object.defineProperty(entry, "place", {
7976
8053
  enumerable: true,
@@ -9482,11 +9559,13 @@ function walk(world, doc, visit, options = {}) {
9482
9559
  continue;
9483
9560
  }
9484
9561
  const { sees, later } = scopesOf(kind.scope, doc.value, split.parts);
9562
+ const grantRules = kind.caps !== void 0 && kind.caps.some((rule) => rule.rule === "grant") ? kind.caps : void 0;
9485
9563
  for (let index = split.parts.length - 1; index >= 0; index -= 1) {
9486
9564
  const slot = split.parts[index];
9487
9565
  const extra = sees[index] ?? [];
9488
9566
  const hidden = later[index] ?? [];
9489
- const grants = partGrants(kind.caps, slot.path, doc.value);
9567
+ const grants = grantRules === void 0 ? void 0 : partGrants(grantRules, slot.path, doc.value);
9568
+ const granted = grants !== void 0 && grants.length > 0 ? grants : void 0;
9490
9569
  stack.push({
9491
9570
  value: slot.item,
9492
9571
  place: slot.path.length === 0 ? item.place : {
@@ -9504,8 +9583,8 @@ function walk(world, doc, visit, options = {}) {
9504
9583
  address: slot.address === true,
9505
9584
  slot: slot.path,
9506
9585
  parent: here,
9507
- caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : [...partCaps(kind.caps, slot.path, item.caps), ...grants],
9508
- handled: grants.length === 0 ? item.handled : [...item.handled ?? [], ...grants],
9586
+ caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : granted === void 0 ? partCaps(kind.caps, slot.path, item.caps) : [...partCaps(kind.caps, slot.path, item.caps), ...granted],
9587
+ handled: granted === void 0 ? item.handled : [...item.handled ?? [], ...granted],
9509
9588
  bound: extra,
9510
9589
  expect: slot.expect
9511
9590
  });
@@ -9595,6 +9674,28 @@ function mapRefs(world, doc, change, options = {}) {
9595
9674
  return out;
9596
9675
  }
9597
9676
  /**
9677
+ * This function changes the documents of a document, from the root to the parts (STATIC.MAPDOCS). The function
9678
+ * `change` reads only the original documents. It decides at each node, and it can stop at a node. The kinds of a
9679
+ * position come from the world, thus this function names no kind. The document is not changed: the function gives a
9680
+ * new document that shares each part without a change.
9681
+ *
9682
+ * @param world - The world of the kinds.
9683
+ * @param doc - The document, as JSON.
9684
+ * @param change - The function that gives the answer for each visit. See `DocChange`.
9685
+ * @param options - The type of a bare root value, and the names that the host binds at the root.
9686
+ * @returns The new document, or `doc` itself when no document changes.
9687
+ */
9688
+ function mapDocs(world, doc, change, options = {}) {
9689
+ let out = doc;
9690
+ walk(world, doc, (visit) => {
9691
+ const next = change(visit);
9692
+ if (next === void 0 || next === "skip") return next;
9693
+ out = setAt(out, visit.at, next.to);
9694
+ return next.into === true ? void 0 : "skip";
9695
+ }, options);
9696
+ return out;
9697
+ }
9698
+ /**
9598
9699
  * This function gives the parts that the code of a runner evaluates itself, without a wait (RUN.DRIVES, D119). The
9599
9700
  * answer of the hook `facts` for the code wins over the contract. The contract describes only the code of its kind for
9600
9701
  * `eval`. Without a declaration, the runner passes each wait of its parts through.
@@ -11161,39 +11262,42 @@ function formulaTypes(profile) {
11161
11262
  });
11162
11263
  return {
11163
11264
  "formula.lit": { synth: (input) => valueType(input.doc.value) },
11164
- "formula.ref": { synth: (input, report) => {
11165
- const path = input.doc.value;
11166
- if (input.address || !Array.isArray(path) || path.length === 0) return "unknown";
11167
- const domains = input.machine.domains;
11168
- const plain = input.machine.plain === true;
11169
- let type;
11170
- let start;
11171
- if (path[0] === "names") {
11172
- const name = path[1];
11173
- if (!isKey(name) || !plain && HEADER_KEYS.has(String(name))) return "unknown";
11174
- type = input.nameType(String(name)) ?? "unknown";
11175
- start = 2;
11176
- } else {
11177
- type = input.rootType(String(path[0]));
11178
- start = 1;
11179
- }
11180
- for (let index = start;; index += 1) {
11181
- if (isUnknown(type, domains) || !plain && holdsEnvelope(type, domains)) return "unknown";
11182
- if (index >= path.length) return type;
11183
- const step = path[index];
11184
- if (!isKey(step)) {
11185
- type = walkType(input, step, type);
11186
- continue;
11265
+ "formula.ref": {
11266
+ read: true,
11267
+ synth: (input, report) => {
11268
+ const path = input.doc.value;
11269
+ if (input.address || !Array.isArray(path) || path.length === 0) return "unknown";
11270
+ const domains = input.machine.domains;
11271
+ const plain = input.machine.plain === true;
11272
+ let type;
11273
+ let start;
11274
+ if (path[0] === "names") {
11275
+ const name = path[1];
11276
+ if (!isKey(name) || !plain && HEADER_KEYS.has(String(name))) return "unknown";
11277
+ type = input.nameType(String(name)) ?? "unknown";
11278
+ start = 2;
11279
+ } else {
11280
+ type = input.rootType(String(path[0]));
11281
+ start = 1;
11187
11282
  }
11188
- const next = stepType(type, step, domains, input.contract);
11189
- if ("missing" in next) {
11190
- const fields = next.missing.length === 0 ? "" : ` Its fields are ${listText(next.missing)}.`;
11191
- report({ reason: `The value at ${path.slice(0, index).map(stepText).join(".")} has no field ${String(step)}.${fields}` });
11192
- return "unknown";
11283
+ for (let index = start;; index += 1) {
11284
+ if (isUnknown(type, domains) || !plain && holdsEnvelope(type, domains)) return "unknown";
11285
+ if (index >= path.length) return type;
11286
+ const step = path[index];
11287
+ if (!isKey(step)) {
11288
+ type = walkType(input, step, type);
11289
+ continue;
11290
+ }
11291
+ const next = stepType(type, step, domains, input.contract);
11292
+ if ("missing" in next) {
11293
+ const fields = next.missing.length === 0 ? "" : ` Its fields are ${listText(next.missing)}.`;
11294
+ report({ reason: `The value at ${path.slice(0, index).map(stepText).join(".")} has no field ${String(step)}.${fields}` });
11295
+ return "unknown";
11296
+ }
11297
+ type = next.type;
11193
11298
  }
11194
- type = next.type;
11195
11299
  }
11196
- } },
11300
+ },
11197
11301
  "formula.record": {
11198
11302
  part: (input, path) => {
11199
11303
  const want = fieldOf(input.expected, String(path[0]), input.machine.domains);
@@ -14702,6 +14806,14 @@ function readsUnknown(reads) {
14702
14806
  function resolutions(reads) {
14703
14807
  return reads.filter((read) => read.free && read.kept !== true);
14704
14808
  }
14809
+ /** This function gives the text of a value of a trace. It does not throw for a bigint or a record with a cycle. */
14810
+ function valueText$1(value) {
14811
+ try {
14812
+ return JSON.stringify(value) ?? describe(value);
14813
+ } catch {
14814
+ return describe(value);
14815
+ }
14816
+ }
14705
14817
  function pathText(path) {
14706
14818
  if (path === void 0) return "no read";
14707
14819
  try {
@@ -14857,6 +14969,96 @@ async function agreeRun(machine, doc, context = makeContext(), options = {}) {
14857
14969
  reads: compared
14858
14970
  };
14859
14971
  }
14972
+ /** The type errors of the kernel, by the evaluator that gives them (STATIC.TYPES-AGREE). */
14973
+ const TYPE_ERRORS = {
14974
+ "formula.op": "#NAME?",
14975
+ "formula.if": "#VALUE!",
14976
+ "formula.and": "#VALUE!",
14977
+ "formula.or": "#VALUE!"
14978
+ };
14979
+ /**
14980
+ * This function examines the agreement rule for types (STATIC.TYPES-AGREE, D148). A document with no issue evaluates
14981
+ * with a trace. Each value of the trace is a member of the type of its place. A value of a precise type is also a member
14982
+ * of the type that its position needs. No document with precise parts gives a type error of the kernel.
14983
+ *
14984
+ * A language imports this function for its own property tests, with `agree`. A failure tells that a signature, a type
14985
+ * rule, a cover or a root type does not hold. A value that breaks a position of an imprecise type ends the promise, and
14986
+ * the result then has `checked: false` (TYPE.GRADUAL).
14987
+ *
14988
+ * @param machine - The world and the code of the evaluators, with their type rules.
14989
+ * @param doc - The document.
14990
+ * @param context - The context. Its roots are members of the root types.
14991
+ * @param options - The options of `check`, with the root types, and `guards`.
14992
+ * @returns The agreement, or the first place that breaks it.
14993
+ */
14994
+ function agreeTypes(machine, doc, context = makeContext(), options = {}) {
14995
+ const typing = typeCheck(machine, doc, options);
14996
+ if (typing.issues.length > 0) return {
14997
+ ok: true,
14998
+ checked: false,
14999
+ values: 0
15000
+ };
15001
+ const keyOf = (path) => JSON.stringify(path.map(String));
15002
+ const places = new Map(typing.places.map((item) => [keyOf(item.place), item]));
15003
+ const domains = machine.domains;
15004
+ const guards = options.guards === true ? boundariesOf(typing, domains) : void 0;
15005
+ const stack = [evaluate(machine, doc, context, {
15006
+ ...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
15007
+ ...guards === void 0 ? {} : { guards }
15008
+ }).trace];
15009
+ const nodes = [];
15010
+ while (stack.length > 0) {
15011
+ const node = stack.pop();
15012
+ nodes.push(node);
15013
+ stack.push(...node.children);
15014
+ }
15015
+ for (const node of nodes) {
15016
+ const place = places.get(keyOf(node.path));
15017
+ if (place?.expected === void 0 || !node.result.ok || isPrecise(place.type, domains)) continue;
15018
+ if (!member(node.result.value, place.expected, domains)) return {
15019
+ ok: true,
15020
+ checked: false,
15021
+ values: 0
15022
+ };
15023
+ }
15024
+ let values = 0;
15025
+ for (const node of nodes.reverse()) {
15026
+ const place = places.get(keyOf(node.path));
15027
+ if (place === void 0) continue;
15028
+ const at = node.path.map(String);
15029
+ if (!node.result.ok) {
15030
+ const parts = node.children.map((child) => places.get(keyOf(child.path)));
15031
+ const decided = node.children.every((child) => child.result.ok) && parts.every((part) => part?.expected !== void 0 && isPrecise(part.type, domains));
15032
+ const code = TYPE_ERRORS[node.answer.evaluator ?? ""];
15033
+ if (decided && node.result.error.code === code) return {
15034
+ ok: false,
15035
+ clause: "error",
15036
+ place: at,
15037
+ reason: `The document gives ${code}, but it checks with no issue.`
15038
+ };
15039
+ continue;
15040
+ }
15041
+ const value = node.result.value;
15042
+ values += 1;
15043
+ if (!member(value, place.type, domains)) return {
15044
+ ok: false,
15045
+ clause: "value",
15046
+ place: at,
15047
+ reason: `The value ${valueText$1(value)} is not a member of ${typeText(place.type)}.`
15048
+ };
15049
+ if (place.expected !== void 0 && !member(value, place.expected, domains)) return {
15050
+ ok: false,
15051
+ clause: "argument",
15052
+ place: at,
15053
+ reason: `The value ${valueText$1(value)} is not a member of the needed type ${typeText(place.expected)}.`
15054
+ };
15055
+ }
15056
+ return {
15057
+ ok: true,
15058
+ checked: true,
15059
+ values
15060
+ };
15061
+ }
14860
15062
  // src/codec-laws.ts
14861
15063
  /** The order of the laws in the list of findings. */
14862
15064
  const ORDER$1 = [
@@ -15280,6 +15482,13 @@ function compileConstructs(given, ops) {
15280
15482
  constructKinds
15281
15483
  };
15282
15484
  }
15485
+ /** This function examines the field `domain` of a call form (D141). A form `literal` of `ext.domain` needs a name, and each other form refuses it. */
15486
+ function compileDomain(given, args) {
15487
+ const writes = args === "literal" && given.kind === "ext.domain";
15488
+ if (writes && (typeof given.domain !== "string" || given.domain === "")) throw new TypeError(`The call form "${given.name}" of ext.domain needs the name of its domain.`);
15489
+ if (!writes && given.domain !== void 0) throw new TypeError(`The call form "${given.name}" takes no domain: only a form literal of ext.domain has one.`);
15490
+ return given.domain;
15491
+ }
15283
15492
  /** This function examines the field `wrap` of a call form (K159). A name that is not a field of the form throws. */
15284
15493
  function compileWrap(given, args) {
15285
15494
  const wrap = given.wrap;
@@ -15291,6 +15500,16 @@ function compileWrap(given, args) {
15291
15500
  return new Set(wrap);
15292
15501
  }
15293
15502
  /** This function gives the types of the data envelopes of a profile (K159), or `undefined` without them. */
15503
+ /** This function examines the field `data` of a call form (D177). Each name is a field of the form, and no name is in `wrap`. */
15504
+ function compileData(given, wrap) {
15505
+ const data = given.data ?? [];
15506
+ if (data.length > 0 && given.fields === void 0) throw new TypeError(`The call form "${given.name}" takes data only with fields.`);
15507
+ for (const name of data) {
15508
+ if (given.fields?.includes(name) !== true) throw new TypeError(`The call form "${given.name}" has no field ${name} for its data.`);
15509
+ if (wrap === true || wrap !== false && wrap.has(name)) throw new TypeError(`The call form "${given.name}" has the field ${name} in wrap and in data.`);
15510
+ }
15511
+ return new Set(data);
15512
+ }
15294
15513
  function compileEnvelopes(given) {
15295
15514
  if (given === void 0) return void 0;
15296
15515
  const out = {};
@@ -15327,17 +15546,22 @@ function compileProfile(profile) {
15327
15546
  if (!FORM_ARGS.includes(args)) throw new TypeError(`The call form "${given.name}" has the unknown arguments ${String(args)}.`);
15328
15547
  if (args === "fields" !== (given.fields !== void 0) && args !== "named") throw new TypeError(`The call form "${given.name}" with the arguments ${args} ${args === "fields" ? "needs" : "takes no"} fields.`);
15329
15548
  if (given.min !== void 0 && (args === "named" || args === "literal")) throw new TypeError(`The call form "${given.name}" with the arguments ${args} takes no min.`);
15549
+ const wrap = compileWrap(given, args);
15330
15550
  const form = {
15331
15551
  name: given.name,
15332
15552
  type,
15333
15553
  args,
15334
15554
  fields: given.fields,
15335
15555
  min: given.min ?? given.fields?.length ?? 0,
15336
- wrap: compileWrap(given, args)
15556
+ wrap,
15557
+ domain: compileDomain(given, args),
15558
+ data: compileData(given, wrap)
15337
15559
  };
15338
15560
  forms.set(form.name, form);
15339
15561
  addTo(formsByKind, key, form);
15340
15562
  }
15563
+ const brackets = [...forms.values()].some((form) => form.data.size > 0);
15564
+ for (const symbol of brackets ? [...ops.prefixSymbols, ...ops.binarySymbols] : []) if (/^[[\]{}]/.test(symbol)) throw new TypeError(`The operator "${symbol}" reads the text of a field of data.`);
15341
15565
  const compiled = {
15342
15566
  ...ops,
15343
15567
  numbers: literals.numbers ?? true,
@@ -15369,7 +15593,8 @@ function compileProfile(profile) {
15369
15593
  ...ops.opWords,
15370
15594
  ...roots
15371
15595
  ]),
15372
- maxDepth: profile.maxDepth ?? 256
15596
+ maxDepth: profile.maxDepth ?? 256,
15597
+ brackets
15373
15598
  };
15374
15599
  compiledProfiles.set(profile, compiled);
15375
15600
  return compiled;
@@ -15828,7 +16053,7 @@ var Parser = class {
15828
16053
  }
15829
16054
  /** This method stops at a token where a group or a list must end. A list can also continue with its separator. */
15830
16055
  noEnd(close, list) {
15831
- const closer = close === ")" ? "parenthesis" : "brace";
16056
+ const closer = closerName(close);
15832
16057
  const before = list ? `"${this.syn.separator}" or a ` : "";
15833
16058
  return this.stop(`A ${before}closing ${closer} is missing.`, this.pos, this.tokenLength());
15834
16059
  }
@@ -15853,16 +16078,31 @@ var Parser = class {
15853
16078
  this.pos += 1;
15854
16079
  return args;
15855
16080
  }
15856
- if (this.pos >= this.text.length) this.stop(`A closing ${close === ")" ? "parenthesis" : "brace"} is missing.`, open, 1);
16081
+ if (this.pos >= this.text.length) this.stop(`A closing ${closerName(close)} is missing.`, open, 1);
15857
16082
  this.noEnd(close, true);
15858
16083
  }
15859
16084
  }
15860
16085
  /**
15861
- * This method reads the entries `key: expr` into a record: the arguments of a form `named` (SYNTAX.RECORD), or the
15862
- * entries between braces without a form (SYNTAX.RECORD-TEXT).
16086
+ * This method reads the argument of a field of data (D177): a list between brackets, a record between braces, or a
16087
+ * document. A literal in it stays its data.
16088
+ */
16089
+ data() {
16090
+ this.skip();
16091
+ const start = this.pos;
16092
+ const c = this.text[start];
16093
+ if (c !== "[" && c !== "{") return this.bound();
16094
+ this.depth += 1;
16095
+ if (this.depth > this.syn.maxDepth) this.stop(`The text is deeper than ${String(this.syn.maxDepth)} levels.`, start, 0);
16096
+ const value = c === "[" ? this.argumentsOf(() => this.data(), "]") : this.entries(void 0, true);
16097
+ this.depth -= 1;
16098
+ return value;
16099
+ }
16100
+ /**
16101
+ * This method reads the entries `key: expr` into a record. The record is the arguments of a form `named`
16102
+ * (SYNTAX.RECORD), or the entries between braces (SYNTAX.RECORD-TEXT). It is also a record of data (D177).
15863
16103
  */
15864
- entries(form) {
15865
- const owner = form === void 0 ? "record" : `form ${form.name}`;
16104
+ entries(form, data = false) {
16105
+ const owner = data ? "record of data" : form === void 0 ? "record" : `form ${form.name}`;
15866
16106
  const value = {};
15867
16107
  const entry = () => {
15868
16108
  this.skip();
@@ -15872,9 +16112,10 @@ var Parser = class {
15872
16112
  this.skip();
15873
16113
  if (key === void 0 || this.text[this.pos] !== ":") this.stop(`Each ${form === void 0 ? "entry" : "argument"} of the ${owner} is a key, a ":" and a document.`, at, Math.max(end - at, this.tokenLength()));
15874
16114
  if (form?.fields !== void 0 && !form.fields.includes(key)) this.stop(`The form ${form.name} has no field ${key}.`, at, end - at);
16115
+ if (data && key === "type") this.stop("A record of data has no key type, because the key type makes a document.", at, end - at);
15875
16116
  if (Object.hasOwn(value, key)) this.stop(`The ${owner} has the field ${key} two times.`, at, end - at);
15876
16117
  this.pos += 1;
15877
- const arg = this.bound();
16118
+ const arg = data || form?.data.has(key) === true ? this.data() : this.bound();
15878
16119
  setOwn$1(value, key, form !== void 0 && wraps(form, key) ? envelop(this.syn, arg) : arg);
15879
16120
  };
15880
16121
  this.argumentsOf(entry, form === void 0 ? "}" : ")");
@@ -15883,11 +16124,19 @@ var Parser = class {
15883
16124
  call(name, start, nameLength) {
15884
16125
  const form = this.syn.forms.get(name);
15885
16126
  if (form?.args === "named") return opDoc(form, this.entries(form));
15886
- const args = this.argumentsOf(() => this.bound());
16127
+ let index = 0;
16128
+ const args = this.argumentsOf(() => {
16129
+ const key = form?.fields?.[index];
16130
+ index += 1;
16131
+ return key !== void 0 && form?.data.has(key) === true ? this.data() : this.bound();
16132
+ });
15887
16133
  if (form?.args === "literal") {
15888
16134
  const [only] = args;
15889
16135
  if (args.length !== 1 || !isScalar(only)) this.stop(`The form ${name} takes one literal that JSON writes.`, start, this.pos - start);
15890
- return opDoc(form, only);
16136
+ return opDoc(form, form.domain === void 0 ? only : {
16137
+ domain: form.domain,
16138
+ data: only
16139
+ });
15891
16140
  }
15892
16141
  if (form !== void 0) {
15893
16142
  const most = form.fields?.length ?? Number.POSITIVE_INFINITY;
@@ -15913,15 +16162,20 @@ var Parser = class {
15913
16162
  /** The end of a recovery. The class `Recovery` throws it, and its method `run` catches it. */
15914
16163
  var End = class {};
15915
16164
  function hasBraces(syn) {
15916
- return syn.constructs.record !== void 0 || syn.constructs.let !== void 0;
16165
+ return syn.constructs.record !== void 0 || syn.constructs.let !== void 0 || syn.brackets;
16166
+ }
16167
+ /** This function gives the name of a closer in a message. */
16168
+ function closerName(close) {
16169
+ return close === ")" ? "parenthesis" : close === "]" ? "bracket" : "brace";
15917
16170
  }
15918
16171
  /** This function gives the closer of an opening bracket of a profile, or `undefined` for each other character. */
15919
16172
  function closerOf(syn, c) {
15920
16173
  if (c === "(") return ")";
16174
+ if (c === "[" && syn.brackets) return "]";
15921
16175
  return c === "{" && hasBraces(syn) ? "}" : void 0;
15922
16176
  }
15923
16177
  function isCloser(syn, c) {
15924
- return c === ")" || c === "}" && hasBraces(syn);
16178
+ return c === ")" || c === "]" && syn.brackets || c === "}" && hasBraces(syn);
15925
16179
  }
15926
16180
  /** This function gives the position after a quoted text at `at`, or after one other character. An open quote gives `Infinity`. */
15927
16181
  function pastToken(syn, text, at) {
@@ -16164,6 +16418,7 @@ function refShape(syn, value) {
16164
16418
  }
16165
16419
  function callName(syn, keys) {
16166
16420
  if (keys.length === 0 || !keys.every((key) => typeof key === "string" && NAME.test(key))) return void 0;
16421
+ if (keys.length > 1 && !syn.fields) return void 0;
16167
16422
  const name = keys.join(".");
16168
16423
  if (syn.forms.has(name) || syn.opWords.has(keys[0])) return void 0;
16169
16424
  return syn.ops === true || syn.ops.has(name) ? name : void 0;
@@ -16186,10 +16441,16 @@ function wrappedShape(syn, doc) {
16186
16441
  const literal = literalShape(syn, doc.value);
16187
16442
  return literal.tag === "text" ? literal : void 0;
16188
16443
  }
16444
+ /** This function tells if a value of `ext.domain` is a record with this domain and its data, and no other key. */
16445
+ function holdsDomain(value, domain) {
16446
+ return isRecord(value) && value["domain"] === domain && Object.hasOwn(value, "data") && Object.keys(value).length === 2;
16447
+ }
16189
16448
  function formShape(syn, form, value) {
16190
16449
  if (form.args === "literal") {
16191
- if (!isScalar(value)) return void 0;
16192
- const literal = literalShape(syn, value);
16450
+ if (form.domain !== void 0 && !holdsDomain(value, form.domain)) return void 0;
16451
+ const data = form.domain === void 0 ? value : value["data"];
16452
+ if (!isScalar(data)) return void 0;
16453
+ const literal = literalShape(syn, data);
16193
16454
  return literal.tag === "text" ? {
16194
16455
  tag: "text",
16195
16456
  text: `${form.name}(${literal.text})`
@@ -16205,7 +16466,8 @@ function formShape(syn, form, value) {
16205
16466
  args: keys.map((key) => [
16206
16467
  key,
16207
16468
  value[key],
16208
- wraps(form, key)
16469
+ wraps(form, key),
16470
+ form.data.has(key)
16209
16471
  ]),
16210
16472
  named: true
16211
16473
  };
@@ -16232,7 +16494,8 @@ function formShape(syn, form, value) {
16232
16494
  args: present.map((key) => [
16233
16495
  key,
16234
16496
  value[key],
16235
- wraps(form, key)
16497
+ wraps(form, key),
16498
+ form.data.has(key)
16236
16499
  ])
16237
16500
  };
16238
16501
  }
@@ -16368,6 +16631,18 @@ function bracesText(syn, record, path, sub) {
16368
16631
  if (!texts.ok) return texts;
16369
16632
  return ok(`{${texts.value.map((text, index) => `${keyText(keys[index])}: ${text}`).join(`${syn.separator} `)}}`);
16370
16633
  }
16634
+ /**
16635
+ * This function writes the argument of a field of data (D177): a list between brackets, or a record between braces.
16636
+ * The function `sub` writes a literal and a document. A record that is an envelope is a document.
16637
+ */
16638
+ function dataText(syn, value, path, sub) {
16639
+ const each = (child, at) => dataText(syn, child, at, sub);
16640
+ if (Array.isArray(value)) {
16641
+ const texts = partTexts(value.map((item, index) => [index, item]), path, each);
16642
+ return texts.ok ? ok(`[${texts.value.join(`${syn.separator} `)}]`) : texts;
16643
+ }
16644
+ return isRecord(value) && !isEnvelope(value) && !Object.hasOwn(value, "type") ? bracesText(syn, value, path, each) : sub(value, path);
16645
+ }
16371
16646
  /** This function writes a construct form (K145). */
16372
16647
  function constructText(syn, shape, sub) {
16373
16648
  if (shape.tag === "record") return bracesText(syn, shape.entries, [], sub);
@@ -16410,8 +16685,8 @@ function printNode(syn, doc, sub) {
16410
16685
  return ok(texts.join("."));
16411
16686
  }
16412
16687
  const texts = [];
16413
- for (const [key, arg, wrapped] of shape.args) {
16414
- const result = sub(arg, [key], wrapped);
16688
+ for (const [key, arg, wrapped, data] of shape.args) {
16689
+ const result = data === true ? dataText(syn, arg, [key], sub) : sub(arg, [key], wrapped);
16415
16690
  if (!result.ok) return result;
16416
16691
  texts.push(shape.named === true ? `${keyText(String(key))}: ${result.value}` : result.value);
16417
16692
  }
@@ -19286,6 +19561,7 @@ function schedule(machine, options = {}) {
19286
19561
  let keptAt = -1;
19287
19562
  const keptNodes = [];
19288
19563
  let keptMet = false;
19564
+ let keptFrom = 0;
19289
19565
  let count = 0;
19290
19566
  let ahead = 0;
19291
19567
  let wanted;
@@ -19356,7 +19632,10 @@ function schedule(machine, options = {}) {
19356
19632
  const reader = stack[stack.length - 1];
19357
19633
  const known = epoch.values.get(id);
19358
19634
  if (known !== void 0) {
19359
- if (reader !== void 0 && onOpen.has(id)) lower(reader, order.get(id));
19635
+ if (reader !== void 0 && onOpen.has(id)) {
19636
+ if (keptAt >= 0 && order.get(id) < keptFrom) keptMet = true;
19637
+ else lower(reader, order.get(id));
19638
+ }
19360
19639
  return known;
19361
19640
  }
19362
19641
  if (busy.has(id)) {
@@ -19560,9 +19839,11 @@ function schedule(machine, options = {}) {
19560
19839
  keeping(read) {
19561
19840
  const outer = keptAt;
19562
19841
  const outerMet = keptMet;
19842
+ const outerFrom = keptFrom;
19563
19843
  const from = keptNodes.length;
19564
19844
  keptAt = stack.length;
19565
19845
  keptMet = false;
19846
+ keptFrom = count;
19566
19847
  try {
19567
19848
  return read();
19568
19849
  } finally {
@@ -19573,6 +19854,7 @@ function schedule(machine, options = {}) {
19573
19854
  }
19574
19855
  keptAt = outer;
19575
19856
  keptMet = outerMet;
19857
+ keptFrom = outerFrom;
19576
19858
  }
19577
19859
  }
19578
19860
  });
@@ -20556,6 +20838,6 @@ function samplesAt(values, closed, depth) {
20556
20838
  function typeFromSamples(values, options = {}) {
20557
20839
  return samplesAt(values, options.closed === true, 0);
20558
20840
  }
20559
- export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, GENERATION_LIMIT, Held, JOURNAL, MAX_SYNTAX_ISSUES, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, capKeys, check, checkCycles, checkLatent, checkStep, checkSteps, checkSyntax, checkWorld, circularOf, classify, codecLaws, collectOf, compilePath, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, documentKey, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partGrants, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, resolveCompiled, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
20841
+ export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, GENERATION_LIMIT, Held, JOURNAL, MAX_SYNTAX_ISSUES, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, agreeTypes, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, boundariesOf, capKeys, check, checkCycles, checkLatent, checkStep, checkSteps, checkSyntax, checkWorld, circularOf, classify, codecLaws, collectOf, compilePath, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, documentKey, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, ifRunner, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapDocs, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partGrants, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, resolveCompiled, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
20560
20842
 
20561
20843
  //# sourceMappingURL=index.js.map