@mark1russell7/coeval 0.16.0 → 0.17.0

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
@@ -577,14 +577,17 @@ function looksLikeKind(value) {
577
577
  const STD_DOMAINS = {
578
578
  null: {
579
579
  is: (value) => value === null,
580
+ values: [null],
580
581
  summary: "The value null."
581
582
  },
582
583
  undefined: {
583
584
  is: (value) => value === void 0,
585
+ values: [void 0],
584
586
  summary: "The value undefined. A document holds it as the extension ext.undefined."
585
587
  },
586
588
  bool: {
587
589
  is: (value) => typeof value === "boolean",
590
+ values: [true, false],
588
591
  summary: "A truth value: true or false."
589
592
  },
590
593
  number: {
@@ -598,6 +601,12 @@ const STD_DOMAINS = {
598
601
  };
599
602
  /** The deepest term that a value type can have. A deeper term reads as `unknown`, thus a check stays total. */
600
603
  const MAX_TYPE_DEPTH = 256;
604
+ /** The most values that the finite rule of `fits` reads for one type (TYPE.FITS-FINITE). A type with more values is not finite for the rule. */
605
+ const MAX_FINITE_VALUES = 64;
606
+ /** The most domains of covers that the cover rule of `fits` tests for one type (TYPE.FITS-COVER). A larger test gives `false`. */
607
+ const MAX_COVER_STEPS = 64;
608
+ /** The most records that one split of `fits` builds, with each split inside its work (TYPE.FITS-PATH, D89). A larger split gives `false`. */
609
+ const MAX_SPLIT_RECORDS = 64;
601
610
  /** The keys that each term permits beside its own key. */
602
611
  const TERM_KEYS = {
603
612
  list: ["list"],
@@ -620,7 +629,7 @@ function domainOf(name, domains) {
620
629
  return typeof found === "object" && found !== null && typeof found.is === "function" ? found : void 0;
621
630
  }
622
631
  /** This function gives the term key of a record, when the record has exactly one term key and no other key. */
623
- function termOf$1(term) {
632
+ function termOf$2(term) {
624
633
  const keys = Object.keys(term);
625
634
  const own = keys.filter((key) => TERMS.includes(key));
626
635
  if (own.length !== 1) return void 0;
@@ -638,7 +647,7 @@ function formOf(type, domains) {
638
647
  };
639
648
  }
640
649
  if (!isRecord(type)) return TOP;
641
- const term = termOf$1(type);
650
+ const term = termOf$2(type);
642
651
  if (term === "list") return {
643
652
  t: "list",
644
653
  item: type["list"]
@@ -745,39 +754,358 @@ function member(value, type, domains) {
745
754
  return memberAt(value, type, domains, 0);
746
755
  }
747
756
  /** This function tells if the record type `a` fits the record type `b`: width, closed records and optional fields. */
748
- function recordFits(a, b, domains, depth, gradual) {
757
+ function recordFits(a, b, domains, depth, gradual, budget) {
749
758
  if (b.closed && (!a.closed || Object.keys(a.fields).some((key) => !Object.hasOwn(b.fields, key)))) return false;
750
759
  for (const key of Object.keys(b.fields)) {
751
760
  const want = b.fields[key];
752
761
  const needed = !b.optional.has(key);
753
762
  if (Object.hasOwn(a.fields, key)) {
754
763
  if (needed && a.optional.has(key)) return false;
755
- if (!fitsAt(a.fields[key], want, domains, depth, gradual)) return false;
764
+ if (!fitsAt(a.fields[key], want, domains, depth, gradual, true, budget)) return false;
756
765
  } else if (needed) return false;
757
766
  else if (!a.closed && formOf(want, domains).t !== "top") return false;
758
767
  }
759
768
  return true;
760
769
  }
770
+ /** This function adds a value to a list of distinct values, by `docEquals`. */
771
+ function addValue(out, value) {
772
+ if (!out.some((item) => docEquals(item, value))) out.push(value);
773
+ }
774
+ /**
775
+ * This function gives the values of a base type with a finite list. It reads the list of the first domain of the line
776
+ * with at most 64 values, and it keeps only the members of the type. Thus the list of a parent serves each domain under it.
777
+ */
778
+ function baseValues(name, domains) {
779
+ const domain = domainOf(name, domains);
780
+ if (domain === void 0) return void 0;
781
+ const line = Array.isArray(domain.values) || !Array.isArray(domain.under) ? [name] : lineOf(name, domains);
782
+ for (const each of line) {
783
+ const values = domainOf(each, domains)?.values;
784
+ if (!Array.isArray(values) || values.length > MAX_FINITE_VALUES) continue;
785
+ const out = [];
786
+ for (let index = 0; index < values.length; index += 1) if (inDomain(values[index], name, domains)) addValue(out, values[index]);
787
+ return out;
788
+ }
789
+ }
790
+ /** This function gives a copy of a record with one more field. */
791
+ function withField(record, key, value) {
792
+ const out = {};
793
+ for (const name of Object.keys(record)) setOwn$6(out, name, record[name]);
794
+ setOwn$6(out, key, value);
795
+ return out;
796
+ }
797
+ /**
798
+ * This function gives the members of a record type, when they are few. A record with a needed field without members
799
+ * has no members. Only a closed record with a finite list for each field has a finite list.
800
+ */
801
+ function recordValues(form, domains, depth) {
802
+ let out = [{}];
803
+ let finite = form.closed;
804
+ for (const key of Object.keys(form.fields)) {
805
+ const values = valuesOf$1(form.fields[key], domains, depth);
806
+ const optional = form.optional.has(key);
807
+ if (values === void 0) {
808
+ finite = false;
809
+ continue;
810
+ }
811
+ if (values.length === 0 && !optional) return [];
812
+ if (!finite) continue;
813
+ if (out.length * (values.length + (optional ? 1 : 0)) > MAX_FINITE_VALUES) {
814
+ finite = false;
815
+ continue;
816
+ }
817
+ out = out.flatMap((record) => [...optional ? [record] : [], ...values.map((value) => withField(record, key, value))]);
818
+ }
819
+ return finite ? out : void 0;
820
+ }
821
+ /**
822
+ * This function gives a list of the members of a type, when the type has at most 64 members (TYPE.FITS-FINITE). Each
823
+ * other type gives `undefined`. Such a type is `unknown`, a base type without a finite list, or a function type. A
824
+ * list that can hold an item and an open record with members are also such types.
825
+ */
826
+ function valuesOf$1(type, domains, depth) {
827
+ if (depth > MAX_TYPE_DEPTH) return void 0;
828
+ const form = formOf(type, domains);
829
+ const next = depth + 1;
830
+ switch (form.t) {
831
+ case "bottom": return [];
832
+ case "base": return baseValues(form.name, domains);
833
+ case "list": return valuesOf$1(form.item, domains, next)?.length === 0 ? [[]] : void 0;
834
+ case "record": return recordValues(form, domains, next);
835
+ case "one":
836
+ case "union": {
837
+ const out = [];
838
+ const items = form.t === "one" ? form.values : form.members;
839
+ for (const item of items) {
840
+ const values = form.t === "one" ? [item] : valuesOf$1(item, domains, next);
841
+ if (values === void 0) return void 0;
842
+ for (const value of values) addValue(out, value);
843
+ if (out.length > MAX_FINITE_VALUES) return void 0;
844
+ }
845
+ return out;
846
+ }
847
+ default: return;
848
+ }
849
+ }
850
+ /** This function gives the members of a type at one depth, for `membersOf`. */
851
+ function membersAt(type, domains, samples, depth) {
852
+ const finite = valuesOf$1(type, domains, depth);
853
+ if (finite !== void 0) return finite;
854
+ const form = formOf(type, domains);
855
+ if (form.t !== "union" || depth > MAX_TYPE_DEPTH) return samples.filter((sample) => member(sample, type, domains));
856
+ const out = [];
857
+ for (const item of form.members) for (const value of membersAt(item, domains, samples, depth + 1)) addValue(out, value);
858
+ return out;
859
+ }
860
+ /**
861
+ * This function gives members of a type for a test of a declaration (D86). A type with at most 64 members gives each
862
+ * member, from the lists `values` of its domains (TYPE.FITS-FINITE). A union gives the members of each of its types.
863
+ * Each other type gives the samples that are its members. The kernel does not export the function.
864
+ *
865
+ * @param type - The type.
866
+ * @param domains - The domains of the machine.
867
+ * @param samples - The values to test when the type has no full list of members.
868
+ * @returns Distinct members of the type.
869
+ */
870
+ function membersOf(type, domains, samples) {
871
+ return membersAt(type, domains, samples, 0);
872
+ }
873
+ /** This function holds the rules of the shapes of `fits`: base types, lists, records and functions. */
874
+ function shapeFits(a, b, domains, next, gradual, budget) {
875
+ if (a.t === "base") return b.t === "base" && lineOf(a.name, domains).has(b.name);
876
+ if (a.t === "list") return b.t === "list" && fitsAt(a.item, b.item, domains, next, gradual, true, budget);
877
+ if (a.t === "record") return b.t === "record" && recordFits(a, b, domains, next, gradual, budget);
878
+ if (a.t !== "fn" || b.t !== "fn" || a.params.length > b.params.length) return false;
879
+ return a.params.every((param, index) => fitsAt(b.params[index], param, domains, next, gradual, true, budget)) && fitsAt(a.to, b.to, domains, next, gradual, true, budget);
880
+ }
761
881
  /**
762
882
  * This function is the relation `fits` at one depth of two types. The order of its tests is the order of the rules of
763
883
  * `fits`. Without `gradual`, `unknown` is only the top: it fits only `unknown`. The join uses this strict form.
884
+ *
885
+ * When the rules of the shapes refuse a type with few members, the finite rule tests each member (TYPE.FITS-FINITE).
886
+ * The cover rule and the split rule come after it. Without `finite`, the call skips these three rules. The members of
887
+ * a union in `expected` get such calls, because the call for the union tests `found` against the full union.
888
+ *
889
+ * The budget is the budget of the outer split, when the call is part of the work of a split (TYPE.FITS-PATH, D89).
764
890
  */
765
- function fitsAt(found, expected, domains, depth, gradual = true) {
891
+ function fitsAt(found, expected, domains, depth, gradual = true, finite = true, budget) {
766
892
  if (depth > MAX_TYPE_DEPTH) return true;
767
893
  const a = formOf(found, domains);
768
894
  const b = formOf(expected, domains);
769
895
  const next = depth + 1;
770
896
  if (b.t === "top" || a.t === "bottom") return true;
771
897
  if (a.t === "top") return gradual;
772
- if (a.t === "union") return a.members.every((item) => fitsAt(item, expected, domains, next, gradual));
898
+ if (a.t === "union") return a.members.every((item) => fitsAt(item, expected, domains, next, gradual, true, budget));
773
899
  if (a.t === "one") return a.values.every((item) => memberAt(item, expected, domains, next));
774
- if (b.t === "bottom") return false;
775
- if (b.t === "union") return b.members.some((item) => fitsAt(found, item, domains, next, gradual));
776
- if (a.t === "base") return b.t === "base" && lineOf(a.name, domains).has(b.name);
777
- if (a.t === "list") return b.t === "list" && fitsAt(a.item, b.item, domains, next, gradual);
778
- if (a.t === "record") return b.t === "record" && recordFits(a, b, domains, next, gradual);
779
- if (b.t !== "fn" || a.params.length > b.params.length) return false;
780
- return a.params.every((param, index) => fitsAt(b.params[index], param, domains, next, gradual)) && fitsAt(a.to, b.to, domains, next, gradual);
900
+ if (b.t === "union" ? b.members.some((item) => fitsAt(found, item, domains, next, gradual, false, budget)) : b.t !== "bottom" && shapeFits(a, b, domains, next, gradual, budget)) return true;
901
+ if (!finite || a.t === "fn") return false;
902
+ const values = valuesOf$1(found, domains, next);
903
+ if (values !== void 0) return values.every((value) => memberAt(value, expected, domains, next));
904
+ if (a.t === "base") return (b.t === "union" || b.t === "one") && lineCovered(a.name, expected, domains, depth, gradual, void 0);
905
+ return a.t === "record" && (b.t === "union" || b.t === "one" && a.closed) && splitFits(found, a, expected, domains, depth, gradual, budget);
906
+ }
907
+ /**
908
+ * This function is the cover rule of `fits` (TYPE.FITS-COVER, D85). A base type fits when a domain of its line has a
909
+ * cover, and each domain of the cover fits `expected`. The function makes the state at the first domain with covers.
910
+ */
911
+ function lineCovered(name, expected, domains, depth, gradual, state) {
912
+ let now = state;
913
+ for (const each of lineOf(name, domains)) {
914
+ if (!Array.isArray(domainOf(each, domains)?.covers)) continue;
915
+ now ??= {
916
+ held: /* @__PURE__ */ new Map(),
917
+ left: MAX_COVER_STEPS
918
+ };
919
+ if (covered(each, expected, domains, depth, gradual, now)) return true;
920
+ }
921
+ return false;
922
+ }
923
+ /**
924
+ * This function tells if a cover of one domain holds the domain in `expected`. A cover that is empty, or that names
925
+ * the domain or a name that is not under it, does not count. Each domain of a cover costs one step, and the rule
926
+ * stops after 64 steps.
927
+ */
928
+ function covered(name, expected, domains, depth, gradual, state) {
929
+ const known = state.held.get(name);
930
+ if (known !== void 0) return known;
931
+ state.held.set(name, false);
932
+ const covers = domainOf(name, domains)?.covers;
933
+ if (!Array.isArray(covers)) return false;
934
+ for (const cover of covers) {
935
+ if (!Array.isArray(cover) || cover.length === 0) continue;
936
+ let held = true;
937
+ for (const part of cover) {
938
+ state.left -= 1;
939
+ if (state.left < 0) return false;
940
+ if (typeof part !== "string" || part === name || !lineOf(part, domains).has(name) || !partFits(part, expected, domains, depth, gradual, state)) {
941
+ held = false;
942
+ break;
943
+ }
944
+ }
945
+ if (held) {
946
+ state.held.set(name, true);
947
+ return true;
948
+ }
949
+ }
950
+ return false;
951
+ }
952
+ /** This function tells if a domain of a cover fits `expected`. It tries the rules of the shapes, the finite rule and its own covers. */
953
+ function partFits(part, expected, domains, depth, gradual, state) {
954
+ if (fitsAt(part, expected, domains, depth, gradual, false)) return true;
955
+ const values = valuesOf$1(part, domains, depth + 1);
956
+ if (values !== void 0) return values.every((value) => memberAt(value, expected, domains, depth + 1));
957
+ return lineCovered(part, expected, domains, depth, gradual, state);
958
+ }
959
+ /**
960
+ * This function gives the fields that the split rule can split, in the order of the split (TYPE.FITS-PATH, D89). The
961
+ * fields of the record come first, in the order of the keys. Then the paths of the next depth follow, and so on. A path
962
+ * goes into a field only when the field is a record without a finite list. A field with a finite list of two or more
963
+ * cases is a split. An optional field also has the absent case.
964
+ *
965
+ * The type splits follow each value split, in the same order (D90). A base type with a valid cover in its line splits
966
+ * into the domains of the cover. A union without a finite list splits into its members. The prefix is the path of `a`.
967
+ */
968
+ function splitsOf(a, domains, depth, prefix = []) {
969
+ const out = [];
970
+ const later = [];
971
+ let level = [{
972
+ path: prefix,
973
+ form: a
974
+ }];
975
+ for (let at = depth + 1; level.length > 0 && at <= MAX_TYPE_DEPTH; at += 1) {
976
+ const deeper = [];
977
+ for (const { path, form } of level) for (const key of Object.keys(form.fields)) {
978
+ const values = valuesOf$1(form.fields[key], domains, at);
979
+ const optional = form.optional.has(key);
980
+ if (values !== void 0) {
981
+ if (values.length + (optional ? 1 : 0) > 1) out.push({
982
+ path: [...path, key],
983
+ values,
984
+ optional
985
+ });
986
+ continue;
987
+ }
988
+ const inner = formOf(form.fields[key], domains);
989
+ if (inner.t === "record") deeper.push({
990
+ path: [...path, key],
991
+ form: inner
992
+ });
993
+ else if (inner.t === "union") later.push({
994
+ path: [...path, key],
995
+ types: inner.members,
996
+ optional
997
+ });
998
+ else if (inner.t === "base") {
999
+ const cover = coverOf(inner.name, domains, false);
1000
+ if (cover !== void 0) later.push({
1001
+ path: [...path, key],
1002
+ types: cover,
1003
+ optional
1004
+ });
1005
+ }
1006
+ }
1007
+ level = deeper;
1008
+ }
1009
+ return later.length === 0 ? out : [...out, ...later];
1010
+ }
1011
+ /** This function tells if a cover of a domain is valid by the line rule of D85. Such a cover is not empty, and each name in it is a domain under the domain. */
1012
+ function validCover(name, cover, domains) {
1013
+ return Array.isArray(cover) && cover.length > 0 && cover.every((part) => typeof part === "string" && part !== name && lineOf(part, domains).has(name));
1014
+ }
1015
+ /**
1016
+ * This function gives the cover of a base type for a type split (D90). The cover is the first valid cover of the first
1017
+ * domain in the line with a valid cover. With `own`, only the domain of the type itself counts. Each other type gives
1018
+ * `undefined`.
1019
+ */
1020
+ function coverOf(name, domains, own) {
1021
+ for (const each of own ? [name] : lineOf(name, domains)) {
1022
+ const covers = domainOf(each, domains)?.covers;
1023
+ if (!Array.isArray(covers)) continue;
1024
+ for (const cover of covers) if (validCover(each, cover, domains)) return cover;
1025
+ }
1026
+ }
1027
+ /**
1028
+ * This function gives the splits of a case of a type split, at the path of the case (D90). A case with a finite list
1029
+ * splits by its members. A base type splits by a cover of its own domain, because the covers of its parents hold it
1030
+ * already. A union splits by its members, and a record splits by the paths into its fields.
1031
+ */
1032
+ function againOf(type, path, domains, depth) {
1033
+ const at = depth + path.length;
1034
+ const values = valuesOf$1(type, domains, at);
1035
+ if (values !== void 0) return values.length > 1 ? [{
1036
+ path,
1037
+ values,
1038
+ optional: false
1039
+ }] : [];
1040
+ const form = formOf(type, domains);
1041
+ if (form.t === "record") return splitsOf(form, domains, at, path);
1042
+ if (form.t === "union") return [{
1043
+ path,
1044
+ types: form.members,
1045
+ optional: false
1046
+ }];
1047
+ const cover = form.t === "base" ? coverOf(form.name, domains, true) : void 0;
1048
+ return cover === void 0 ? [] : [{
1049
+ path,
1050
+ types: cover,
1051
+ optional: false
1052
+ }];
1053
+ }
1054
+ /**
1055
+ * This function gives a copy of a record type with one field narrowed at a path. A case type replaces the field. The
1056
+ * absent case removes the field of a closed record, and it gives an optional field of type `never` in an open record.
1057
+ */
1058
+ function narrowAt(type, path, at, narrowed, domains) {
1059
+ const form = formOf(type, domains);
1060
+ const key = path[at];
1061
+ if (form.t !== "record" || key === void 0) return type;
1062
+ const last = at + 1 === path.length;
1063
+ const fields = {};
1064
+ for (const name of Object.keys(form.fields)) if (name !== key) setOwn$6(fields, name, form.fields[name]);
1065
+ else if (!last) setOwn$6(fields, name, narrowAt(form.fields[name], path, at + 1, narrowed, domains));
1066
+ else if (narrowed !== void 0) setOwn$6(fields, name, narrowed);
1067
+ else if (!form.closed) setOwn$6(fields, name, "never");
1068
+ const optional = [...form.optional].filter((name) => !last || name !== key || narrowed === void 0 && !form.closed);
1069
+ return {
1070
+ record: fields,
1071
+ ...optional.length === 0 ? {} : { optional },
1072
+ ...form.closed ? { closed: true } : {}
1073
+ };
1074
+ }
1075
+ /**
1076
+ * This function is the split rule of `fits` (TYPE.FITS-FINITE, D84, TYPE.FITS-PATH, D89). A record type fits when each
1077
+ * record of its split fits. A split takes the first field in the order of `splitsOf`. Each member of the field gives a
1078
+ * record with the field narrowed to that member. An optional field also gives a record without the field. A type split
1079
+ * narrows the field to each case type instead (TYPE.FITS-SPLIT-TYPE, D90).
1080
+ *
1081
+ * A record of the split that does not fit splits the next such field. A record of a type split first splits its case
1082
+ * again, at the same path. One budget of 64 records serves the outer split and each split inside its work, at each
1083
+ * depth. Thus nested splits do not multiply the work.
1084
+ */
1085
+ function splitFits(found, a, expected, domains, depth, gradual, budget) {
1086
+ const splits = splitsOf(a, domains, depth);
1087
+ if (splits.length === 0) return false;
1088
+ return casesFit(found, a.closed, splits, 0, expected, domains, depth, gradual, budget ?? { left: MAX_SPLIT_RECORDS });
1089
+ }
1090
+ /** This function tells if each record of the split of one field fits `expected`. It splits the next field for a record that does not fit. */
1091
+ function casesFit(type, closed, splits, index, expected, domains, depth, gradual, budget) {
1092
+ const split = splits[index];
1093
+ if (split === void 0) return false;
1094
+ const cases = (split.values?.map((value) => ({ one: [value] })) ?? split.types ?? []).map((each) => narrowAt(type, split.path, 0, each, domains));
1095
+ if (split.optional) cases.push(narrowAt(type, split.path, 0, void 0, domains));
1096
+ for (const [at, record] of cases.entries()) {
1097
+ budget.left -= 1;
1098
+ if (budget.left < 0) return false;
1099
+ if (fitsAt(record, expected, domains, depth, gradual, false, budget)) continue;
1100
+ const values = closed ? valuesOf$1(record, domains, depth + 1) : void 0;
1101
+ if (values !== void 0) {
1102
+ if (values.every((value) => memberAt(value, expected, domains, depth + 1))) continue;
1103
+ return false;
1104
+ }
1105
+ const again = split.types !== void 0 && at < split.types.length ? againOf(split.types[at], split.path, domains, depth) : [];
1106
+ if (!casesFit(record, closed, again.length === 0 ? splits : [...again, ...splits.slice(index + 1)], again.length === 0 ? index + 1 : 0, expected, domains, depth, gradual, budget)) return false;
1107
+ }
1108
+ return true;
781
1109
  }
782
1110
  /**
783
1111
  * This function tells if each value of the type `found` can be where the type `expected` must be (TYPE.FITS). Each
@@ -794,9 +1122,33 @@ function fitsAt(found, expected, domains, depth, gradual = true) {
794
1122
  * field is `unknown`.
795
1123
  * - A function fits when it has the same or fewer parameters, each expected parameter fits its parameter, and its
796
1124
  * result fits.
797
- *
798
- * The relation is sound: a member of `found` is a member of `expected` when no `unknown` is in the types. It is not
799
- * complete. For example, `bool` does not fit `{ "one": [true, false] }`. The function does not throw.
1125
+ * - The finite rule comes after these rules (TYPE.FITS-FINITE). A type with at most 64 members fits when each member
1126
+ * is a member of `expected`. Thus `bool` fits `{ "one": [true, false] }`.
1127
+ * - A base type has few members when its domain or a parent declares `values`, as `null`, `undefined` and `bool` do.
1128
+ * A union, a `one`, a closed record of such types and a list of `never` also have few members.
1129
+ * - The cover rule comes next (TYPE.FITS-COVER, D85). A base type fits a union or a `one` when each domain of a cover
1130
+ * fits. The cover is in `covers` of a domain of its line. Each domain of a cover is under the covered
1131
+ * domain. Thus a cover of `number` by `neg` and `nonneg` gives `number` a fit against `neg | nonneg`.
1132
+ * - The split rule comes last (D84). An open record, or a closed record with more than 64 members, splits a field with
1133
+ * few members over a union. A closed record also splits over a `one`. Each record of the split narrows the field to
1134
+ * one member, and each record must fit.
1135
+ * Thus `{ "record": { "a": "bool" } }` fits a union of a record for each value of `a`.
1136
+ * - A split also narrows a field of a record in a field, by its path (TYPE.FITS-PATH, D89). The fields of the record
1137
+ * split first, then the paths of each next depth, in the order of the keys. A path goes into a record without a
1138
+ * finite list. Thus `{a: {x: bool}}` fits the union of `{a: {x: true}}` and `{a: {x: false}}`.
1139
+ * - A type split comes after each value split (TYPE.FITS-SPLIT-TYPE, D90). A field of a base type with a valid cover in
1140
+ * its line splits into the domains of the first such cover. A field of a union without a finite list splits into its
1141
+ * members. A case that does not fit splits again at its path, by the same rules. A base type there uses only a
1142
+ * cover of its own domain. Thus `{a: number}` fits `{a: neg} | {a: nonneg}` when `neg` and `nonneg` cover `number`.
1143
+ *
1144
+ * The relation is sound: a member of `found` is a member of `expected` when no `unknown` is in the types
1145
+ * (TYPE.FITS-SOUND). The finite rule trusts `values`, and the cover rule trusts `covers`. Thus a list without a member
1146
+ * or a false cover makes the relation unsound for that domain.
1147
+ *
1148
+ * The relation is not complete. A split builds at most 64 records, with each split inside its work at each depth. A
1149
+ * type split uses one cover of a field, not each cover of its line. A domain without `values` gets no finite rule, and
1150
+ * neither does a type with more than 64 members that is not a record. The cover rule tests at most 64 domains of
1151
+ * covers. The function does not throw.
800
1152
  *
801
1153
  * @param found - The type that a part has.
802
1154
  * @param expected - The type that the position needs.
@@ -807,7 +1159,7 @@ function fits(found, expected, domains) {
807
1159
  return fitsAt(found, expected, domains, 0);
808
1160
  }
809
1161
  /** This function sets an own field of a new record. Only the key `__proto__` needs `defineProperty`. */
810
- function setOwn$5(target, key, value) {
1162
+ function setOwn$6(target, key, value) {
811
1163
  if (key === "__proto__") Object.defineProperty(target, key, {
812
1164
  value,
813
1165
  enumerable: true,
@@ -826,10 +1178,10 @@ function joinRecords(a, b, domains, depth) {
826
1178
  const inA = Object.hasOwn(a.fields, key);
827
1179
  const inB = Object.hasOwn(b.fields, key);
828
1180
  if (inA && inB) {
829
- setOwn$5(fields, key, joinAt(a.fields[key], b.fields[key], domains, depth));
1181
+ setOwn$6(fields, key, joinAt(a.fields[key], b.fields[key], domains, depth));
830
1182
  if (a.optional.has(key) || b.optional.has(key)) optional.push(key);
831
1183
  } else if (closed) {
832
- setOwn$5(fields, key, inA ? a.fields[key] : b.fields[key]);
1184
+ setOwn$6(fields, key, inA ? a.fields[key] : b.fields[key]);
833
1185
  optional.push(key);
834
1186
  }
835
1187
  }
@@ -932,7 +1284,7 @@ function valueText$1(value) {
932
1284
  function textAt(type, depth, wrap) {
933
1285
  if (depth > MAX_TYPE_DEPTH) return "unknown";
934
1286
  if (typeof type === "string") return type;
935
- const term = isRecord(type) ? termOf$1(type) : void 0;
1287
+ const term = isRecord(type) ? termOf$2(type) : void 0;
936
1288
  if (!isRecord(type) || term === void 0) return "unknown";
937
1289
  const next = depth + 1;
938
1290
  const group = (items) => items.length === 0 ? "never" : items.length > 1 && wrap ? `(${items.join(" | ")})` : items.join(" | ");
@@ -1155,7 +1507,7 @@ function typeIssues(type, domains) {
1155
1507
  if (here !== "unknown" && here !== "never" && domainOf(here, domains) === void 0) issue(`The machine has no domain ${here}.`);
1156
1508
  continue;
1157
1509
  }
1158
- const term = isRecord(here) ? termOf$1(here) : void 0;
1510
+ const term = isRecord(here) ? termOf$2(here) : void 0;
1159
1511
  if (!isRecord(here) || term === void 0) {
1160
1512
  issue(`A value type is a text, or a record with one of the keys ${TERMS.join(", ")} and the keys that go with it.`);
1161
1513
  continue;
@@ -1233,7 +1585,7 @@ function keyOf(path) {
1233
1585
  return JSON.stringify(path.map(String));
1234
1586
  }
1235
1587
  /** This function sets an own data property. An assignment to the key `__proto__` changes the prototype. */
1236
- function setOwn$4(target, key, value) {
1588
+ function setOwn$5(target, key, value) {
1237
1589
  if (key === "__proto__") Object.defineProperty(target, key, {
1238
1590
  value,
1239
1591
  enumerable: true,
@@ -1250,7 +1602,7 @@ function defined(value) {
1250
1602
  if (Array.isArray(value)) return value.map(defined);
1251
1603
  if (!isRecord(value)) return value;
1252
1604
  const out = {};
1253
- for (const key of Object.keys(value)) if (value[key] !== void 0) setOwn$4(out, key, defined(value[key]));
1605
+ for (const key of Object.keys(value)) if (value[key] !== void 0) setOwn$5(out, key, defined(value[key]));
1254
1606
  return out;
1255
1607
  }
1256
1608
  /** Two values are the same when they are equal by `docEquals`. A function and a host value are equal only to themselves. */
@@ -1259,23 +1611,38 @@ function same(a, b) {
1259
1611
  }
1260
1612
  /**
1261
1613
  * Two domains are the same when they are one object. They are also the same when they have the same test `is`,
1262
- * parents, summary and steps. Thus two languages that give one test under one name give one domain.
1614
+ * parents, summary, steps, codec, list of values and covers. Thus two languages that give one test under one name give one
1615
+ * domain. Two codecs are the same when they have the same functions `encode` and `decode` (D80).
1263
1616
  */
1264
1617
  function sameDomain(a, b) {
1265
- return a === b || a.is === b.is && same(a.under ?? [], b.under ?? []) && a.summary === b.summary && same(a.steps ?? {}, b.steps ?? {});
1618
+ if (a === b) return true;
1619
+ const fields = {
1620
+ is: a.is === b.is,
1621
+ under: same(a.under ?? [], b.under ?? []),
1622
+ summary: a.summary === b.summary,
1623
+ steps: same(a.steps ?? {}, b.steps ?? {}),
1624
+ codec: same(a.codec ?? null, b.codec ?? null),
1625
+ values: same(a.values ?? null, b.values ?? null),
1626
+ covers: same(a.covers ?? [], b.covers ?? [])
1627
+ };
1628
+ return Object.values(fields).every(Boolean);
1266
1629
  }
1267
1630
  /**
1268
- * This function makes a part of a merge that adds parents or steps to a domain of an earlier part (TYPE.PARENTS). An
1269
- * example is a domain of another language. The part reads the domain from the merge before it (`prev`). It gives a
1270
- * copy with the same test and summary, and it names `["domains", name]` in `replaces` (D17). A domain of the kernel
1271
- * that the earlier parts do not name comes from `STD_DOMAINS`.
1631
+ * This function makes a part of a merge that adds parents, steps or covers to a domain of an earlier part
1632
+ * (TYPE.PARENTS). An example is a domain of another language. The part reads the domain from the merge before it
1633
+ * (`prev`). It gives a copy with the same test, summary, codec and list of values, and it names `["domains", name]`
1634
+ * in `replaces` (D17).
1635
+ * A domain of the kernel that the earlier parts do not name comes from `STD_DOMAINS`.
1636
+ *
1637
+ * An extension does not change the codec. Thus each member keeps its document (D80).
1272
1638
  *
1273
1639
  * A new parent adds its test to the domain (TYPE.MEMBER). Thus `fits` stays sound, but a value that fails the test of
1274
1640
  * the parent is no longer a member. The language that adds the parent keeps the signatures of the other language
1275
- * true. A name without a domain gives an empty part, and `typeIssues` reports each use of that name.
1641
+ * true. A new parent of a domain in a cover of another domain can make that cover false (D85). A name without a
1642
+ * domain gives an empty part, and `typeIssues` reports each use of that name.
1276
1643
  *
1277
1644
  * @param name - The name of the domain.
1278
- * @param more - The parents and the steps to add.
1645
+ * @param more - The parents, the steps and the covers to add.
1279
1646
  * @returns The part, as a function of the merge before it.
1280
1647
  */
1281
1648
  function extendDomain(name, more) {
@@ -1288,14 +1655,21 @@ function extendDomain(name, more) {
1288
1655
  ...found.steps,
1289
1656
  ...more.steps
1290
1657
  };
1291
- const domain = {
1658
+ const covers = [...found.covers ?? []];
1659
+ for (const cover of more.covers ?? []) if (!covers.some((each) => same(each, cover))) covers.push([...cover]);
1660
+ const fields = {
1292
1661
  is: found.is,
1293
- ...under.length === 0 ? {} : { under },
1294
- ...found.summary === void 0 ? {} : { summary: found.summary },
1295
- ...Object.keys(steps).length === 0 ? {} : { steps }
1662
+ under: under.length === 0 ? void 0 : under,
1663
+ summary: found.summary,
1664
+ steps: Object.keys(steps).length === 0 ? void 0 : steps,
1665
+ codec: found.codec,
1666
+ values: found.values,
1667
+ covers: covers.length === 0 ? void 0 : covers
1296
1668
  };
1669
+ const domain = {};
1670
+ for (const [key, value] of Object.entries(fields)) if (value !== void 0) domain[key] = value;
1297
1671
  const domains = {};
1298
- setOwn$4(domains, name, domain);
1672
+ setOwn$5(domains, name, domain);
1299
1673
  return {
1300
1674
  domains,
1301
1675
  replaces: [["domains", name]]
@@ -1345,10 +1719,10 @@ function mergeLeaf(m, table, key, later, path, part, replaces, equal, reason) {
1345
1719
  if (later === void 0) return;
1346
1720
  const earlier = own$2(table, key);
1347
1721
  if (earlier === void 0) {
1348
- setOwn$4(table, key, later);
1722
+ setOwn$5(table, key, later);
1349
1723
  m.give(path, part);
1350
1724
  } else if (replaces.has(keyOf(path))) {
1351
- setOwn$4(table, key, later);
1725
+ setOwn$5(table, key, later);
1352
1726
  m.replace(path, part);
1353
1727
  } else if (!equal(earlier, later)) m.clash(path, part, reason);
1354
1728
  }
@@ -1369,9 +1743,9 @@ function mergeEntries(m, into, from, path, part, replaces) {
1369
1743
  const at = [...path, key];
1370
1744
  const earlier = own$2(into, key);
1371
1745
  if (earlier === void 0) {
1372
- setOwn$4(into, key, later);
1746
+ setOwn$5(into, key, later);
1373
1747
  m.give(at, part);
1374
- } else setOwn$4(into, key, mergeEntry(m, earlier, later, at, part, replaces));
1748
+ } else setOwn$5(into, key, mergeEntry(m, earlier, later, at, part, replaces));
1375
1749
  }
1376
1750
  }
1377
1751
  /** This function merges two entries at one path. Two namespaces merge key by key, and their fallbacks merge too. */
@@ -1524,8 +1898,8 @@ function mergeCode(m, draft, part, index, replaces) {
1524
1898
  const runnerPath = ["runners", name];
1525
1899
  if (replaces.has(keyOf(evaluatorPath)) || replaces.has(keyOf(runnerPath))) {
1526
1900
  if (evaluator === void 0) delete draft.evaluators[name];
1527
- else setOwn$4(draft.evaluators, name, evaluator);
1528
- if (runner !== void 0) setOwn$4(draft.runners ??= {}, name, runner);
1901
+ else setOwn$5(draft.evaluators, name, evaluator);
1902
+ if (runner !== void 0) setOwn$5(draft.runners ??= {}, name, runner);
1529
1903
  else if (draft.runners !== void 0) delete draft.runners[name];
1530
1904
  m.replace(evaluatorPath, index);
1531
1905
  m.replace(runnerPath, index);
@@ -1648,7 +2022,7 @@ function removeEntry(entries, path) {
1648
2022
  }
1649
2023
  const out = { ...entries };
1650
2024
  if (next === void 0) delete out[key];
1651
- else setOwn$4(out, key, next);
2025
+ else setOwn$5(out, key, next);
1652
2026
  return out;
1653
2027
  }
1654
2028
  /**
@@ -2043,11 +2417,12 @@ function derefStep(nav, thing, key) {
2043
2417
  const derefs = nav.derefs;
2044
2418
  const answer = derefs === void 0 ? void 0 : answerOf(nav.world, ownEntries(envelope), kindFor(nav.world, envelope.type), "deref", (name) => codeIn(derefs, name));
2045
2419
  if (answer !== void 0) {
2046
- const reached = derefs[answer.name]?.(envelope, key);
2047
- return reached === void 0 ? void 0 : {
2420
+ const code = derefs[answer.name];
2421
+ const reached = code?.(envelope, key);
2422
+ return reached !== void 0 || code?.has?.(envelope, key) === true ? {
2048
2423
  thing: reached,
2049
2424
  by: answer.rung
2050
- };
2425
+ } : void 0;
2051
2426
  }
2052
2427
  const reached = plainStep(envelope.value, key);
2053
2428
  return reached === NOTHING ? void 0 : {
@@ -2285,6 +2660,25 @@ function resolve(nav, ctx, path, options = {}) {
2285
2660
  }
2286
2661
  return resolveFully$1(nav, ctx, path, options.hops === false ? void 0 : [], void 0);
2287
2662
  }
2663
+ /** The functions of the last navigator that gave a walker its input. A walk with the same navigator makes no new functions. */
2664
+ let lastSteps;
2665
+ /**
2666
+ * This function gives the functions `deref` and `has` of the input of a walker. They depend only on the navigator,
2667
+ * thus the function keeps the functions of the last navigator (K170).
2668
+ */
2669
+ function walkSteps(nav) {
2670
+ if (lastSteps !== void 0 && lastSteps.nav === nav) return lastSteps;
2671
+ const adopt = nav.adopt;
2672
+ lastSteps = {
2673
+ nav,
2674
+ deref: adopt === void 0 ? (thing, key) => derefStep(nav, thing, key)?.thing : (thing, key) => {
2675
+ const reached = derefStep(nav, thing, key);
2676
+ return reached === void 0 ? void 0 : adopt(reached.thing);
2677
+ },
2678
+ has: (thing, key) => derefStep(nav, thing, key) !== void 0
2679
+ };
2680
+ return lastSteps;
2681
+ }
2288
2682
  /**
2289
2683
  * This function resolves a path with the full algorithm of `resolve`.
2290
2684
  *
@@ -2379,20 +2773,19 @@ function resolveFully$1(nav, ctx, path, hops, known) {
2379
2773
  const walker = given === void 0 ? walkerOf(nav, step) : given ?? void 0;
2380
2774
  if (walker === void 0) return failed("#STEP?", "A step is a key, or a document of a kind with the verb step.");
2381
2775
  const envelope = step;
2382
- const deref = (thing, key) => {
2383
- const reached = derefStep(nav, thing, key);
2384
- return reached === void 0 ? void 0 : adopt(reached.thing);
2385
- };
2776
+ const { deref, has } = walkSteps(nav);
2386
2777
  const result = walker(hops === void 0 ? {
2387
2778
  data: envelope.value,
2388
2779
  here,
2389
2780
  context: ctx,
2390
- deref
2781
+ deref,
2782
+ has
2391
2783
  } : {
2392
2784
  data: envelope.value,
2393
2785
  here,
2394
2786
  context: ctx,
2395
2787
  deref,
2788
+ has,
2396
2789
  visit: (key, thing) => hops.push({
2397
2790
  step: key,
2398
2791
  thing,
@@ -2479,7 +2872,7 @@ var Bad = class {
2479
2872
  }
2480
2873
  };
2481
2874
  /** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
2482
- function setOwn$3(target, key, value) {
2875
+ function setOwn$4(target, key, value) {
2483
2876
  if (key === "__proto__") Object.defineProperty(target, key, {
2484
2877
  value,
2485
2878
  enumerable: true,
@@ -2493,7 +2886,7 @@ function hasSlots(template) {
2493
2886
  return template.t !== "data";
2494
2887
  }
2495
2888
  /** This function gives the shape of a part with the default type `of` and the value type `expect` of its container. */
2496
- function termOf(of, expect) {
2889
+ function termOf$1(of, expect) {
2497
2890
  return {
2498
2891
  shape: "term",
2499
2892
  ...of === void 0 ? {} : { of },
@@ -2602,7 +2995,7 @@ function splitParts(shape, value) {
2602
2995
  const twice = list.findIndex((child, index) => list.slice(0, index).some((before) => docEquals(before, child)));
2603
2996
  if (twice !== -1) throw new Bad("The items of the list must be different.", [...path, twice]);
2604
2997
  }
2605
- const each = spec.item ?? termOf(spec.of, spec.expect);
2998
+ const each = spec.item ?? termOf$1(spec.of, spec.expect);
2606
2999
  const items = list.map((child, index) => walk(each, child, [...path, index]));
2607
3000
  return isData(each) ? {
2608
3001
  t: "data",
@@ -2614,14 +3007,14 @@ function splitParts(shape, value) {
2614
3007
  }
2615
3008
  if (!isRecord(item)) throw new Bad("The value must be a record.", path);
2616
3009
  if (spec.shape === "map") {
2617
- const each = spec.item ?? termOf(spec.of, spec.expect);
3010
+ const each = spec.item ?? termOf$1(spec.of, spec.expect);
2618
3011
  return {
2619
3012
  t: "record",
2620
3013
  fields: Object.keys(item).map((key) => [key, walk(each, item[key], [...path, key])])
2621
3014
  };
2622
3015
  }
2623
3016
  for (const name of spec.required ?? []) if (!Object.hasOwn(item, name)) throw new Bad(`The field ${name} is missing.`, path);
2624
- const named = Array.isArray(spec.fields) ? Object.fromEntries(spec.fields.map((name) => [name, termOf(spec.of, spec.expect)])) : spec.fields;
3017
+ const named = Array.isArray(spec.fields) ? Object.fromEntries(spec.fields.map((name) => [name, termOf$1(spec.of, spec.expect)])) : spec.fields;
2625
3018
  const fields = [];
2626
3019
  for (const key of Object.keys(item)) {
2627
3020
  if (spec.closed === true && !Object.hasOwn(named, key)) throw new Bad(`The field ${key} is not a field of this kind.`, [...path, key]);
@@ -2651,7 +3044,7 @@ function splitParts(shape, value) {
2651
3044
  const out = {};
2652
3045
  for (const [key, child] of node.fields) {
2653
3046
  const kept = strip(child);
2654
- if (kept !== void 0) setOwn$3(out, key, kept);
3047
+ if (kept !== void 0) setOwn$4(out, key, kept);
2655
3048
  }
2656
3049
  return out;
2657
3050
  };
@@ -2660,7 +3053,7 @@ function splitParts(shape, value) {
2660
3053
  if (node.t === "slot") return handles[node.index];
2661
3054
  if (node.t === "list") return node.items.map((child) => fillWith(child, handles));
2662
3055
  const out = {};
2663
- for (const [key, child] of node.fields) setOwn$3(out, key, fillWith(child, handles));
3056
+ for (const [key, child] of node.fields) setOwn$4(out, key, fillWith(child, handles));
2664
3057
  return out;
2665
3058
  };
2666
3059
  return {
@@ -2918,10 +3311,19 @@ const GRANT = /* @__PURE__ */ Symbol("coeval.grant");
2918
3311
  /**
2919
3312
  * The key of the epoch of a grant (CAP.NARROW-KEPT). The epoch is the list of capabilities that the host gave the root
2920
3313
  * of the evaluation of the grant. A spread of a context keeps its epoch, as it keeps its grant. An
2921
- * effect and a resolution read a context of another epoch as a context without a grant.
3314
+ * effect and a resolution read a context of another epoch as a context without a grant. The root has no field of
3315
+ * the epoch, because its grant is the list of the host (`epochOf`).
2922
3316
  */
2923
3317
  const EPOCH = /* @__PURE__ */ Symbol("coeval.epoch");
2924
3318
  /**
3319
+ * This function gives the epoch of the grant of a context (CAP.NARROW-KEPT). A context without the field of the epoch
3320
+ * has the epoch of its grant. Only a root has no field, thus its grant is the list of the host. The root then has
3321
+ * one field fewer, and each evaluation makes it faster (K154).
3322
+ */
3323
+ function epochOf(ctx) {
3324
+ return ctx[EPOCH] ?? ctx[GRANT];
3325
+ }
3326
+ /**
2925
3327
  * This function gives the capabilities that a context and its grant both permit, the meet `intersectCaps` (CAP.MEET).
2926
3328
  * A context whose grant is its own list gives that list after one comparison. A context without a grant gives none.
2927
3329
  */
@@ -2941,10 +3343,36 @@ function granted(ctx) {
2941
3343
  return {
2942
3344
  ...ctx,
2943
3345
  caps,
2944
- [GRANT]: caps
3346
+ [GRANT]: caps,
3347
+ [EPOCH]: epochOf(ctx)
2945
3348
  };
2946
3349
  }
2947
3350
  /**
3351
+ * This function tells if a list of capabilities is equal to the epoch of the evaluation (CAP.EPOCH-EQUAL). An equal list
3352
+ * has the same length, and at each index the same text or the same keys in the same order. The runtime uses it only
3353
+ * when the two lists are not the same object. Thus a host that gives a new copy of its list for each evaluation keeps
3354
+ * the grant of a kept context.
3355
+ */
3356
+ function sameCaps(caps, epoch) {
3357
+ if (caps === void 0 || caps.length !== epoch.length) return false;
3358
+ for (let index = 0; index < caps.length; index += 1) {
3359
+ const a = caps[index];
3360
+ const b = epoch[index];
3361
+ if (a === b) continue;
3362
+ if (typeof a === "string" || typeof b === "string" || a.length !== b.length) return false;
3363
+ for (let key = 0; key < a.length; key += 1) if (!Object.is(a[key], b[key])) return false;
3364
+ }
3365
+ return true;
3366
+ }
3367
+ /**
3368
+ * This function tells if a context has the epoch of the evaluation: the same list, or an equal list (CAP.NARROW-KEPT,
3369
+ * CAP.EPOCH-EQUAL). The comparison of the entries happens only when the two lists are not the same object.
3370
+ */
3371
+ function inEpoch(ctx, epoch) {
3372
+ const own = epochOf(ctx);
3373
+ return own === epoch || sameCaps(own, epoch);
3374
+ }
3375
+ /**
2948
3376
  * This function gives a context of another epoch the epoch of the evaluation, without capabilities (CAP.NARROW-KEPT).
2949
3377
  * Thus the context reads as a context without a grant. The kernel cannot know the document of the context in this
2950
3378
  * evaluation.
@@ -2962,16 +3390,26 @@ function ungranted(ctx, epoch) {
2962
3390
  * The context has the meet of its list and its grant, and a context without a grant has none. Thus a read of the root
2963
3391
  * `caps` and a walker of a step document get the capabilities of the document from a widened context.
2964
3392
  * A context that the code narrowed keeps its own list. A context whose list does not change stays the same object.
2965
- * A context of another epoch has no capabilities (CAP.NARROW-KEPT).
3393
+ *
3394
+ * A context of another epoch has no capabilities (CAP.NARROW-KEPT). An equal list of the host is the same epoch
3395
+ * (CAP.EPOCH-EQUAL). The first test answers for a context of the epoch whose grant is its list, for example the root.
3396
+ * The other contexts go to `readableOther`, thus the hot part of the function stays small (K154).
2966
3397
  */
2967
3398
  function readable(ctx, epoch) {
2968
- if (ctx[EPOCH] !== epoch) return ctx.caps.length === 0 ? ctx : ungranted(ctx, epoch);
3399
+ const grant = ctx[GRANT];
3400
+ if (grant === ctx.caps && (ctx[EPOCH] ?? grant) === epoch) return ctx;
3401
+ return readableOther(ctx, epoch);
3402
+ }
3403
+ /** This function gives the result of `readable` for each other context: a context of another epoch or a narrowed context. */
3404
+ function readableOther(ctx, epoch) {
3405
+ if (!inEpoch(ctx, epoch)) return ctx.caps.length === 0 ? ctx : ungranted(ctx, epoch);
2969
3406
  const caps = grantedCaps(ctx);
2970
3407
  if (caps === ctx.caps || caps.length === 0 && ctx.caps.length === 0) return ctx;
2971
3408
  return {
2972
3409
  ...ctx,
2973
3410
  caps,
2974
- [GRANT]: caps
3411
+ [GRANT]: caps,
3412
+ [EPOCH]: epochOf(ctx)
2975
3413
  };
2976
3414
  }
2977
3415
  /**
@@ -2981,8 +3419,8 @@ function readable(ctx, epoch) {
2981
3419
  */
2982
3420
  function handed(parent, next) {
2983
3421
  const ctx = narrow(parent, next);
2984
- const epoch = parent[EPOCH];
2985
- if (ctx[GRANT] === ctx.caps && ctx[EPOCH] === epoch) return ctx;
3422
+ const epoch = epochOf(parent);
3423
+ if (ctx[GRANT] === ctx.caps && epochOf(ctx) === epoch) return ctx;
2986
3424
  return {
2987
3425
  ...ctx,
2988
3426
  [GRANT]: ctx.caps,
@@ -2990,7 +3428,7 @@ function handed(parent, next) {
2990
3428
  };
2991
3429
  }
2992
3430
  /** The text that names a resolution in the error of an exception of the host. */
2993
- const READ_FAILED = "the resolution of a path";
3431
+ const READ_FAILED$1 = "the resolution of a path";
2994
3432
  /**
2995
3433
  * This function gives what a resolution reached as a result: the thing, or the error with its code and its reason.
2996
3434
  * The record of a read and `verifyReads` share it.
@@ -3019,7 +3457,7 @@ function readAgain(nav, ctx, path, hops) {
3019
3457
  hops: found.hops
3020
3458
  } : { reached: reachedOf(found) };
3021
3459
  } catch (error) {
3022
- return { reached: thrown(error, READ_FAILED) };
3460
+ return { reached: thrown(error, READ_FAILED$1) };
3023
3461
  }
3024
3462
  }
3025
3463
  /**
@@ -3124,7 +3562,7 @@ function keptPath(nav, root, path) {
3124
3562
  } catch (error) {
3125
3563
  return {
3126
3564
  path: path.slice(0, index + 1),
3127
- reached: thrown(error, READ_FAILED)
3565
+ reached: thrown(error, READ_FAILED$1)
3128
3566
  };
3129
3567
  }
3130
3568
  if (step === void 0) return end(index);
@@ -3160,7 +3598,7 @@ function keptAgain(nav, ctx, path) {
3160
3598
  try {
3161
3599
  step = here.known(path[index]);
3162
3600
  } catch (error) {
3163
- return thrown(error, READ_FAILED);
3601
+ return thrown(error, READ_FAILED$1);
3164
3602
  }
3165
3603
  if (step === void 0) return void 0;
3166
3604
  known = true;
@@ -3255,7 +3693,7 @@ var Session = class {
3255
3693
  } catch (error) {
3256
3694
  reading.list.push({
3257
3695
  path,
3258
- reached: thrown(error, READ_FAILED),
3696
+ reached: thrown(error, READ_FAILED$1),
3259
3697
  free
3260
3698
  });
3261
3699
  throw error;
@@ -3343,10 +3781,10 @@ var Session = class {
3343
3781
  * This function checks the capability of an effect, and records the effect with its address (RUN.ADDRESS). The
3344
3782
  * context keeps only the capabilities of its grant, thus compiled code cannot widen the context of its own effect
3345
3783
  * (CAP.NARROW-CODE). A context of another epoch has no capabilities, thus code cannot keep a context for a later
3346
- * evaluation with fewer capabilities (CAP.NARROW-KEPT).
3784
+ * evaluation with fewer capabilities (CAP.NARROW-KEPT). An equal list of the host is the same epoch (CAP.EPOCH-EQUAL).
3347
3785
  */
3348
3786
  record(given, kind, payload, place) {
3349
- const ctx = given[EPOCH] === this.epoch ? granted(given) : ungranted(given, this.epoch);
3787
+ const ctx = inEpoch(given, this.epoch) ? granted(given) : ungranted(given, this.epoch);
3350
3788
  const keys = typeof kind === "string" ? kind.split(".") : kind;
3351
3789
  const text = keys.join(".");
3352
3790
  if (!this.permitted(ctx, keys)) return fail("#CAP!", `The context has no capability for the effect ${text}.`, { place });
@@ -3429,6 +3867,7 @@ var Session = class {
3429
3867
  let failed = false;
3430
3868
  const active = [];
3431
3869
  let next = 0;
3870
+ let before = 0;
3432
3871
  const settle = (index, result) => {
3433
3872
  results[index] = result;
3434
3873
  if (failFast && !result.ok) failed = true;
@@ -3492,10 +3931,11 @@ var Session = class {
3492
3931
  };
3493
3932
  start();
3494
3933
  while (active.length > 0 && !failed) {
3495
- const chosen = journal?.next?.(address, active.map((item) => item.index));
3934
+ const chosen = journal?.next?.(address, active.map((item) => item.index), before);
3496
3935
  const pick = chosen === void 0 ? void 0 : active.find((item) => item.index === chosen);
3497
3936
  const settled = yield pick === void 0 ? Promise.race(active.map((item) => item.pending)) : pick.pending;
3498
3937
  journal?.settled?.(address, settled.item.index);
3938
+ before += 1;
3499
3939
  active.splice(active.indexOf(settled.item), 1);
3500
3940
  advance(settled.item.index, settled.item.steps, settled);
3501
3941
  start();
@@ -4184,7 +4624,8 @@ function gated(rules, part) {
4184
4624
  return {
4185
4625
  ...ctx,
4186
4626
  caps,
4187
- [GRANT]: caps
4627
+ [GRANT]: caps,
4628
+ [EPOCH]: epochOf(ctx)
4188
4629
  };
4189
4630
  };
4190
4631
  return {
@@ -4223,6 +4664,30 @@ function runOf(code) {
4223
4664
  function fillOf(split, doc) {
4224
4665
  return (items) => split.parts.length === 0 ? doc.value : split.fill(items);
4225
4666
  }
4667
+ /**
4668
+ * The key of the runtime on the input of an evaluator. Only the kernel reads it. The node of a tree evaluates its
4669
+ * equations in the evaluation of this runtime, thus their reads go in its list (READS.EQUATION). A copy of the input
4670
+ * with a spread keeps the key.
4671
+ */
4672
+ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
4673
+ /**
4674
+ * This function evaluates a plan inside the evaluation of another runtime, for example an equation of a tree inside
4675
+ * the evaluation of its tree (READS.EQUATION). The plan gets its own runtime, as in `plan.evaluate`. The reads of the
4676
+ * plan go in the record of the reads of `outer`. The context at the root of `outer` tells which reads are free
4677
+ * (READS.FREE). Without such a record, the function gives `plan.evaluate(context)`.
4678
+ *
4679
+ * @param plan - The plan.
4680
+ * @param context - The context of the plan.
4681
+ * @param outer - The runtime of the evaluation around the plan, or `undefined`.
4682
+ * @returns The result.
4683
+ */
4684
+ function evaluateWithin(plan, context, outer) {
4685
+ const reading = outer instanceof Session ? outer.reading : void 0;
4686
+ if (reading === void 0 || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
4687
+ const machine = plan.machine;
4688
+ const ctx = rootContext(machine, context);
4689
+ return plan.code(ctx, new Session(machine, ctx.caps, false, plan.traced, void 0, void 0, void 0, reading));
4690
+ }
4226
4691
  function interpret(fn, input, fill) {
4227
4692
  const { kind, typePath, doc, data, place, machine } = input;
4228
4693
  const address = input.address === true ? { address: true } : {};
@@ -4249,7 +4714,8 @@ function interpret(fn, input, fill) {
4249
4714
  ...address,
4250
4715
  resolve: (path, options) => rt.resolve(ctx, path, options),
4251
4716
  effect: (effectKind, payload) => rt.effect(ctx, effectKind, payload, place),
4252
- fill: refill
4717
+ fill: refill,
4718
+ [RUNTIME]: rt
4253
4719
  });
4254
4720
  };
4255
4721
  }
@@ -4285,18 +4751,27 @@ function interpretRun(fn, input, fill) {
4285
4751
  /**
4286
4752
  * This function gives the context at the root of an evaluation. It is the context of the host, with the world of
4287
4753
  * the machine when the context has none. The host gives the capabilities, thus the root has the grant of each one
4288
- * (CAP.NARROW-CODE). The list of the host is also the epoch of the grant (CAP.NARROW-KEPT). An evaluation and
4289
- * `verifyReads` share it.
4754
+ * (CAP.NARROW-CODE). The list of the host is also the epoch of the grant (CAP.NARROW-KEPT). The root has no field of
4755
+ * the epoch, thus it has the shape of a context before K120 (K154). An evaluation and `verifyReads` share it.
4756
+ *
4757
+ * The function reads the epoch of the context one time, and one test keeps a context that is already a root (K169).
4290
4758
  *
4291
4759
  * @param machine - The machine.
4292
4760
  * @param ctx - The context of the host.
4293
4761
  * @returns The context at the root.
4294
4762
  */
4295
4763
  function rootContext(machine, ctx) {
4296
- if (ctx.world !== null && ctx[GRANT] === ctx.caps && ctx[EPOCH] === ctx.caps) return ctx;
4764
+ const epoch = ctx[EPOCH];
4765
+ if (ctx.world !== null && ctx[GRANT] === ctx.caps && (epoch === void 0 || epoch === ctx.caps)) return ctx;
4766
+ const world = ctx.world === null ? worldThing(machine.world) : ctx.world;
4767
+ if (epoch === void 0) return {
4768
+ ...ctx,
4769
+ world,
4770
+ [GRANT]: ctx.caps
4771
+ };
4297
4772
  return {
4298
4773
  ...ctx,
4299
- world: ctx.world === null ? worldThing(machine.world) : ctx.world,
4774
+ world,
4300
4775
  [GRANT]: ctx.caps,
4301
4776
  [EPOCH]: ctx.caps
4302
4777
  };
@@ -4736,6 +5211,158 @@ const STD_WORLD = {
4736
5211
  },
4737
5212
  defaults: { view: "view.card" }
4738
5213
  };
5214
+ /**
5215
+ * The text syntax of the standard world (K162, D64). The syntax kit (D41) reads it, thus a host of `STD_WORLD` does
5216
+ * not write its own profile. The operators `>`, `+` and `*` make `greater`, `add` and `multiply`. A call form makes
5217
+ * each other kind, and `ref` uses the reference syntax of the kit.
5218
+ *
5219
+ * A literal in a place that takes a document gets its data envelope (K159, D65). Such a place is a part of `if`,
5220
+ * `list`, `seq` or `pure`, the value of `write`, or the whole text. The document after a header name is such a place
5221
+ * too. Thus `list(1, "a")` evaluates to `[1, "a"]`. The forms `add`, `multiply` and `greater` write an operator document that its operator
5222
+ * does not write, for example `add(5)` (K163).
5223
+ *
5224
+ * A host with more kinds spreads this profile and adds its forms to `calls.forms`. `STD_SYNTAX` stays the profile of
5225
+ * the formula kit.
5226
+ */
5227
+ const WORLD_SYNTAX = /* @__PURE__ */ Object.freeze({
5228
+ operators: [
5229
+ {
5230
+ symbol: ">",
5231
+ fixity: "infix",
5232
+ prec: 4,
5233
+ assoc: "none",
5234
+ kind: "greater"
5235
+ },
5236
+ {
5237
+ symbol: "+",
5238
+ fixity: "infix",
5239
+ prec: 5,
5240
+ assoc: "flat",
5241
+ kind: "add"
5242
+ },
5243
+ {
5244
+ symbol: "*",
5245
+ fixity: "infix",
5246
+ prec: 6,
5247
+ assoc: "flat",
5248
+ kind: "multiply"
5249
+ }
5250
+ ],
5251
+ calls: {
5252
+ ops: [],
5253
+ forms: [
5254
+ {
5255
+ name: "if",
5256
+ kind: "if",
5257
+ fields: [
5258
+ "test",
5259
+ "then",
5260
+ "else"
5261
+ ],
5262
+ min: 2,
5263
+ wrap: true
5264
+ },
5265
+ {
5266
+ name: "list",
5267
+ kind: "list",
5268
+ wrap: true
5269
+ },
5270
+ {
5271
+ name: "seq",
5272
+ kind: "seq",
5273
+ wrap: true
5274
+ },
5275
+ {
5276
+ name: "pure",
5277
+ kind: "pure",
5278
+ min: 1,
5279
+ wrap: true
5280
+ },
5281
+ {
5282
+ name: "log",
5283
+ kind: "log",
5284
+ min: 1
5285
+ },
5286
+ {
5287
+ name: "write",
5288
+ kind: "write",
5289
+ fields: ["key", "value"],
5290
+ wrap: ["value"]
5291
+ },
5292
+ {
5293
+ name: "math.sum",
5294
+ kind: "math.sum"
5295
+ },
5296
+ {
5297
+ name: "math.product",
5298
+ kind: "math.product"
5299
+ },
5300
+ {
5301
+ name: "number",
5302
+ kind: "number",
5303
+ args: "literal"
5304
+ },
5305
+ {
5306
+ name: "text",
5307
+ kind: "text",
5308
+ args: "literal"
5309
+ },
5310
+ {
5311
+ name: "bool",
5312
+ kind: "bool",
5313
+ args: "literal"
5314
+ },
5315
+ {
5316
+ name: "panel",
5317
+ kind: "panel",
5318
+ args: "named",
5319
+ fields: [
5320
+ "width",
5321
+ "height",
5322
+ "children"
5323
+ ]
5324
+ },
5325
+ {
5326
+ name: "box",
5327
+ kind: "box",
5328
+ args: "named",
5329
+ fields: [
5330
+ "width",
5331
+ "height",
5332
+ "children"
5333
+ ]
5334
+ },
5335
+ {
5336
+ name: "nearest",
5337
+ kind: "nearest",
5338
+ args: "named",
5339
+ fields: [
5340
+ "type",
5341
+ "follow",
5342
+ "self"
5343
+ ]
5344
+ },
5345
+ {
5346
+ name: "add",
5347
+ kind: "add"
5348
+ },
5349
+ {
5350
+ name: "multiply",
5351
+ kind: "multiply"
5352
+ },
5353
+ {
5354
+ name: "greater",
5355
+ kind: "greater"
5356
+ }
5357
+ ]
5358
+ },
5359
+ literals: { envelopes: {
5360
+ number: "number",
5361
+ text: "text",
5362
+ bool: "bool"
5363
+ } },
5364
+ header: { bind: "=" }
5365
+ });
4739
5366
  function isNumber(value) {
4740
5367
  return typeof value === "number" && Number.isFinite(value);
4741
5368
  }
@@ -4914,6 +5541,7 @@ function plainOf(value, path) {
4914
5541
  */
4915
5542
  function treeThing(input, build, outer) {
4916
5543
  const { parts, context, kind: type, place, machine } = input;
5544
+ const runtime = input[RUNTIME];
4917
5545
  const { tree, of } = contractOf$1(machine, input.typePath);
4918
5546
  const above = stateOf(outer);
4919
5547
  const up = above !== void 0 && above.build === build ? above : void 0;
@@ -5015,12 +5643,12 @@ function treeThing(input, build, outer) {
5015
5643
  read,
5016
5644
  equation(term, names) {
5017
5645
  if (machine === void 0) return fail("#NOEVAL", "The evaluation of an equation needs the machine.");
5018
- return equationPlan(machine, of, term).evaluate({
5646
+ return evaluateWithin(equationPlan(machine, of, term), {
5019
5647
  ...context,
5020
5648
  names,
5021
5649
  caps: NO_CAPS$1,
5022
5650
  self: node
5023
- });
5651
+ }, runtime);
5024
5652
  },
5025
5653
  childNames(child) {
5026
5654
  const children = read("children");
@@ -6310,7 +6938,7 @@ const DOWN_NAMES = /* @__PURE__ */ Object.freeze([
6310
6938
  const FOLD_NAMES = /* @__PURE__ */ Object.freeze(["acc", "item"]);
6311
6939
  /**
6312
6940
  * This function gives each equation of the tree contract of a kind, with the names that it sees (D42). An equation of
6313
- * `equations`, a `unit` and a `default` see no names.
6941
+ * `equations`, a `unit` and a `default` see no names. `check` and `factsOf` read the equations with this one function.
6314
6942
  */
6315
6943
  function equationsOf(kind) {
6316
6944
  const tree = kind.tree;
@@ -6632,9 +7260,11 @@ function partLazy(above, parent, slot) {
6632
7260
  *
6633
7261
  * - `reads`: each free reference, with the root and the keys of its path. A read under a lazy part has the mark
6634
7262
  * `lazy`, for example a read in a branch of `if`. A read after a step document has `exact: false`. A kind that
6635
- * declares `reads` adds a read of each of its roots at each document of the kind.
7263
+ * declares `reads` adds a read of each of its roots at each document of the kind. The first document of a tree
7264
+ * kind also gets the lazy reads of the equations of its kind (FACTS.EQUATIONS). A read from `self` or from a name
7265
+ * of a rung is not one of them, because it is not free (READS.EQUATION).
6636
7266
  * - `side` and `effects`: from the contract of each kind.
6637
- * - `pure`: each kind declares `pure`, and the document has no effect and is not volatile.
7267
+ * - `pure`: each kind declares `pure`, also in an equation, and the document has no effect and is not volatile.
6638
7268
  * - `volatile`: a kind, an operation or a step document declares `volatile`, or the host marks a read.
6639
7269
  *
6640
7270
  * The hook `facts` of the machine answers for a name that a fallback kind covers, for example an operation. Its
@@ -6658,7 +7288,6 @@ function partLazy(above, parent, slot) {
6658
7288
  function factsOf(machine, doc, options = {}) {
6659
7289
  const world = machine.world;
6660
7290
  const hook = machine.facts;
6661
- const verb = options.verb ?? "eval";
6662
7291
  const reads = [];
6663
7292
  const effects = [];
6664
7293
  const above = /* @__PURE__ */ new Map();
@@ -6666,115 +7295,141 @@ function factsOf(machine, doc, options = {}) {
6666
7295
  let pure = true;
6667
7296
  let volatile = false;
6668
7297
  let size = 0;
7298
+ let seen;
6669
7299
  const note = (isPure, isVolatile) => {
6670
7300
  if (isPure !== true) pure = false;
6671
7301
  if (isVolatile === true) volatile = true;
6672
7302
  };
6673
- walk(world, doc, (v) => {
6674
- size += 1;
6675
- const up = v.parent === void 0 ? void 0 : above.get(v.parent);
6676
- const lazy = up !== void 0 && v.parent !== void 0 && (up.lazy || partLazy(up, v.parent, v.slot));
6677
- const kind = v.kind;
6678
- if (kind === void 0) {
6679
- pure = false;
6680
- above.set(v, {
6681
- lazy,
6682
- rules: void 0
6683
- });
6684
- return;
6685
- }
6686
- const code = codeOf(world, v.declared ? void 0 : v.doc.own, kind, verb, "eval");
6687
- const answer = code.name === void 0 ? void 0 : hook?.(v.typePath ?? [], code.name);
6688
- let roots;
6689
- if (code.described) {
6690
- note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
6691
- above.set(v, {
6692
- lazy,
6693
- rules: answer?.lazy ?? kind.lazy
6694
- });
6695
- roots = answer?.reads ?? kind.reads;
6696
- } else {
6697
- note(answer?.pure, answer?.volatile);
6698
- above.set(v, {
6699
- lazy,
6700
- rules: answer?.lazy ?? EACH$1
6701
- });
6702
- roots = answer?.reads;
6703
- }
6704
- for (const root of roots ?? NONE) {
6705
- const read = {
6706
- root,
6707
- keys: NONE,
6708
- exact: true,
6709
- lazy,
6710
- address: false,
6711
- path: [root],
6712
- place: tight(v.place),
6713
- at: tight(v.at)
6714
- };
6715
- reads.push(read);
6716
- if (options.volatile?.(read) === true) volatile = true;
6717
- }
6718
- if (kind.side === "run") side = "run";
6719
- for (const keys of declaredEffects(v)) {
6720
- const text = keys.join(".");
6721
- if (!effects.includes(text)) effects.push(text);
6722
- }
6723
- if (!isRef(v.doc)) return void 0;
6724
- const path = v.doc.value;
6725
- const root = path[0];
6726
- if (typeof root !== "string" || !ROOTS.includes(root)) return void 0;
6727
- let exact = true;
6728
- const keys = [];
6729
- for (let index = 1; index < path.length; index += 1) {
6730
- const step = path[index];
6731
- if (exact && isKey(step)) {
6732
- keys.push(step);
6733
- continue;
6734
- }
6735
- exact = false;
6736
- const found = isEnvelope(step) ? lookupKind(world, step.type) : void 0;
6737
- if (found?.ok !== true) {
6738
- pure = false;
6739
- continue;
6740
- }
6741
- const walker = codeOf(world, step.own, found.kind, "step", "step");
6742
- const stepAnswer = walker.name === void 0 ? void 0 : hook?.(found.path, walker.name);
6743
- if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
6744
- else note(stepAnswer?.pure, stepAnswer?.volatile);
6745
- }
6746
- const first = path[1];
6747
- if (root === "names" && isKey(first) && v.names.has(String(first))) return void 0;
6748
- const read = {
6749
- root,
6750
- keys: tight(keys),
6751
- exact,
6752
- lazy,
6753
- address: v.address === true,
6754
- path,
6755
- place: tight(v.place),
6756
- at: tight(v.at)
6757
- };
7303
+ const add = (read) => {
6758
7304
  reads.push(read);
6759
7305
  if (options.volatile?.(read) === true) volatile = true;
6760
- }, options.declaredType === void 0 ? {} : { declaredType: options.declaredType });
6761
- return {
6762
- reads: tight(reads),
6763
- side,
6764
- effects: tight(effects),
6765
- pure: pure && !volatile && effects.length === 0 && side === "derive",
6766
- volatile,
6767
- size
6768
7306
  };
6769
- }
6770
- //#endregion
6771
- //#region src/effects.ts
6772
- /** Each capability: one capability with no keys. It permits each effect, because each kind starts with no keys (CAP.KEYS). */
6773
- const EACH = /* @__PURE__ */ Object.freeze([[]]);
6774
- /**
6775
- * This function finds each declared effect that can reach the host, in the order of the document. It is the one
6776
- * inference of `effectsOf` and `checkLatent`. `check` and `factsOf` read the same declarations (`declaredEffects`).
6777
- */
7307
+ /**
7308
+ * This function walks a document. Without `node`, it walks the document of the facts. With `node`, it walks an
7309
+ * equation of a tree kind, and each read gets the place of that node: the first document of the kind.
7310
+ */
7311
+ const scan = (term, walkOptions, verb, node) => {
7312
+ walk(world, term, (v) => {
7313
+ if (node === void 0) size += 1;
7314
+ const up = v.parent === void 0 ? void 0 : above.get(v.parent);
7315
+ const lazy = node !== void 0 || up !== void 0 && v.parent !== void 0 && (up.lazy || partLazy(up, v.parent, v.slot));
7316
+ const place = node ?? v;
7317
+ const kind = v.kind;
7318
+ if (kind === void 0) {
7319
+ pure = false;
7320
+ above.set(v, {
7321
+ lazy,
7322
+ rules: void 0
7323
+ });
7324
+ return;
7325
+ }
7326
+ const code = codeOf(world, v.declared ? void 0 : v.doc.own, kind, verb, "eval");
7327
+ const answer = code.name === void 0 ? void 0 : hook?.(v.typePath ?? [], code.name);
7328
+ let roots;
7329
+ if (code.described) {
7330
+ note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
7331
+ above.set(v, {
7332
+ lazy,
7333
+ rules: answer?.lazy ?? kind.lazy
7334
+ });
7335
+ roots = answer?.reads ?? kind.reads;
7336
+ } else {
7337
+ note(answer?.pure, answer?.volatile);
7338
+ above.set(v, {
7339
+ lazy,
7340
+ rules: answer?.lazy ?? EACH$1
7341
+ });
7342
+ roots = answer?.reads;
7343
+ }
7344
+ for (const root of roots ?? NONE) {
7345
+ if (node !== void 0 && root === "self") continue;
7346
+ add({
7347
+ root,
7348
+ keys: NONE,
7349
+ exact: true,
7350
+ lazy,
7351
+ address: false,
7352
+ path: [root],
7353
+ place: tight(place.place),
7354
+ at: tight(place.at)
7355
+ });
7356
+ }
7357
+ if (kind.side === "run") {
7358
+ if (node === void 0) side = "run";
7359
+ else pure = false;
7360
+ }
7361
+ for (const keys of declaredEffects(v)) {
7362
+ if (node !== void 0) {
7363
+ pure = false;
7364
+ continue;
7365
+ }
7366
+ const text = keys.join(".");
7367
+ if (!effects.includes(text)) effects.push(text);
7368
+ }
7369
+ if (kind.tree !== void 0 && !(seen ??= /* @__PURE__ */ new Set()).has(kind)) {
7370
+ seen.add(kind);
7371
+ const of = equationType(kind);
7372
+ for (const { term: equation, names } of equationsOf(kind)) scan(equation, of === void 0 ? { names } : {
7373
+ names,
7374
+ declaredType: of
7375
+ }, "eval", place);
7376
+ }
7377
+ if (!isRef(v.doc)) return void 0;
7378
+ const path = v.doc.value;
7379
+ const root = path[0];
7380
+ if (typeof root !== "string" || !ROOTS.includes(root)) return void 0;
7381
+ if (node !== void 0 && root === "self") return void 0;
7382
+ let exact = true;
7383
+ const keys = [];
7384
+ for (let index = 1; index < path.length; index += 1) {
7385
+ const step = path[index];
7386
+ if (exact && isKey(step)) {
7387
+ keys.push(step);
7388
+ continue;
7389
+ }
7390
+ exact = false;
7391
+ const found = isEnvelope(step) ? lookupKind(world, step.type) : void 0;
7392
+ if (found?.ok !== true) {
7393
+ pure = false;
7394
+ continue;
7395
+ }
7396
+ const walker = codeOf(world, step.own, found.kind, "step", "step");
7397
+ const stepAnswer = walker.name === void 0 ? void 0 : hook?.(found.path, walker.name);
7398
+ if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
7399
+ else note(stepAnswer?.pure, stepAnswer?.volatile);
7400
+ }
7401
+ const first = path[1];
7402
+ if (root === "names" && isKey(first) && v.names.has(String(first))) return void 0;
7403
+ add({
7404
+ root,
7405
+ keys: tight(keys),
7406
+ exact,
7407
+ lazy,
7408
+ address: v.address === true,
7409
+ path,
7410
+ place: tight(place.place),
7411
+ at: tight(place.at)
7412
+ });
7413
+ }, walkOptions);
7414
+ };
7415
+ scan(doc, options.declaredType === void 0 ? {} : { declaredType: options.declaredType }, options.verb ?? "eval", void 0);
7416
+ return {
7417
+ reads: tight(reads),
7418
+ side,
7419
+ effects: tight(effects),
7420
+ pure: pure && !volatile && effects.length === 0 && side === "derive",
7421
+ volatile,
7422
+ size
7423
+ };
7424
+ }
7425
+ //#endregion
7426
+ //#region src/effects.ts
7427
+ /** Each capability: one capability with no keys. It permits each effect, because each kind starts with no keys (CAP.KEYS). */
7428
+ const EACH = /* @__PURE__ */ Object.freeze([[]]);
7429
+ /**
7430
+ * This function finds each declared effect that can reach the host, in the order of the document. It is the one
7431
+ * inference of `effectsOf` and `checkLatent`. `check` and `factsOf` read the same declarations (`declaredEffects`).
7432
+ */
6778
7433
  function reaching(machine, doc, options) {
6779
7434
  const out = [];
6780
7435
  const rule = options.caps === void 0 ? permits : permitsOf(machine);
@@ -6896,7 +7551,7 @@ function domainTypeOf(data, domains) {
6896
7551
  return domain !== void 0 && codecOf(domain) !== void 0 ? data["domain"] : "unknown";
6897
7552
  }
6898
7553
  /** This function sets an own data property. Only the key `__proto__` needs `defineProperty`. */
6899
- function setOwn$2(target, key, value) {
7554
+ function setOwn$3(target, key, value) {
6900
7555
  if (key === "__proto__") Object.defineProperty(target, key, {
6901
7556
  value,
6902
7557
  enumerable: true,
@@ -6971,7 +7626,7 @@ function encodeTerm(value, encoder) {
6971
7626
  else {
6972
7627
  const fields = {};
6973
7628
  const record = value;
6974
- for (const key of Object.keys(record)) setOwn$2(fields, key, encodeTerm(record[key], encoder));
7629
+ for (const key of Object.keys(record)) setOwn$3(fields, key, encodeTerm(record[key], encoder));
6975
7630
  out = {
6976
7631
  type: "record",
6977
7632
  value: fields
@@ -7067,7 +7722,7 @@ function strictTruthy(value) {
7067
7722
  * This function sets an own data property. Only the key `__proto__` needs `defineProperty`: an assignment to it
7068
7723
  * changes the prototype. An assignment is faster for each other key of a new plain object.
7069
7724
  */
7070
- function setOwn$1(target, key, value) {
7725
+ function setOwn$2(target, key, value) {
7071
7726
  if (key === "__proto__") Object.defineProperty(target, key, {
7072
7727
  value,
7073
7728
  enumerable: true,
@@ -7281,11 +7936,28 @@ function paramsOf(value) {
7281
7936
  }
7282
7937
  /**
7283
7938
  * This function makes the type rules of the formula kit for one profile (TYPE.SYNTH, D25). Each evaluator of the kit
7284
- * holds its rule. The rules read the rules of the profile that change a type: `truthy`, `logic`, `otherwise`, `omit`
7285
- * and `sigs`.
7939
+ * holds its rule. The rules read the rules of the profile that change a type: `truthy`, `truthType`, `logic`,
7940
+ * `otherwise`, `omit` and `sigs`.
7286
7941
  */
7287
7942
  function formulaTypes(profile) {
7288
- const truth = profile.truthy === void 0 ? "bool" : void 0;
7943
+ const declared = profile.truthy !== void 0 && profile.truthType !== void 0;
7944
+ const truth = profile.truthy === void 0 ? "bool" : profile.truthType;
7945
+ /**
7946
+ * The need of a test or a term. The check examines a declared type of a truth as a contract, one time. A declared
7947
+ * type with a problem needs nothing, thus one problem gives one issue.
7948
+ */
7949
+ const truthPart = (input, what) => {
7950
+ if (truth === void 0) return {};
7951
+ if (!declared) return {
7952
+ expect: truth,
7953
+ what
7954
+ };
7955
+ const type = input.contract(truth, "truth type of the profile");
7956
+ return typeIssues(type, input.machine.domains).length > 0 ? {} : {
7957
+ expect: type,
7958
+ what
7959
+ };
7960
+ };
7289
7961
  const logicValue = profile.logic === "value";
7290
7962
  const otherwise = Object.hasOwn(profile, "otherwise") ? valueType(profile.otherwise) : "null";
7291
7963
  const lookup = (name) => {
@@ -7321,10 +7993,7 @@ function formulaTypes(profile) {
7321
7993
  };
7322
7994
  };
7323
7995
  const logic = (word) => ({
7324
- part: (_input, path) => truth === void 0 ? {} : {
7325
- expect: truth,
7326
- what: `term ${Number(path[0]) + 1} of ${word}`
7327
- },
7996
+ part: (input, path) => truthPart(input, `term ${Number(path[0]) + 1} of ${word}`),
7328
7997
  synth: (input) => {
7329
7998
  if (!logicValue) return "bool";
7330
7999
  if (input.paths.length === 0) return { one: [word === "and"] };
@@ -7373,7 +8042,7 @@ function formulaTypes(profile) {
7373
8042
  },
7374
8043
  synth: (input) => {
7375
8044
  const fields = {};
7376
- for (const path of input.paths) setOwn$1(fields, String(path[0]), input.typeOf(path));
8045
+ for (const path of input.paths) setOwn$2(fields, String(path[0]), input.typeOf(path));
7377
8046
  const keys = Object.keys(fields);
7378
8047
  return {
7379
8048
  record: fields,
@@ -7396,7 +8065,7 @@ function formulaTypes(profile) {
7396
8065
  part: (input, path) => {
7397
8066
  if (path[0] !== "body") return {};
7398
8067
  const names = {};
7399
- for (const each of input.paths) if (each[0] === "bind" && each.length === 2) setOwn$1(names, String(each[1]), input.typeOf(each));
8068
+ for (const each of input.paths) if (each[0] === "bind" && each.length === 2) setOwn$2(names, String(each[1]), input.typeOf(each));
7400
8069
  return {
7401
8070
  names,
7402
8071
  ...isUnknown(input.expected, input.machine.domains) ? {} : {
@@ -7412,7 +8081,7 @@ function formulaTypes(profile) {
7412
8081
  if (path[0] !== "body") return {};
7413
8082
  const want = fnOf(input.expected, input.machine.domains);
7414
8083
  const names = {};
7415
- paramsOf(input.doc.value).forEach((name, index) => setOwn$1(names, name, want?.params[index] ?? "unknown"));
8084
+ paramsOf(input.doc.value).forEach((name, index) => setOwn$2(names, name, want?.params[index] ?? "unknown"));
7416
8085
  return {
7417
8086
  names,
7418
8087
  ...want === void 0 || isUnknown(want.to, input.machine.domains) ? {} : {
@@ -7468,10 +8137,7 @@ function formulaTypes(profile) {
7468
8137
  } },
7469
8138
  "formula.if": {
7470
8139
  part: (input, path) => {
7471
- if (path[0] === "test") return truth === void 0 ? {} : {
7472
- expect: truth,
7473
- what: "test of if"
7474
- };
8140
+ if (path[0] === "test") return truthPart(input, "test of if");
7475
8141
  return isUnknown(input.expected, input.machine.domains) ? {} : {
7476
8142
  expect: input.expected,
7477
8143
  what: `${String(path[0])} branch of if`
@@ -7545,18 +8211,44 @@ function formulaTypes(profile) {
7545
8211
  function formulaEvaluators(profile = {}) {
7546
8212
  return { ...kitOf(profile).evaluators };
7547
8213
  }
8214
+ /** The evaluators of the kit that read the truth of a value. */
8215
+ const TRUTH_READERS = [
8216
+ "formula.if",
8217
+ "formula.and",
8218
+ "formula.or"
8219
+ ];
8220
+ /** The declared truth of each evaluator of the kit that reads a truth, for `conforms` (D86). */
8221
+ const truthByCode = /* @__PURE__ */ new WeakMap();
8222
+ /**
8223
+ * This function gives the declared truth of the profile of an evaluator of the kit (D86). Only `formula.if`,
8224
+ * `formula.and` and `formula.or` of a profile with an own `truthy` and a `truthType` have one. The kernel does not
8225
+ * export the function.
8226
+ *
8227
+ * @param code - The evaluator or the runner.
8228
+ * @returns The declared truth, or `undefined`.
8229
+ */
8230
+ function declaredTruthOf(code) {
8231
+ return (typeof code === "object" || typeof code === "function") && code !== null ? truthByCode.get(code) : void 0;
8232
+ }
7548
8233
  /** This function makes new evaluators of the formula kit for the fields of one profile. */
7549
8234
  function makeEvaluators(profile) {
7550
8235
  const evaluators = formulaCode(profile);
7551
8236
  const types = formulaTypes(profile);
8237
+ const { truthy, truthType } = profile;
8238
+ const truth = truthy === void 0 || truthType === void 0 ? void 0 : {
8239
+ truthy,
8240
+ truthType
8241
+ };
7552
8242
  const out = {};
7553
8243
  for (const name of Object.keys(evaluators)) {
7554
8244
  const evaluator = evaluators[name];
7555
8245
  const type = Object.hasOwn(types, name) ? types[name] : void 0;
7556
- out[name] = Object.freeze(type === void 0 ? evaluator : {
8246
+ const made = Object.freeze(type === void 0 ? evaluator : {
7557
8247
  compile: evaluator.compile,
7558
8248
  type
7559
8249
  });
8250
+ if (truth !== void 0 && TRUTH_READERS.includes(name)) truthByCode.set(made, truth);
8251
+ out[name] = made;
7560
8252
  }
7561
8253
  return Object.freeze(out);
7562
8254
  }
@@ -7566,6 +8258,7 @@ const PROFILE_KEYS = /* @__PURE__ */ Object.freeze([
7566
8258
  "lazy",
7567
8259
  "ext",
7568
8260
  "truthy",
8261
+ "truthType",
7569
8262
  "otherwise",
7570
8263
  "logic",
7571
8264
  "omit",
@@ -7750,7 +8443,7 @@ function formulaCode(profile) {
7750
8443
  if (!Array.isArray(values)) return values;
7751
8444
  const out = {};
7752
8445
  keys.forEach((key, index) => {
7753
- if (values[index] !== SKIPPED) setOwn$1(out, key, values[index]);
8446
+ if (values[index] !== SKIPPED) setOwn$2(out, key, values[index]);
7754
8447
  });
7755
8448
  return ok(out);
7756
8449
  };
@@ -7763,7 +8456,7 @@ function formulaCode(profile) {
7763
8456
  if (omit !== void 0 && omit(result.error)) continue;
7764
8457
  return result;
7765
8458
  }
7766
- setOwn$1(out, keys[index], result.value);
8459
+ setOwn$2(out, keys[index], result.value);
7767
8460
  }
7768
8461
  return ok(out);
7769
8462
  };
@@ -7780,7 +8473,7 @@ function formulaCode(profile) {
7780
8473
  const names = { ...ctx.names };
7781
8474
  for (const [name, part] of bindings) {
7782
8475
  const result = part.code(ctx, rt);
7783
- setOwn$1(names, name, result.ok ? result.value : new Held(result.error));
8476
+ setOwn$2(names, name, result.ok ? result.value : new Held(result.error));
7784
8477
  }
7785
8478
  return body.code({
7786
8479
  ...ctx,
@@ -7811,7 +8504,7 @@ function formulaCode(profile) {
7811
8504
  rt.keepsContext?.(ctx, reads);
7812
8505
  const closure = (...args) => {
7813
8506
  const scope = { ...ctx.names };
7814
- names.forEach((name, index) => setOwn$1(scope, name, args[index]));
8507
+ names.forEach((name, index) => setOwn$2(scope, name, args[index]));
7815
8508
  const result = body.code({
7816
8509
  ...ctx,
7817
8510
  names: scope
@@ -8084,7 +8777,8 @@ function formulaMachine(profile = {}, more = {}) {
8084
8777
  /**
8085
8778
  * The standard syntax of the formula kit. It gives the site and the playground a text form. The operators are
8086
8779
  * `or`, `and`, `not`, the comparisons, `+ - * / %`, a minus sign and `^`, from the loosest to the tightest. A call
8087
- * `name(args)` applies the operation `ops.name`. `if(test, then, else)` and `list(items)` make the constructs.
8780
+ * `name(args)` applies the operation `ops.name`. `if(test, then, else)` and `list(items)` make the constructs. The
8781
+ * text `total = 2 + 3` gives the document the header name `total` (D62).
8088
8782
  */
8089
8783
  const STD_SYNTAX = /* @__PURE__ */ Object.freeze({
8090
8784
  operators: [
@@ -8214,7 +8908,8 @@ const STD_SYNTAX = /* @__PURE__ */ Object.freeze({
8214
8908
  }, {
8215
8909
  name: "list",
8216
8910
  kind: "list"
8217
- }] }
8911
+ }] },
8912
+ header: { bind: "=" }
8218
8913
  });
8219
8914
  const NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
8220
8915
  const NAME_AT = /[A-Za-z_][A-Za-z0-9_]*/y;
@@ -8232,6 +8927,12 @@ const DEFAULT_ROOTS = [
8232
8927
  "event",
8233
8928
  "caps"
8234
8929
  ];
8930
+ const FORM_ARGS = [
8931
+ "list",
8932
+ "fields",
8933
+ "named",
8934
+ "literal"
8935
+ ];
8235
8936
  const compiledProfiles = /* @__PURE__ */ new WeakMap();
8236
8937
  function typeOfKind(kind) {
8237
8938
  const keys = kind.split(".");
@@ -8287,6 +8988,37 @@ function compileOps(profile, separator) {
8287
8988
  opWords
8288
8989
  };
8289
8990
  }
8991
+ /** This function examines the bind symbol of a header. A text with the symbol after a name was not valid before. */
8992
+ function compileBind(bind, separator, binary) {
8993
+ if (bind === void 0) return void 0;
8994
+ if (!SYMBOL.test(bind) || bind.includes(separator)) throw new TypeError(`The bind symbol "${bind}" is not a group of symbols.`);
8995
+ for (const symbol of binary.keys()) if (bind.startsWith(symbol)) throw new TypeError(`The bind symbol "${bind}" starts with the operator "${symbol}".`);
8996
+ return bind;
8997
+ }
8998
+ /** This function examines the field `wrap` of a call form (K159). A name that is not a field of the form throws. */
8999
+ function compileWrap(given, args) {
9000
+ const wrap = given.wrap;
9001
+ if (wrap === void 0 || wrap === false) return false;
9002
+ if (args === "literal") throw new TypeError(`The call form "${given.name}" with the arguments literal takes no wrap.`);
9003
+ if (wrap === true) return true;
9004
+ if (args === "list") throw new TypeError(`The call form "${given.name}" with the arguments list takes only the wrap true.`);
9005
+ for (const name of wrap) if (given.fields !== void 0 && !given.fields.includes(name)) throw new TypeError(`The call form "${given.name}" has no field ${name} for its wrap.`);
9006
+ return new Set(wrap);
9007
+ }
9008
+ /** This function gives the types of the data envelopes of a profile (K159), or `undefined` without them. */
9009
+ function compileEnvelopes(given) {
9010
+ if (given === void 0) return void 0;
9011
+ const out = {};
9012
+ for (const key of [
9013
+ "number",
9014
+ "text",
9015
+ "bool"
9016
+ ]) {
9017
+ const kind = given[key];
9018
+ if (kind !== void 0) out[key] = typeOfKind(kind);
9019
+ }
9020
+ return out;
9021
+ }
8290
9022
  function compileProfile(profile) {
8291
9023
  const cached = compiledProfiles.get(profile);
8292
9024
  if (cached !== void 0) return cached;
@@ -8301,13 +9033,22 @@ function compileProfile(profile) {
8301
9033
  const forms = /* @__PURE__ */ new Map();
8302
9034
  const formsByKind = /* @__PURE__ */ new Map();
8303
9035
  for (const given of calls.forms ?? []) {
8304
- if (!NAME.test(given.name)) throw new TypeError(`The call form "${given.name}" is not a plain name.`);
9036
+ const keys = given.name.split(".");
9037
+ if (!keys.every((key) => NAME.test(key))) throw new TypeError(`The call form "${given.name}" is not a plain name or a path of plain names.`);
9038
+ if (keys.length > 1 && refs.fields === false) throw new TypeError(`The call form "${given.name}" has dots, but the syntax has no field steps.`);
9039
+ if (keys.length > 1 && ops.opWords.has(keys[0])) throw new TypeError(`The call form "${given.name}" starts with the word operator "${keys[0]}".`);
8305
9040
  const { type, key } = typeOfKind(given.kind);
9041
+ const args = given.args ?? (given.fields === void 0 ? "list" : "fields");
9042
+ if (!FORM_ARGS.includes(args)) throw new TypeError(`The call form "${given.name}" has the unknown arguments ${String(args)}.`);
9043
+ 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.`);
9044
+ if (given.min !== void 0 && (args === "named" || args === "literal")) throw new TypeError(`The call form "${given.name}" with the arguments ${args} takes no min.`);
8306
9045
  const form = {
8307
9046
  name: given.name,
8308
9047
  type,
9048
+ args,
8309
9049
  fields: given.fields,
8310
- min: given.min ?? given.fields?.length ?? 0
9050
+ min: given.min ?? given.fields?.length ?? 0,
9051
+ wrap: compileWrap(given, args)
8311
9052
  };
8312
9053
  forms.set(form.name, form);
8313
9054
  addTo(formsByKind, key, form);
@@ -8319,6 +9060,7 @@ function compileProfile(profile) {
8319
9060
  quote: strings === void 0 ? void 0 : strings.quote ?? "\"",
8320
9061
  doubled: strings !== void 0 && strings.escape === "double",
8321
9062
  words,
9063
+ envelopes: compileEnvelopes(literals.envelopes),
8322
9064
  bare: refs.bare ?? "names",
8323
9065
  roots,
8324
9066
  fields: refs.fields ?? true,
@@ -8335,6 +9077,7 @@ function compileProfile(profile) {
8335
9077
  forms,
8336
9078
  formsByKind,
8337
9079
  separator,
9080
+ bind: compileBind(profile.header?.bind, separator, ops.binary),
8338
9081
  reserved: /* @__PURE__ */ new Set([
8339
9082
  ...words.keys(),
8340
9083
  ...ops.opWords,
@@ -8361,6 +9104,37 @@ function opDoc(op, value) {
8361
9104
  value
8362
9105
  };
8363
9106
  }
9107
+ /** This function gives the kind of the data envelope of a literal (K159), or `undefined` when the literal has none. */
9108
+ function envelopeOf(syn, value) {
9109
+ const kinds = syn.envelopes;
9110
+ if (kinds === void 0 || !isScalar(value)) return void 0;
9111
+ return typeof value === "string" ? kinds.text : typeof value === "number" ? kinds.number : typeof value === "boolean" ? kinds.bool : void 0;
9112
+ }
9113
+ /** This function gives a literal in a place that takes a document its data envelope (K159). Each other document stays. */
9114
+ function envelop(syn, doc) {
9115
+ const kind = isEnvelope(doc) ? void 0 : envelopeOf(syn, doc);
9116
+ return kind === void 0 ? doc : {
9117
+ type: kind.type,
9118
+ value: doc
9119
+ };
9120
+ }
9121
+ /** This function tells if an argument of a form takes a document (K159). */
9122
+ function wraps(form, key) {
9123
+ return form.wrap === true || form.wrap !== false && form.wrap.has(String(key));
9124
+ }
9125
+ /** This function tells if a value is a literal that JSON writes exactly: a text, a finite number, a truth value or `null`. */
9126
+ function isScalar(value) {
9127
+ return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) && !Object.is(value, -0);
9128
+ }
9129
+ function setOwn$1(target, key, value) {
9130
+ if (key === "__proto__") Object.defineProperty(target, key, {
9131
+ value,
9132
+ enumerable: true,
9133
+ writable: true,
9134
+ configurable: true
9135
+ });
9136
+ else target[key] = value;
9137
+ }
8364
9138
  const ESCAPES = {
8365
9139
  "\"": "\"",
8366
9140
  "'": "'",
@@ -8384,10 +9158,10 @@ var Parser = class {
8384
9158
  parse() {
8385
9159
  this.skip();
8386
9160
  if (this.pos >= this.text.length) this.stop("The text is empty.", 0, 0);
8387
- const doc = this.expr(0);
9161
+ const doc = this.bound();
8388
9162
  this.skip();
8389
9163
  if (this.pos < this.text.length) this.stop("The text continues after the expression.", this.pos, this.tokenLength());
8390
- return doc;
9164
+ return envelop(this.syn, doc);
8391
9165
  }
8392
9166
  position() {
8393
9167
  return this.pos;
@@ -8409,6 +9183,60 @@ var Parser = class {
8409
9183
  tokenLength() {
8410
9184
  return (this.at(NAME_AT) ?? this.at(DIGITS_AT) ?? "x").length;
8411
9185
  }
9186
+ /**
9187
+ * This method reads an expression that can have a header name: `name = expr` (D62). The bind symbol of the profile
9188
+ * follows the name. A longer operator that starts with the symbol wins, for example `==` over `=`.
9189
+ */
9190
+ bound() {
9191
+ const name = this.bindingName();
9192
+ if (name === void 0) return this.expr(0);
9193
+ this.skip();
9194
+ const start = this.pos;
9195
+ const doc = this.expr(0);
9196
+ if (isEnvelope(doc)) {
9197
+ if (doc.name !== void 0) this.stop(`The document already has the name ${doc.name}.`, start, this.pos - start);
9198
+ return {
9199
+ ...doc,
9200
+ name
9201
+ };
9202
+ }
9203
+ const kind = envelopeOf(this.syn, doc);
9204
+ return kind === void 0 ? {
9205
+ type: "lit",
9206
+ value: doc,
9207
+ name
9208
+ } : {
9209
+ type: kind.type,
9210
+ value: doc,
9211
+ name
9212
+ };
9213
+ }
9214
+ /** This method reads a name and the bind symbol after it. Without them, it gives `undefined` and keeps the position. */
9215
+ bindingName() {
9216
+ const bind = this.syn.bind;
9217
+ if (bind === void 0) return void 0;
9218
+ this.skip();
9219
+ const back = this.pos;
9220
+ let name;
9221
+ if (this.text[this.pos] === "`") try {
9222
+ name = this.quoted();
9223
+ } catch (error) {
9224
+ if (!(error instanceof Stop)) throw error;
9225
+ }
9226
+ else {
9227
+ name = this.at(NAME_AT);
9228
+ if (name !== void 0) this.pos += name.length;
9229
+ }
9230
+ if (name !== void 0) {
9231
+ this.skip();
9232
+ const longer = this.syn.binarySymbols.some((symbol) => symbol.length > bind.length && symbol.startsWith(bind) && this.text.startsWith(symbol, this.pos));
9233
+ if (this.text.startsWith(bind, this.pos) && !longer) {
9234
+ this.pos += bind.length;
9235
+ return name;
9236
+ }
9237
+ }
9238
+ this.pos = back;
9239
+ }
8412
9240
  /** This method reads an expression by precedence climbing. It stops at an operator below `min`. */
8413
9241
  expr(min) {
8414
9242
  const start = this.pos;
@@ -8541,7 +9369,7 @@ var Parser = class {
8541
9369
  group() {
8542
9370
  const open = this.pos;
8543
9371
  this.pos += 1;
8544
- const inner = this.expr(0);
9372
+ const inner = this.bound();
8545
9373
  this.skip();
8546
9374
  if (this.text[this.pos] !== ")") {
8547
9375
  if (this.pos >= this.text.length) this.stop("A closing parenthesis is missing.", open, 1);
@@ -8591,6 +9419,11 @@ var Parser = class {
8591
9419
  }
8592
9420
  this.pos += 1;
8593
9421
  this.skip();
9422
+ if (this.text[this.pos] === "(") {
9423
+ path.push(this.group());
9424
+ allPlain = false;
9425
+ continue;
9426
+ }
8594
9427
  if (this.text[this.pos] === "`") {
8595
9428
  path.push(this.quoted());
8596
9429
  allPlain = false;
@@ -8606,7 +9439,7 @@ var Parser = class {
8606
9439
  const back = this.pos;
8607
9440
  this.skip();
8608
9441
  if (this.text[this.pos] === "(") {
8609
- if (!allPlain) this.stop("The name of a call is a plain name.", start, back - start);
9442
+ if (!allPlain) this.stop("Each key of the name of a call is a plain name.", start, back - start);
8610
9443
  return this.call(path.join("."), start, back - start);
8611
9444
  }
8612
9445
  this.pos = back;
@@ -8616,14 +9449,18 @@ var Parser = class {
8616
9449
  value: plain && this.syn.roots.has(first) ? path : [this.syn.bare, ...path]
8617
9450
  };
8618
9451
  }
8619
- call(name, start, nameLength) {
9452
+ /** This method reads the arguments of a call in parentheses. `item` reads one argument. */
9453
+ argumentsOf(item) {
8620
9454
  const open = this.pos;
8621
9455
  const args = [];
8622
9456
  this.pos += 1;
8623
9457
  this.skip();
8624
- if (this.text[this.pos] === ")") this.pos += 1;
8625
- else for (;;) {
8626
- args.push(this.expr(0));
9458
+ if (this.text[this.pos] === ")") {
9459
+ this.pos += 1;
9460
+ return args;
9461
+ }
9462
+ for (;;) {
9463
+ args.push(item());
8627
9464
  this.skip();
8628
9465
  if (this.text.startsWith(this.syn.separator, this.pos)) {
8629
9466
  this.pos += this.syn.separator.length;
@@ -8631,22 +9468,55 @@ var Parser = class {
8631
9468
  }
8632
9469
  if (this.text[this.pos] === ")") {
8633
9470
  this.pos += 1;
8634
- break;
9471
+ return args;
8635
9472
  }
8636
9473
  if (this.pos >= this.text.length) this.stop("A closing parenthesis is missing.", open, 1);
8637
9474
  this.stop(`A "${this.syn.separator}" or a closing parenthesis is missing.`, this.pos, this.tokenLength());
8638
9475
  }
9476
+ }
9477
+ /** This method reads the arguments `key: expr` of a form `named` into a record (SYNTAX.RECORD). */
9478
+ namedArguments(form) {
9479
+ const value = {};
9480
+ this.argumentsOf(() => {
9481
+ this.skip();
9482
+ const at = this.pos;
9483
+ let key;
9484
+ if (this.text[at] === "`") key = this.quoted();
9485
+ else {
9486
+ key = this.at(NAME_AT);
9487
+ if (key !== void 0) this.pos += key.length;
9488
+ }
9489
+ const end = this.pos;
9490
+ this.skip();
9491
+ if (key === void 0 || this.text[this.pos] !== ":") this.stop(`Each argument of the form ${form.name} is a key, a ":" and a document.`, at, Math.max(end - at, this.tokenLength()));
9492
+ if (form.fields !== void 0 && !form.fields.includes(key)) this.stop(`The form ${form.name} has no field ${key}.`, at, end - at);
9493
+ if (Object.hasOwn(value, key)) this.stop(`The form ${form.name} has the field ${key} two times.`, at, end - at);
9494
+ this.pos += 1;
9495
+ const arg = this.bound();
9496
+ setOwn$1(value, key, wraps(form, key) ? envelop(this.syn, arg) : arg);
9497
+ });
9498
+ return opDoc(form, value);
9499
+ }
9500
+ call(name, start, nameLength) {
8639
9501
  const form = this.syn.forms.get(name);
9502
+ if (form?.args === "named") return this.namedArguments(form);
9503
+ const args = this.argumentsOf(() => this.bound());
9504
+ if (form?.args === "literal") {
9505
+ const [only] = args;
9506
+ if (args.length !== 1 || !isScalar(only)) this.stop(`The form ${name} takes one literal that JSON writes.`, start, this.pos - start);
9507
+ return opDoc(form, only);
9508
+ }
8640
9509
  if (form !== void 0) {
8641
9510
  const most = form.fields?.length ?? Number.POSITIVE_INFINITY;
8642
9511
  if (args.length < form.min || args.length > most) {
8643
9512
  const range = most === form.min ? String(most) : most === Number.POSITIVE_INFINITY ? `${String(form.min)} or more` : `${String(form.min)} to ${String(most)}`;
8644
9513
  this.stop(`The form ${name} takes ${range} arguments.`, start, this.pos - start);
8645
9514
  }
8646
- if (form.fields === void 0) return opDoc(form, args);
9515
+ if (form.fields === void 0) return opDoc(form, form.wrap === true ? args.map((arg) => envelop(this.syn, arg)) : args);
8647
9516
  const value = {};
8648
9517
  args.forEach((arg, index) => {
8649
- value[form.fields?.[index]] = arg;
9518
+ const key = form.fields?.[index];
9519
+ value[key] = wraps(form, key) ? envelop(this.syn, arg) : arg;
8650
9520
  });
8651
9521
  return opDoc(form, value);
8652
9522
  }
@@ -8725,8 +9595,10 @@ function literalShape(syn, value) {
8725
9595
  function plainSegment(syn, name) {
8726
9596
  return NAME.test(name) && !syn.reserved.has(name) && !syn.patterns.some((p) => p.whole.test(name));
8727
9597
  }
8728
- function laterSegment(step) {
9598
+ /** This function gives the text of a later step of a path, or the step and its index when the step is a document. */
9599
+ function laterSegment(step, index) {
8729
9600
  if (typeof step === "string") return NAME.test(step) ? step : quoteName(step);
9601
+ if (isEnvelope(step)) return [index, step];
8730
9602
  return typeof step === "number" && Number.isSafeInteger(step) && step >= 0 ? String(step) : void 0;
8731
9603
  }
8732
9604
  function refShape(syn, value) {
@@ -8740,18 +9612,23 @@ function refShape(syn, value) {
8740
9612
  }
8741
9613
  const [root, ...rest] = value;
8742
9614
  if ((rest.length > 1 || root !== syn.bare && rest.length > 0) && !syn.fields) return none("This syntax has no field steps.");
8743
- const later = rest.slice(1).map(laterSegment);
8744
9615
  let first;
8745
- let tail = later;
8746
- if (root === syn.bare && typeof rest[0] === "string") first = plainSegment(syn, rest[0]) ? rest[0] : quoteName(rest[0]);
8747
- else if (typeof root === "string" && syn.roots.has(root) && !syn.patterns.some((p) => p.whole.test(root))) {
9616
+ let tail = [];
9617
+ if (root === syn.bare && typeof rest[0] === "string") {
9618
+ first = plainSegment(syn, rest[0]) ? rest[0] : quoteName(rest[0]);
9619
+ tail = rest.slice(1).map((step, index) => laterSegment(step, index + 2));
9620
+ } else if (typeof root === "string" && syn.roots.has(root) && !syn.patterns.some((p) => p.whole.test(root))) {
8748
9621
  first = root;
8749
- tail = rest.map(laterSegment);
9622
+ tail = rest.map((step, index) => laterSegment(step, index + 1));
8750
9623
  }
8751
9624
  if (first === void 0 || tail.includes(void 0)) return none("This syntax has no text for the path of the reference.");
8752
- return {
9625
+ const segments = [first, ...tail];
9626
+ return segments.every((segment) => typeof segment === "string") ? {
8753
9627
  tag: "text",
8754
- text: [first, ...tail].join(".")
9628
+ text: segments.join(".")
9629
+ } : {
9630
+ tag: "path",
9631
+ segments
8755
9632
  };
8756
9633
  }
8757
9634
  function callName(syn, keys) {
@@ -8760,13 +9637,58 @@ function callName(syn, keys) {
8760
9637
  if (syn.forms.has(name) || syn.opWords.has(keys[0])) return void 0;
8761
9638
  return syn.ops === true || syn.ops.has(name) ? name : void 0;
8762
9639
  }
8763
- function formShape(form, value) {
9640
+ const WRAPPED = "This syntax reads a literal in this place as its data envelope, thus a bare literal has no text here.";
9641
+ /**
9642
+ * This function gives the text of a document in a place that takes a document (K159). A data envelope of a literal
9643
+ * is the bare literal. A literal without its envelope has no text, because `parse` gives it the envelope. The
9644
+ * function gives `undefined` for each other document.
9645
+ */
9646
+ function wrappedShape(syn, doc) {
9647
+ if (syn.envelopes === void 0) return void 0;
9648
+ if (!isEnvelope(doc)) return envelopeOf(syn, doc) === void 0 ? void 0 : none(WRAPPED);
9649
+ if (doc.name !== void 0 || doc.own !== void 0 || !Object.hasOwn(doc, "value")) return void 0;
9650
+ const path = typePath(doc.type);
9651
+ if (path === void 0) return void 0;
9652
+ const key = JSON.stringify(path);
9653
+ if (key === JSON.stringify(["lit"])) return envelopeOf(syn, doc.value) === void 0 ? void 0 : none(WRAPPED);
9654
+ if (envelopeOf(syn, doc.value)?.key !== key) return void 0;
9655
+ const literal = literalShape(syn, doc.value);
9656
+ return literal.tag === "text" ? literal : void 0;
9657
+ }
9658
+ function formShape(syn, form, value) {
9659
+ if (form.args === "literal") {
9660
+ if (!isScalar(value)) return void 0;
9661
+ const literal = literalShape(syn, value);
9662
+ return literal.tag === "text" ? {
9663
+ tag: "text",
9664
+ text: `${form.name}(${literal.text})`
9665
+ } : void 0;
9666
+ }
9667
+ if (form.args === "named") {
9668
+ if (!isRecord(value)) return void 0;
9669
+ const keys = Object.keys(value);
9670
+ if (form.fields !== void 0 && !keys.every((key) => form.fields?.includes(key) === true)) return void 0;
9671
+ return {
9672
+ tag: "call",
9673
+ name: form.name,
9674
+ args: keys.map((key) => [
9675
+ key,
9676
+ value[key],
9677
+ wraps(form, key)
9678
+ ]),
9679
+ named: true
9680
+ };
9681
+ }
8764
9682
  if (form.fields === void 0) {
8765
9683
  if (!Array.isArray(value) || value.length < form.min) return void 0;
8766
9684
  return {
8767
9685
  tag: "call",
8768
9686
  name: form.name,
8769
- args: value.map((item, index) => [index, item])
9687
+ args: value.map((item, index) => [
9688
+ index,
9689
+ item,
9690
+ wraps(form, index)
9691
+ ])
8770
9692
  };
8771
9693
  }
8772
9694
  if (!isRecord(value)) return void 0;
@@ -8776,7 +9698,11 @@ function formShape(form, value) {
8776
9698
  return {
8777
9699
  tag: "call",
8778
9700
  name: form.name,
8779
- args: present.map((key) => [key, value[key]])
9701
+ args: present.map((key) => [
9702
+ key,
9703
+ value[key],
9704
+ wraps(form, key)
9705
+ ])
8780
9706
  };
8781
9707
  }
8782
9708
  function opShape(syn, key, terms) {
@@ -8789,7 +9715,16 @@ function opShape(syn, key, terms) {
8789
9715
  /** This function gives the shape of a document: a literal or a reference, an operator, a call, or no text. */
8790
9716
  function shapeOf(syn, doc) {
8791
9717
  if (!isEnvelope(doc)) return Array.isArray(doc) || isRecord(doc) ? none("This syntax has no text for a list or a record literal.") : literalShape(syn, doc);
8792
- if (doc.name !== void 0 || doc.own !== void 0) return none("This syntax has no text for the header of a document.");
9718
+ if (doc.own !== void 0) return none("This syntax has no text for the own entries of a document.");
9719
+ if (doc.name !== void 0) {
9720
+ if (syn.bind === void 0) return none("This syntax has no text for the name of a document.");
9721
+ const { name, ...rest } = doc;
9722
+ return {
9723
+ tag: "bind",
9724
+ name,
9725
+ doc: rest
9726
+ };
9727
+ }
8793
9728
  const path = typePath(doc.type);
8794
9729
  if (path === void 0) return none("This syntax has no text for a computed type.");
8795
9730
  const value = doc.value;
@@ -8810,7 +9745,7 @@ function shapeOf(syn, doc) {
8810
9745
  const op = Array.isArray(value) ? opShape(syn, key, value) : void 0;
8811
9746
  if (op !== void 0) return op;
8812
9747
  for (const form of syn.formsByKind.get(key) ?? []) {
8813
- const shape = formShape(form, value);
9748
+ const shape = formShape(syn, form, value);
8814
9749
  if (shape !== void 0) return shape;
8815
9750
  }
8816
9751
  const called = path[0] === "ops" && Array.isArray(value) ? callName(syn, path.slice(1)) : void 0;
@@ -8823,7 +9758,7 @@ function shapeOf(syn, doc) {
8823
9758
  }
8824
9759
  function levelOf(syn, doc) {
8825
9760
  const shape = shapeOf(syn, doc);
8826
- return shape.tag === "op" ? shape.op.prec : Number.POSITIVE_INFINITY;
9761
+ return shape.tag === "op" ? shape.op.prec : shape.tag === "bind" ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
8827
9762
  }
8828
9763
  /** This function tells if a term needs parentheses in its position, so that `parse` reads the same tree. */
8829
9764
  function needsGroup(op, index, level) {
@@ -8853,18 +9788,42 @@ function printNode(syn, doc, sub) {
8853
9788
  if (shape.tag === "text") return ok(shape.text);
8854
9789
  if (shape.tag === "none") return fail("#VALUE!", shape.reason);
8855
9790
  if (shape.tag === "op") return opText(syn, shape.op, shape.terms, sub);
9791
+ if (shape.tag === "bind") {
9792
+ const head = wrappedShape(syn, shape.doc);
9793
+ const inner = head === void 0 ? printNode(syn, shape.doc, sub) : head.tag === "text" ? ok(head.text) : fail("#VALUE!", WRAPPED);
9794
+ return inner.ok ? ok(`${NAME.test(shape.name) ? shape.name : quoteName(shape.name)} ${syn.bind} ${inner.value}`) : inner;
9795
+ }
9796
+ if (shape.tag === "path") {
9797
+ const texts = [];
9798
+ for (const segment of shape.segments) {
9799
+ if (typeof segment === "string") {
9800
+ texts.push(segment);
9801
+ continue;
9802
+ }
9803
+ const result = sub(segment[1], [segment[0]]);
9804
+ if (!result.ok) return result;
9805
+ texts.push(`(${result.value})`);
9806
+ }
9807
+ return ok(texts.join("."));
9808
+ }
8856
9809
  const texts = [];
8857
- for (const [key, arg] of shape.args) {
8858
- const result = sub(arg, [key]);
9810
+ for (const [key, arg, wrapped] of shape.args) {
9811
+ const result = sub(arg, [key], wrapped);
8859
9812
  if (!result.ok) return result;
8860
- texts.push(result.value);
9813
+ texts.push(shape.named === true ? `${NAME.test(String(key)) ? String(key) : quoteName(String(key))}: ${result.value}` : result.value);
8861
9814
  }
8862
9815
  return ok(`${shape.name}(${texts.join(`${syn.separator} `)})`);
8863
9816
  }
8864
9817
  function printTree(syn, doc, place) {
8865
- const result = printNode(syn, doc, (child, path) => printTree(syn, child, [...place, ...path]));
9818
+ const result = printNode(syn, doc, (child, path, wrapped) => (wrapped === true ? printPlace : printTree)(syn, child, [...place, ...path]));
8866
9819
  return result.ok || result.error.place !== void 0 ? result : fail(result.error.code, result.error.reason, { place });
8867
9820
  }
9821
+ /** This function writes a document in a place that takes a document, for example the whole text (K159). */
9822
+ function printPlace(syn, doc, place) {
9823
+ const shape = wrappedShape(syn, doc);
9824
+ if (shape === void 0) return printTree(syn, doc, place);
9825
+ return shape.tag === "text" ? ok(shape.text) : fail("#VALUE!", WRAPPED, { place });
9826
+ }
8868
9827
  /**
8869
9828
  * This function writes a document as text with the rules of a profile (SYNTAX.PRINT). It writes the fewest
8870
9829
  * parentheses that keep the tree. `parse` reads the text back to the same document (SYNTAX.ROUNDTRIP).
@@ -8877,7 +9836,7 @@ function printTree(syn, doc, place) {
8877
9836
  function print(profile, doc) {
8878
9837
  const syn = compileProfile(profile);
8879
9838
  try {
8880
- return printTree(syn, doc, []);
9839
+ return printPlace(syn, doc, []);
8881
9840
  } catch (error) {
8882
9841
  if (isStackOverflow(error)) return fail("#DEPTH!", "The document is too deep for the stack of the host.", { cause: error });
8883
9842
  throw error;
@@ -8895,7 +9854,9 @@ function syntaxFormat(profile) {
8895
9854
  const syn = compileProfile(profile);
8896
9855
  const code = ({ doc, parts, place }) => {
8897
9856
  const byPath = new Map(parts.map((part) => [JSON.stringify(part.path), part]));
8898
- return printNode(syn, doc, (child, path) => {
9857
+ return printNode(syn, doc, (child, path, wrapped) => {
9858
+ const own = wrapped === true ? wrappedShape(syn, child) : void 0;
9859
+ if (own !== void 0) return own.tag === "text" ? ok(own.text) : fail("#VALUE!", WRAPPED, { place: [...place, ...path] });
8899
9860
  const part = byPath.get(JSON.stringify(path));
8900
9861
  if (part === void 0) return printTree(syn, child, [...place, ...path]);
8901
9862
  const result = part.evaluate();
@@ -9016,6 +9977,54 @@ function resolveFully(machine, ctx, path, options) {
9016
9977
  hops: []
9017
9978
  };
9018
9979
  }
9980
+ /** The text that names a resolution in the error of an exception of the host (READS.RECORD). */
9981
+ const READ_FAILED = "the resolution of a path";
9982
+ /**
9983
+ * This function resolves a path for a document, and records the read when the evaluation has a list (REF.READS,
9984
+ * READS.RECORD). An exception of the host gives the error value of the read, and the exception goes on.
9985
+ */
9986
+ function readAt(env, ctx, path, options) {
9987
+ const reading = env.reading;
9988
+ if (reading === void 0) return resolveFully(env.machine, ctx, path, options);
9989
+ const free = freeIn(reading.root, ctx, path);
9990
+ let found;
9991
+ try {
9992
+ found = resolveFully(env.machine, ctx, path, options);
9993
+ } catch (error) {
9994
+ reading.list.push({
9995
+ path,
9996
+ reached: thrown(error, READ_FAILED),
9997
+ free
9998
+ });
9999
+ throw error;
10000
+ }
10001
+ reading.list.push(options?.hops === true ? {
10002
+ path,
10003
+ reached: reachedOf(found),
10004
+ free,
10005
+ hops: found.hops
10006
+ } : {
10007
+ path,
10008
+ reached: reachedOf(found),
10009
+ free
10010
+ });
10011
+ return found;
10012
+ }
10013
+ /**
10014
+ * This function tells if a read reads the context at the root of the evaluation (READS.FREE). The reference reads
10015
+ * the rule from SPEC. A name that a kind binds, a `self` that a kind sets and a path without a root are not free. A
10016
+ * name that a kind does not bind keeps its value from the root.
10017
+ */
10018
+ function freeIn(root, ctx, path) {
10019
+ const head = path[0];
10020
+ if (head === "self") return Object.is(ctx.self, root.self);
10021
+ if (head !== "names") return typeof head === "string" && ROOTS.includes(head);
10022
+ const name = path[1];
10023
+ if (ctx.names === root.names || !isKey(name)) return true;
10024
+ const key = String(name);
10025
+ const bound = Object.hasOwn(ctx.names, key);
10026
+ return bound === Object.hasOwn(root.names, key) && (!bound || Object.is(ctx.names[key], root.names[key]));
10027
+ }
9019
10028
  /**
9020
10029
  * This function causes an effect when the capabilities permit it (RUN.CAP, CAP.HOOK). It records the effect with its
9021
10030
  * address (RUN.ADDRESS) and its outcome (RUN.OUTCOME). The mock answers the effect at once (RUN.MOCK). Without a
@@ -9170,7 +10179,7 @@ function evalInput(env, seen, at) {
9170
10179
  place: at.place,
9171
10180
  machine: env.machine,
9172
10181
  ...at.address ? { address: true } : {},
9173
- resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
10182
+ resolve: (path, options) => readAt(env, at.ctx, path, options),
9174
10183
  effect: (kind, payload) => causeFromEvaluator(env, at.ctx, kind, payload, at.place),
9175
10184
  fill
9176
10185
  };
@@ -9197,7 +10206,7 @@ function runInput(env, seen, at) {
9197
10206
  context: at.ctx,
9198
10207
  place: at.place,
9199
10208
  machine: env.machine,
9200
- resolve: (path, options) => resolveFully(env.machine, at.ctx, path, options),
10209
+ resolve: (path, options) => readAt(env, at.ctx, path, options),
9201
10210
  effect: (kind, payload) => causeAndWait(env, at.ctx, kind, payload, at.place),
9202
10211
  all: (list, options) => together(env, list, options),
9203
10212
  fill
@@ -9226,6 +10235,7 @@ function* together(env, list, options = {}) {
9226
10235
  outer.alls += 1;
9227
10236
  let failed = false;
9228
10237
  let started = 0;
10238
+ let before = 0;
9229
10239
  const end = (index, result) => {
9230
10240
  results[index] = result;
9231
10241
  if (failFast && !result.ok) failed = true;
@@ -9289,10 +10299,11 @@ function* together(env, list, options = {}) {
9289
10299
  };
9290
10300
  startMore();
9291
10301
  while (waiting.length > 0 && !failed) {
9292
- const chosen = env.journal?.next?.(address, waiting.map((waiter) => waiter.index));
10302
+ const chosen = env.journal?.next?.(address, waiting.map((waiter) => waiter.index), before);
9293
10303
  const pick = chosen === void 0 ? void 0 : waiting.find((waiter) => waiter.index === chosen);
9294
10304
  const resumed = yield pick === void 0 ? Promise.race(waiting.map((waiter) => waiter.next)) : pick.next;
9295
10305
  env.journal?.settled?.(address, resumed.waiter.index);
10306
+ before += 1;
9296
10307
  waiting.splice(waiting.indexOf(resumed.waiter), 1);
9297
10308
  goOn(resumed.waiter.index, resumed.waiter.steps, resumed);
9298
10309
  startMore();
@@ -9319,9 +10330,17 @@ function* together(env, list, options = {}) {
9319
10330
  * @returns The result.
9320
10331
  */
9321
10332
  function reference(machine, doc, context = makeContext(), options = {}) {
9322
- const env = envOf(machine, options, false);
10333
+ return evaluateRoot(machine, doc, context, options, void 0);
10334
+ }
10335
+ /**
10336
+ * This function evaluates a document from its root. An equation of a tree gives the record of its tree. Thus the
10337
+ * reads of the equation go in the list of the outer evaluation (REF.READS).
10338
+ */
10339
+ function evaluateRoot(machine, doc, context, options, outer) {
10340
+ const at = rootAt(machine, doc, context, options);
10341
+ const env = envOf(machine, options, false, at.ctx, outer);
9323
10342
  try {
9324
- return within(env, () => evaluateAt(env, rootAt(machine, doc, context, options)));
10343
+ return within(env, () => evaluateAt(env, at));
9325
10344
  } catch (error) {
9326
10345
  return placed(thrown(error, "the reference"), []);
9327
10346
  }
@@ -9342,11 +10361,15 @@ function reference(machine, doc, context = makeContext(), options = {}) {
9342
10361
  * @returns The result, when the run ends.
9343
10362
  */
9344
10363
  function referenceRun(machine, doc, context = makeContext(), options = {}) {
9345
- const env = envOf(machine, options, true);
9346
- return driveRun(env, stepsAt(env, rootAt(machine, doc, context, options)), options.signal).catch((error) => placed(thrown(error, "the reference"), []));
10364
+ const at = rootAt(machine, doc, context, options);
10365
+ const env = envOf(machine, options, true, at.ctx, void 0);
10366
+ return driveRun(env, stepsAt(env, at), options.signal).catch((error) => placed(thrown(error, "the reference"), []));
9347
10367
  }
9348
- /** This function makes the state of the reference for one evaluation or one run. */
9349
- function envOf(machine, options, running) {
10368
+ /**
10369
+ * This function makes the state of the reference for one evaluation or one run. The record of the reads comes from
10370
+ * the evaluation around it, or from the list of the options.
10371
+ */
10372
+ function envOf(machine, options, running, root, outer) {
9350
10373
  const perform = options.perform;
9351
10374
  return {
9352
10375
  machine,
@@ -9361,7 +10384,11 @@ function envOf(machine, options, running) {
9361
10384
  prefix: "",
9362
10385
  counts: /* @__PURE__ */ new Map(),
9363
10386
  alls: 0
9364
- }
10387
+ },
10388
+ reading: outer ?? (options.reads === void 0 ? void 0 : {
10389
+ list: options.reads,
10390
+ root
10391
+ })
9365
10392
  };
9366
10393
  }
9367
10394
  /** This function gives the root position of a document. A context without a world gets the world of the machine. */
@@ -9436,7 +10463,8 @@ function refNodeOf(thing) {
9436
10463
  }
9437
10464
  /**
9438
10465
  * TREE.LADDER: an equation of the kind of a node evaluates in the reference. It gets the node as `self`, the names of
9439
- * its rung and no capabilities. A bare equation gets the type `of` of the parts of the kind.
10466
+ * its rung and no capabilities. A bare equation gets the type `of` of the parts of the kind. The reads of the
10467
+ * equation go in the record of the evaluation that made the node (REF.READS).
9440
10468
  */
9441
10469
  function equationOf(node, term, names) {
9442
10470
  const env = node.env;
@@ -9447,10 +10475,10 @@ function equationOf(node, term, names) {
9447
10475
  caps: [],
9448
10476
  self: node.thing
9449
10477
  };
9450
- return reference(env.machine, term, ctx, {
10478
+ return evaluateRoot(env.machine, term, ctx, {
9451
10479
  definitions: env.definitions,
9452
10480
  ...node.of === void 0 ? {} : { declaredType: node.of }
9453
- });
10481
+ }, env.reading);
9454
10482
  }
9455
10483
  function termIn(table, name) {
9456
10484
  return table === void 0 || !Object.hasOwn(table, name) ? void 0 : table[name];
@@ -9696,10 +10724,13 @@ function formulaDefinitions(profile = {}) {
9696
10724
  }
9697
10725
  const head = path[0] === "names" && typeof path[1] === "string" ? path[1] : void 0;
9698
10726
  const bound = head === void 0 ? void 0 : own$1(context.names, head);
9699
- if (bound instanceof Held) return {
9700
- ok: false,
9701
- error: bound.error
9702
- };
10727
+ if (bound instanceof Held) {
10728
+ walk(["names", head]);
10729
+ return {
10730
+ ok: false,
10731
+ error: bound.error
10732
+ };
10733
+ }
9703
10734
  const found = walk(steps);
9704
10735
  if (!found.ok) return fail(found.code, found.reason);
9705
10736
  if (address === true) return ok(found.thing);
@@ -9862,18 +10893,21 @@ function valuesOfStrict(parts) {
9862
10893
  * Its log keeps each effect with its address, its kind, its payload and the outcome that the kernel gives it. The log
9863
10894
  * also keeps the order in which the waits of each `all` settle.
9864
10895
  *
10896
+ * The recorder gives each call of its journal to the journal of the inner function, for example of a replayer. Thus a
10897
+ * recording of a replay settles the waits in the order of the replayer, and it gives the same log (RUN.REPLAY-ORDER).
10898
+ *
9865
10899
  * @param perform - The function of the host. Without it, each effect gives its payload, as in a run without a host.
9866
10900
  * @returns The function `perform` for the run, and the log.
9867
10901
  */
9868
10902
  function recorder(perform) {
9869
10903
  const seen = [];
9870
10904
  const settles = [];
9871
- const journal = { settled: (all, item) => {
10905
+ const journal = relay(perform, (all, item) => {
9872
10906
  settles.push({
9873
10907
  all,
9874
10908
  item
9875
10909
  });
9876
- } };
10910
+ });
9877
10911
  const host = (effect) => {
9878
10912
  const entry = {
9879
10913
  effect,
@@ -9903,14 +10937,17 @@ function recorder(perform) {
9903
10937
  * recorded error comes again with its code, its reason, its place and its cause. The waits of each `all` settle in the
9904
10938
  * recorded order. An effect that the log does not have at its address gives `#REPLAY!` (RUN.REPLAY-MISMATCH).
9905
10939
  *
9906
- * A replayer keeps its place in the order of the waits, thus each run needs a new replayer.
10940
+ * One replayer serves more than one run, also two runs at the same time (RUN.REPLAY-RUNS). The kernel tells the journal
10941
+ * the number of the waits of each `all` that settled before, thus the replayer keeps no state of a run. When the
10942
+ * recorded item of a wait does not wait in the run, that wait follows the order of the host.
9907
10943
  *
9908
- * @param log - The log of a recorder.
9909
- * @param options - `wait: false` for an evaluation.
10944
+ * @param log - The log of a recorder, or of `decodeLog`.
10945
+ * @param options - `wait: false` for an evaluation, and the rule of the host for payloads.
9910
10946
  * @returns The function `perform` for the replay.
9911
10947
  */
9912
10948
  function replayer(log, options = {}) {
9913
10949
  const wait = options.wait !== false;
10950
+ const equal = options.equal;
9914
10951
  const entries = /* @__PURE__ */ new Map();
9915
10952
  for (const entry of log.effects) entries.set(entry.address, entry);
9916
10953
  const order = /* @__PURE__ */ new Map();
@@ -9919,16 +10956,19 @@ function replayer(log, options = {}) {
9919
10956
  if (items === void 0) order.set(settle.all, [settle.item]);
9920
10957
  else items.push(settle.item);
9921
10958
  }
9922
- const journal = { next: (all, waiting) => {
10959
+ let places;
10960
+ const journal = { next: (all, waiting, before) => {
9923
10961
  const items = order.get(all);
9924
- const item = items?.[0];
9925
- if (items === void 0 || item === void 0 || !waiting.includes(item)) return void 0;
9926
- items.shift();
10962
+ if (items === void 0) return void 0;
10963
+ const at = before ?? (places ??= /* @__PURE__ */ new Map()).get(all) ?? 0;
10964
+ const item = items[at];
10965
+ if (item === void 0 || !waiting.includes(item)) return void 0;
10966
+ if (before === void 0) places?.set(all, at + 1);
9927
10967
  return item;
9928
10968
  } };
9929
10969
  const perform = (effect) => {
9930
10970
  const entry = effect.address === void 0 ? void 0 : entries.get(effect.address);
9931
- const wrong = mismatch(effect, entry);
10971
+ const wrong = mismatch(effect, entry, equal);
9932
10972
  if (wrong !== void 0 || entry === void 0) throw wrong;
9933
10973
  const outcome = entry.outcome;
9934
10974
  const failure = outcome === void 0 ? replayError(effect, `The log has no outcome for the effect ${effect.kind} at ${effect.address ?? ""}: the recorded run stopped before the answer.`) : outcome.ok ? void 0 : new Failure(outcome.error);
@@ -9940,16 +10980,882 @@ function replayer(log, options = {}) {
9940
10980
  return Object.assign(perform, { [JOURNAL]: journal });
9941
10981
  }
9942
10982
  /** This function gives the error of an effect that the log does not have at its address, or `undefined`. */
9943
- function mismatch(effect, entry) {
10983
+ function mismatch(effect, entry, equal) {
9944
10984
  const at = effect.address ?? "";
9945
10985
  if (entry === void 0) return replayError(effect, `The log has no effect at the address ${at}, and the run asks for the effect ${effect.kind}.`);
9946
10986
  if (entry.kind !== effect.kind) return replayError(effect, `The log has the effect ${entry.kind} at the address ${at}, and the run asks for the effect ${effect.kind}.`);
9947
- if (!docEquals(entry.payload, effect.payload)) return replayError(effect, `The effect ${effect.kind} at the address ${at} has another payload than the log.`);
10987
+ if (!equalWith(entry.payload, effect.payload, equal)) return replayError(effect, `The effect ${effect.kind} at the address ${at} has another payload than the log.`);
9948
10988
  }
9949
10989
  /** This function gives the exception that carries `#REPLAY!` to the kernel, with the place of the effect. */
9950
10990
  function replayError(effect, reason) {
9951
10991
  return new Failure(fail("#REPLAY!", reason, { place: effect.place }).error);
9952
10992
  }
10993
+ /**
10994
+ * This function gives a journal that tells a function of its own each wait that settles. It gives each call to the
10995
+ * journal of the inner function `perform`, when that function has one.
10996
+ *
10997
+ * @param perform - The inner function.
10998
+ * @param settled - The function of its own.
10999
+ * @returns The journal.
11000
+ */
11001
+ function relay(perform, settled) {
11002
+ const inner = perform === void 0 ? void 0 : perform[JOURNAL];
11003
+ const tell = (all, item) => {
11004
+ settled(all, item);
11005
+ inner?.settled?.(all, item);
11006
+ };
11007
+ if (inner?.next === void 0) return { settled: tell };
11008
+ return {
11009
+ settled: tell,
11010
+ next: (all, waiting, before) => inner.next?.(all, waiting, before)
11011
+ };
11012
+ }
11013
+ /** This function tells if a key is a field of an error value that the JSON form keeps. */
11014
+ function errorField(key) {
11015
+ return key === "code" || key === "reason" || key === "place" || key === "cause";
11016
+ }
11017
+ /** This function tells if a key is a field of an exception that the JSON form keeps in a field of its own, or drops. */
11018
+ function ownField(key) {
11019
+ return key === "name" || key === "message" || key === "stack" || key === "cause";
11020
+ }
11021
+ /** This function tells if a key is a field of the JSON form of an exception. */
11022
+ function exceptionField(key) {
11023
+ return key === "name" || key === "message" || key === "fields" || key === "parts" || key === "dropped" || key === "hidden" || key === "cause" || key === "exception" || key === "loop" || key === "causeParts";
11024
+ }
11025
+ /**
11026
+ * The own fields that are not enumerable and that the JSON form keeps in `hidden` (D77). The standard classes define
11027
+ * them: `errors` of `AggregateError`, `error` and `suppressed` of `SuppressedError`.
11028
+ */
11029
+ const HIDDEN = /* @__PURE__ */ Object.freeze([
11030
+ "errors",
11031
+ "error",
11032
+ "suppressed"
11033
+ ]);
11034
+ /** The result of `readField` for a field that the walk of `causeJson` cannot read. */
11035
+ const MISSING = /* @__PURE__ */ Symbol("missing");
11036
+ /**
11037
+ * This function tells if a value holds a hole of a list at some depth. `encodeValue` writes a hole as `undefined`. Thus
11038
+ * the walk of `causeJson` keeps such a value in parts, and the hole keeps its mark (D82).
11039
+ */
11040
+ function holdsHole(value) {
11041
+ const seen = /* @__PURE__ */ new Set();
11042
+ const stack = [value];
11043
+ while (stack.length > 0) {
11044
+ const at = stack.pop();
11045
+ if (typeof at !== "object" || at === null || seen.has(at) || !(Array.isArray(at) || isRecord(at))) continue;
11046
+ seen.add(at);
11047
+ if (Array.isArray(at)) for (let item = 0; item < at.length; item += 1) {
11048
+ if (!Object.hasOwn(at, item)) return true;
11049
+ stack.push(at[item]);
11050
+ }
11051
+ else for (const key of Object.keys(at)) stack.push(at[key]);
11052
+ }
11053
+ return false;
11054
+ }
11055
+ /**
11056
+ * This function tells if a list or a plain record holds an exception at some depth (D87). It reads the items as the
11057
+ * walk of `causeJson` does, thus a cause container with an exception gets a form.
11058
+ */
11059
+ function holdsException(value) {
11060
+ const seen = /* @__PURE__ */ new Set();
11061
+ const stack = [value];
11062
+ while (stack.length > 0) {
11063
+ const at = stack.pop();
11064
+ if (at instanceof Error) return true;
11065
+ if (typeof at !== "object" || at === null || seen.has(at) || !(Array.isArray(at) || isRecord(at))) continue;
11066
+ seen.add(at);
11067
+ if (Array.isArray(at)) {
11068
+ for (let item = 0; item < at.length; item += 1) if (Object.hasOwn(at, item)) stack.push(readField(at, item));
11069
+ } else for (const key of Object.keys(at)) stack.push(readField(at, key));
11070
+ }
11071
+ return false;
11072
+ }
11073
+ /** This function gives the field of a cause for its form after the walk (D76, D87). A cause without a form has no field. */
11074
+ function causeOf(built) {
11075
+ const form = built.form;
11076
+ if (form === void 0) return { names: built.names };
11077
+ if (Array.isArray(form) || "record" in form || "share" in form) return {
11078
+ link: { causeParts: form },
11079
+ names: built.names
11080
+ };
11081
+ return {
11082
+ link: "value" in form ? { cause: form.value } : form,
11083
+ names: built.names
11084
+ };
11085
+ }
11086
+ /** This function gives the term document of a value of an exception, or `undefined` when the value has none. */
11087
+ function termOrNothing(machine, value) {
11088
+ if (holdsHole(value)) return void 0;
11089
+ try {
11090
+ return encodeValue(machine, value);
11091
+ } catch {
11092
+ return;
11093
+ }
11094
+ }
11095
+ /** This function reads a field of a value, or gives `MISSING` when the read throws. */
11096
+ function readField(value, key) {
11097
+ try {
11098
+ return value[key];
11099
+ } catch {
11100
+ return MISSING;
11101
+ }
11102
+ }
11103
+ /** This function gives the forms of the parts with a form, with their keys, in the order of the keys. */
11104
+ function keptOf(keys, built) {
11105
+ const kept = [];
11106
+ for (let place = 0; place < keys.length; place += 1) {
11107
+ const form = built[place]?.form;
11108
+ if (form !== void 0) kept.push([keys[place], form]);
11109
+ }
11110
+ return kept;
11111
+ }
11112
+ /**
11113
+ * This function writes a cause without a term document as JSON (RUN.REPLAY-CAUSES, RUN.REPLAY-HIDDEN, RUN.REPLAY-FIELDS).
11114
+ * The cause is an exception with its hidden fields and its causes, or a container with an exception (D87). A host
11115
+ * makes the exception, thus a part without a term document is a note in `dropped`, not a refusal (D75, D76).
11116
+ *
11117
+ * The walk gives each exception an index in the order of a depth-first walk. It takes the fields in `parts` in the
11118
+ * order of their keys, the hidden fields in the order of `HIDDEN`, then the cause (D78). A list or a plain record
11119
+ * without a term document is a container of parts, with its items in their order (D82). A cause is a container only
11120
+ * when it holds an exception (D87). A value that is an earlier exception of the walk is its index in `loop` (D77).
11121
+ *
11122
+ * A container that an earlier place holds is its index in `share`, also a container that holds itself (D88). The walk is
11123
+ * a loop, thus a long chain does not overflow the stack.
11124
+ */
11125
+ function causeJson(machine, root) {
11126
+ const items = [];
11127
+ const index = /* @__PURE__ */ new Map();
11128
+ const holders = /* @__PURE__ */ new Map();
11129
+ const tasks = [];
11130
+ const later = (children) => {
11131
+ for (let place = children.length - 1; place >= 0; place -= 1) tasks.push(children[place]);
11132
+ };
11133
+ const hold = (name, value, keep, children) => {
11134
+ const at = items.length;
11135
+ holders.set(value, at);
11136
+ const list = Array.isArray(value);
11137
+ const keys = list ? [] : Object.keys(value);
11138
+ const slots = [];
11139
+ items.push({
11140
+ name,
11141
+ list,
11142
+ keep,
11143
+ keys,
11144
+ slots
11145
+ });
11146
+ const size = list ? value.length : keys.length;
11147
+ for (let place = 0; place < size; place += 1) {
11148
+ const key = list ? place : keys[place];
11149
+ const item = list && !Object.hasOwn(value, place) ? MISSING : readField(value, key);
11150
+ const put = (part) => {
11151
+ slots[place] = part;
11152
+ };
11153
+ children.push({
11154
+ value: item,
11155
+ name: `${name}.${key}`,
11156
+ tried: false,
11157
+ nest: true,
11158
+ keep: false,
11159
+ put
11160
+ });
11161
+ }
11162
+ return at;
11163
+ };
11164
+ const open = (current) => {
11165
+ const at = items.length;
11166
+ index.set(current, index.size);
11167
+ const fields = [];
11168
+ const linked = [];
11169
+ for (const key of Object.keys(current)) {
11170
+ if (ownField(key)) continue;
11171
+ const value = readField(current, key);
11172
+ const term = value === MISSING ? void 0 : termOrNothing(machine, value);
11173
+ if (term === void 0) linked.push([key, value]);
11174
+ else fields.push([key, term]);
11175
+ }
11176
+ const node = {
11177
+ head: {
11178
+ name: String(current.name),
11179
+ message: String(current.message),
11180
+ ...fields.length === 0 ? {} : { fields: Object.fromEntries(fields) }
11181
+ },
11182
+ keys: linked.map(([key]) => key),
11183
+ parts: [],
11184
+ hiddenKeys: [],
11185
+ hidden: []
11186
+ };
11187
+ items.push(node);
11188
+ const children = [];
11189
+ for (let place = 0; place < linked.length; place += 1) {
11190
+ const [key, value] = linked[place];
11191
+ const put = (part) => {
11192
+ node.parts[place] = part;
11193
+ };
11194
+ children.push({
11195
+ value,
11196
+ name: key,
11197
+ tried: true,
11198
+ nest: true,
11199
+ keep: false,
11200
+ put
11201
+ });
11202
+ }
11203
+ for (const key of HIDDEN) {
11204
+ if (Object.getOwnPropertyDescriptor(current, key)?.enumerable !== false) continue;
11205
+ const place = node.hiddenKeys.length;
11206
+ node.hiddenKeys.push(key);
11207
+ const value = readField(current, key);
11208
+ const put = (part) => {
11209
+ node.hidden[place] = part;
11210
+ };
11211
+ children.push({
11212
+ value,
11213
+ name: key,
11214
+ tried: false,
11215
+ nest: true,
11216
+ keep: Array.isArray(value),
11217
+ put
11218
+ });
11219
+ }
11220
+ if (Object.hasOwn(current, "cause")) {
11221
+ const put = (part) => {
11222
+ node.cause = part;
11223
+ };
11224
+ children.push({
11225
+ value: current.cause,
11226
+ name: "cause",
11227
+ tried: false,
11228
+ nest: false,
11229
+ keep: false,
11230
+ put
11231
+ });
11232
+ }
11233
+ later(children);
11234
+ return at;
11235
+ };
11236
+ let top = { none: "cause" };
11237
+ tasks.push({
11238
+ value: root,
11239
+ name: "cause",
11240
+ tried: true,
11241
+ nest: false,
11242
+ keep: false,
11243
+ put: (part) => {
11244
+ top = part;
11245
+ }
11246
+ });
11247
+ for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {
11248
+ const value = task.value;
11249
+ if (value === MISSING) {
11250
+ task.put({ none: task.name });
11251
+ continue;
11252
+ }
11253
+ const loop = index.get(value);
11254
+ if (loop !== void 0) {
11255
+ task.put({ loop });
11256
+ continue;
11257
+ }
11258
+ const term = task.tried || task.keep ? void 0 : termOrNothing(machine, value);
11259
+ if (term !== void 0) task.put({ value: term });
11260
+ else if (value instanceof Error) task.put({ node: open(value) });
11261
+ else if ((Array.isArray(value) || isRecord(value)) && (task.nest || holdsException(value))) {
11262
+ const held = holders.get(value);
11263
+ if (held === void 0) {
11264
+ const children = [];
11265
+ task.put({ holder: hold(task.name, value, task.keep, children) });
11266
+ later(children);
11267
+ } else {
11268
+ if (task.keep) items[held].keep = true;
11269
+ task.put({
11270
+ same: held,
11271
+ name: task.name
11272
+ });
11273
+ }
11274
+ } else task.put({ none: task.name });
11275
+ }
11276
+ const { formed, shares } = formsOf(items);
11277
+ const forms = [];
11278
+ const builtOf = (part) => {
11279
+ if ("none" in part) return { names: [part.none] };
11280
+ if ("node" in part) return {
11281
+ form: { exception: forms[part.node] },
11282
+ names: []
11283
+ };
11284
+ if ("holder" in part) return forms[part.holder];
11285
+ if ("same" in part) return formed[part.same] === true ? {
11286
+ form: { share: shares[part.same] },
11287
+ names: []
11288
+ } : { names: [part.name] };
11289
+ return {
11290
+ form: part,
11291
+ names: []
11292
+ };
11293
+ };
11294
+ for (let at = items.length - 1; at >= 0; at -= 1) {
11295
+ const item = items[at];
11296
+ if ("slots" in item) {
11297
+ if (formed[at] !== true) {
11298
+ forms[at] = { names: [item.name] };
11299
+ continue;
11300
+ }
11301
+ const built = Array.from(item.slots, builtOf);
11302
+ const form = item.list ? built.map((part) => part.form ?? { dropped: true }) : { record: Object.fromEntries(keptOf(item.keys, built)) };
11303
+ forms[at] = {
11304
+ form,
11305
+ names: built.flatMap((part) => part.names)
11306
+ };
11307
+ continue;
11308
+ }
11309
+ const { head, keys, parts, hiddenKeys, hidden, cause } = item;
11310
+ const linked = Array.from(parts, builtOf);
11311
+ const kept = Array.from(hidden, builtOf);
11312
+ const link = cause === void 0 ? { names: [] } : causeOf(builtOf(cause));
11313
+ const dropped = [
11314
+ ...linked,
11315
+ ...kept,
11316
+ link
11317
+ ].flatMap((part) => part.names);
11318
+ const partsOf = keptOf(keys, linked);
11319
+ const hiddenOf = keptOf(hiddenKeys, kept);
11320
+ forms[at] = {
11321
+ ...head,
11322
+ ...partsOf.length === 0 ? {} : { parts: Object.fromEntries(partsOf) },
11323
+ ...dropped.length === 0 ? {} : { dropped },
11324
+ ...hiddenOf.length === 0 ? {} : { hidden: Object.fromEntries(hiddenOf) },
11325
+ ...link.link
11326
+ };
11327
+ }
11328
+ return causeOf(builtOf(top));
11329
+ }
11330
+ /**
11331
+ * This function tells which containers of the walk of `causeJson` get a form, and it gives each such container its
11332
+ * index for `share` (D88). A container gets a form when it is a hidden list, or when an item has a form. A share has
11333
+ * the form of its container. Thus a cycle of containers without another form has no form. The index counts the
11334
+ * containers with a form in the order of the walk, as `decodeLog` meets them.
11335
+ */
11336
+ function formsOf(items) {
11337
+ const formed = [];
11338
+ const users = /* @__PURE__ */ new Map();
11339
+ const work = [];
11340
+ for (let at = 0; at < items.length; at += 1) {
11341
+ const item = items[at];
11342
+ if (!("slots" in item)) continue;
11343
+ let seed = item.keep;
11344
+ for (const part of item.slots) {
11345
+ const on = "holder" in part ? part.holder : "same" in part ? part.same : void 0;
11346
+ if (on === void 0) seed ||= !("none" in part);
11347
+ else {
11348
+ const list = users.get(on);
11349
+ if (list === void 0) users.set(on, [at]);
11350
+ else list.push(at);
11351
+ }
11352
+ }
11353
+ if (seed) {
11354
+ formed[at] = true;
11355
+ work.push(at);
11356
+ }
11357
+ }
11358
+ for (let at = work.pop(); at !== void 0; at = work.pop()) for (const user of users.get(at) ?? []) {
11359
+ if (formed[user] === true) continue;
11360
+ formed[user] = true;
11361
+ work.push(user);
11362
+ }
11363
+ const shares = [];
11364
+ let count = 0;
11365
+ for (let at = 0; at < items.length; at += 1) {
11366
+ if (formed[at] !== true) continue;
11367
+ shares[at] = count;
11368
+ count += 1;
11369
+ }
11370
+ return {
11371
+ formed,
11372
+ shares
11373
+ };
11374
+ }
11375
+ /** This function gives the message of an exception, or a short text for another value. */
11376
+ function messageOf(error) {
11377
+ return error instanceof Error ? error.message : describe(error);
11378
+ }
11379
+ /** This function writes a value of a log as a term document, or throws a `TypeError` that names the value. */
11380
+ function termOf(machine, value, what) {
11381
+ try {
11382
+ return encodeValue(machine, value);
11383
+ } catch (error) {
11384
+ throw new TypeError(`encodeLog cannot write ${what()}: ${messageOf(error)}`);
11385
+ }
11386
+ }
11387
+ /** This function writes an error value of a log as JSON, or throws a `TypeError` that names the error. */
11388
+ function errorJson(machine, error, what) {
11389
+ for (const key of Object.keys(error)) if (!errorField(key)) throw new TypeError(`encodeLog cannot write ${what()}: the error has the field ${key}, and the JSON form has no field for it.`);
11390
+ const base = {
11391
+ code: error.code,
11392
+ reason: error.reason,
11393
+ ...error.place === void 0 ? {} : { place: error.place }
11394
+ };
11395
+ if (!Object.hasOwn(error, "cause")) return base;
11396
+ const cause = error.cause;
11397
+ try {
11398
+ return {
11399
+ ...base,
11400
+ cause: encodeValue(machine, cause)
11401
+ };
11402
+ } catch (failure) {
11403
+ const { link, names } = causeJson(machine, cause);
11404
+ if (link === void 0) throw new TypeError(`encodeLog cannot write the cause of ${what()}: ${messageOf(failure)}`);
11405
+ return {
11406
+ ...base,
11407
+ ...link,
11408
+ ...names.length === 0 ? {} : { dropped: names }
11409
+ };
11410
+ }
11411
+ }
11412
+ /**
11413
+ * This function writes a log as JSON (RUN.REPLAY-JSON, D75). Then `JSON.stringify` gives the text of a golden file.
11414
+ *
11415
+ * - Each payload and each value of an outcome is a term document of `encodeValue`. Thus `NaN`, `-0` and `undefined`
11416
+ * stay exact, and a member of a domain with a codec is `ext.domain`.
11417
+ * - An error keeps its code, its reason, its place and its cause. A cause that `encodeValue` cannot write and that is
11418
+ * an exception keeps its name and its message in the field `exception`.
11419
+ * - An exception also keeps its own fields that `encodeValue` writes, and the chain of its causes (RUN.REPLAY-CAUSES).
11420
+ * The list `dropped` names each other own field. A cause that is an earlier exception of the chain is its index in `loop`.
11421
+ * - An exception keeps the hidden fields of the standard classes in `hidden`, for example `errors` of an
11422
+ * `AggregateError` (RUN.REPLAY-HIDDEN, D77). Each exception in them has the rule of a cause.
11423
+ * - An enumerable field without a term document that is an exception, a list or a plain record is in `parts`
11424
+ * (RUN.REPLAY-FIELDS, D78, D82). An item of a list without a form is the mark `dropped` at its place.
11425
+ * - A cause without a term document that is a list or a plain record with an exception is in `causeParts`
11426
+ * (RUN.REPLAY-CAUSE-PARTS, D87). The rule is the same for the cause of an exception and of an error value.
11427
+ * - A list or a record of parts that an earlier place of one error holds is the part `share` with its index
11428
+ * (RUN.REPLAY-SHARED, D88). This rule also covers a container that holds itself.
11429
+ * - An outcome that the log does not have stays absent.
11430
+ *
11431
+ * @param machine - The machine of the run, or only its domains.
11432
+ * @param log - The log of a recorder.
11433
+ * @returns The JSON form. `decodeLog` gives the log again.
11434
+ * @throws {TypeError} A value has no term document, for example a closure, a host thing, a symbol, or a value that no
11435
+ * domain with a codec holds. The message names the effect and its address. A part of an exception is not a refusal.
11436
+ */
11437
+ function encodeLog(machine, log) {
11438
+ return {
11439
+ version: 1,
11440
+ effects: log.effects.map((entry) => {
11441
+ const at = (field) => () => `the ${field} of the effect ${entry.kind} at the address ${entry.address}`;
11442
+ const head = {
11443
+ address: entry.address,
11444
+ kind: entry.kind,
11445
+ payload: termOf(machine, entry.payload, at("payload"))
11446
+ };
11447
+ const outcome = entry.outcome;
11448
+ if (outcome === void 0) return {
11449
+ ...head,
11450
+ waited: entry.waited
11451
+ };
11452
+ const json = outcome.ok ? {
11453
+ ok: true,
11454
+ value: termOf(machine, outcome.value, at("outcome"))
11455
+ } : {
11456
+ ok: false,
11457
+ error: errorJson(machine, outcome.error, at("outcome"))
11458
+ };
11459
+ return {
11460
+ ...head,
11461
+ outcome: json,
11462
+ waited: entry.waited
11463
+ };
11464
+ }),
11465
+ settles: log.settles.map((settle) => ({
11466
+ all: settle.all,
11467
+ item: settle.item
11468
+ }))
11469
+ };
11470
+ }
11471
+ /** This function gives an exception with a name and a message. A standard name gives an instance of its class. */
11472
+ function exception(name, message) {
11473
+ const made = standard(name, message);
11474
+ if (made.name !== name) made.name = name;
11475
+ return made;
11476
+ }
11477
+ /**
11478
+ * This function gives an instance of the standard class with a name, or an `Error`. An `AggregateError` gets an empty
11479
+ * list `errors`, and a `SuppressedError` gets `undefined` for `error` and `suppressed`, as their constructors do.
11480
+ */
11481
+ function standard(name, message) {
11482
+ switch (name) {
11483
+ case "TypeError": return new TypeError(message);
11484
+ case "RangeError": return new RangeError(message);
11485
+ case "SyntaxError": return new SyntaxError(message);
11486
+ case "ReferenceError": return new ReferenceError(message);
11487
+ case "AggregateError": return new AggregateError([], message);
11488
+ case "SuppressedError": return typeof SuppressedError === "function" ? new SuppressedError(void 0, void 0, message) : new Error(message);
11489
+ default: return new Error(message);
11490
+ }
11491
+ }
11492
+ /** This function gives an exception a field that is not enumerable, as the constructor of `Error` does for `cause`. */
11493
+ function hide(error, key, value) {
11494
+ Object.defineProperty(error, key, {
11495
+ value,
11496
+ writable: true,
11497
+ enumerable: false,
11498
+ configurable: true
11499
+ });
11500
+ }
11501
+ /** This function gives the failed result of a JSON form that `decodeLog` cannot read. */
11502
+ function bad(place, reason) {
11503
+ return fail("#VALUE!", `decodeLog cannot read the log: ${reason}`, { place });
11504
+ }
11505
+ /** This function reads a term document of a log again, with the formula kit and the domains of the machine. */
11506
+ function readTerm(kit, doc, place) {
11507
+ const value = decodeValue(kit, doc);
11508
+ return value.ok ? value : bad(place, `the term document gives ${value.error.code}: ${value.error.reason}`);
11509
+ }
11510
+ /** This function reads the JSON form of an error value again. */
11511
+ function readError(kit, data, place) {
11512
+ if (!isRecord(data) || typeof data["code"] !== "string" || !data["code"].startsWith("#") || typeof data["reason"] !== "string") return bad(place, "an error is a record with a code that starts with # and a reason.");
11513
+ for (const key of Object.keys(data)) if (!errorField(key) && key !== "exception" && key !== "causeParts" && key !== "dropped") return bad(place, `an error has no field ${key}.`);
11514
+ const keys = data["place"];
11515
+ if (keys !== void 0 && !(Array.isArray(keys) && keys.every((key) => isKey(key)))) return bad([...place, "place"], "a place is a list of texts and numbers.");
11516
+ const dropped = data["dropped"];
11517
+ if (dropped !== void 0 && !(Array.isArray(dropped) && dropped.every((name) => typeof name === "string"))) return bad([...place, "dropped"], "the list dropped holds texts.");
11518
+ const error = {
11519
+ code: data["code"],
11520
+ reason: data["reason"]
11521
+ };
11522
+ if (keys !== void 0) error.place = keys;
11523
+ const record = data;
11524
+ const links = LINKS.filter((key) => key !== "loop" && Object.hasOwn(record, key));
11525
+ if (links.length > 1) return bad(place, "an error has a cause, an exception or causeParts, not more than one.");
11526
+ const link = links[0];
11527
+ if (link === "cause") {
11528
+ const cause = readTerm(kit, data["cause"], [...place, "cause"]);
11529
+ if (!cause.ok) return cause;
11530
+ error.cause = cause.value;
11531
+ } else if (link !== void 0) {
11532
+ const read = readCause(kit, link, data[link], [...place, link]);
11533
+ if (!read.ok) return read;
11534
+ error.cause = read.value;
11535
+ }
11536
+ return ok(error);
11537
+ }
11538
+ /**
11539
+ * This function reads the JSON form of a cause again: an exception in `exception`, or a container in `causeParts`
11540
+ * (RUN.REPLAY-CAUSES, RUN.REPLAY-HIDDEN, RUN.REPLAY-FIELDS, D87). The walk has the order of `causeJson`, thus a loop
11541
+ * gives the same exception. A list or a record of parts gives a new list or plain record (D82). A share gives the same
11542
+ * list or record as its earlier place (D88). The walk is a loop, thus a long chain does not overflow the stack.
11543
+ */
11544
+ function readCause(kit, kind, data, place) {
11545
+ const chain = [];
11546
+ const held = [];
11547
+ const tasks = [];
11548
+ const open = (at, where) => {
11549
+ if (!isRecord(at) || typeof at["name"] !== "string" || typeof at["message"] !== "string" || !Object.keys(at).every(exceptionField)) return bad(where, "an exception is a record with the texts name and message, and only the fields fields, parts, dropped, hidden, cause, exception, loop and causeParts.");
11550
+ const made = exception(at["name"], at["message"]);
11551
+ const fields = at["fields"];
11552
+ if (fields !== void 0) {
11553
+ if (!isRecord(fields)) return bad([...where, "fields"], "the fields of an exception are a record.");
11554
+ for (const key of Object.keys(fields)) {
11555
+ if (ownField(key)) return bad([
11556
+ ...where,
11557
+ "fields",
11558
+ key
11559
+ ], `the field ${key} of an exception is not in its fields.`);
11560
+ const value = readTerm(kit, fields[key], [
11561
+ ...where,
11562
+ "fields",
11563
+ key
11564
+ ]);
11565
+ if (!value.ok) return value;
11566
+ Object.defineProperty(made, key, {
11567
+ value: value.value,
11568
+ writable: true,
11569
+ enumerable: true,
11570
+ configurable: true
11571
+ });
11572
+ }
11573
+ }
11574
+ const dropped = at["dropped"];
11575
+ if (dropped !== void 0 && !(Array.isArray(dropped) && dropped.every((name) => typeof name === "string"))) return bad([...where, "dropped"], "the list dropped holds texts.");
11576
+ chain.push(made);
11577
+ const children = [];
11578
+ const taken = (key) => isRecord(fields) && Object.hasOwn(fields, key);
11579
+ const parts = at["parts"];
11580
+ if (parts !== void 0) {
11581
+ if (!isRecord(parts)) return bad([...where, "parts"], "the parts of an exception are a record.");
11582
+ for (const key of Object.keys(parts)) {
11583
+ if (ownField(key) || taken(key)) return bad([
11584
+ ...where,
11585
+ "parts",
11586
+ key
11587
+ ], `the field ${key} of an exception is not in its parts.`);
11588
+ const show = (value) => {
11589
+ Object.defineProperty(made, key, {
11590
+ value,
11591
+ writable: true,
11592
+ enumerable: true,
11593
+ configurable: true
11594
+ });
11595
+ };
11596
+ const read = slotTask(parts[key], [
11597
+ ...where,
11598
+ "parts",
11599
+ key
11600
+ ], false, show);
11601
+ if (!read.ok) return read;
11602
+ show(void 0);
11603
+ children.push(read.value);
11604
+ }
11605
+ }
11606
+ const hidden = at["hidden"];
11607
+ if (hidden !== void 0) {
11608
+ if (!isRecord(hidden)) return bad([...where, "hidden"], "the hidden fields of an exception are a record.");
11609
+ for (const key of Object.keys(hidden)) if (!HIDDEN.includes(key) || taken(key) || isRecord(parts) && Object.hasOwn(parts, key)) return bad([
11610
+ ...where,
11611
+ "hidden",
11612
+ key
11613
+ ], `an exception has no hidden field ${key}.`);
11614
+ for (const key of HIDDEN) {
11615
+ if (!Object.hasOwn(hidden, key)) continue;
11616
+ const read = slotTask(hidden[key], [
11617
+ ...where,
11618
+ "hidden",
11619
+ key
11620
+ ], false, (value) => hide(made, key, value));
11621
+ if (!read.ok) return read;
11622
+ children.push(read.value);
11623
+ }
11624
+ }
11625
+ const record = at;
11626
+ const links = LINKS.filter((key) => Object.hasOwn(record, key));
11627
+ if (links.length > 1) return bad(where, "an exception has a cause, an exception, a loop or causeParts, not more than one.");
11628
+ const link = links[0];
11629
+ if (link !== void 0) {
11630
+ const read = linkTask(link, record[link], [...where, link], (value) => hide(made, "cause", value));
11631
+ if (!read.ok) return read;
11632
+ children.push(read.value);
11633
+ }
11634
+ for (let index = children.length - 1; index >= 0; index -= 1) tasks.push(children[index]);
11635
+ return ok(made);
11636
+ };
11637
+ let cause;
11638
+ const root = linkTask(kind, data, place, (value) => {
11639
+ cause = value;
11640
+ });
11641
+ if (!root.ok) return root;
11642
+ tasks.push(root.value);
11643
+ for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {
11644
+ const { kind, data: part, where } = task;
11645
+ if (kind === "dropped") continue;
11646
+ if (kind === "loop") {
11647
+ if (typeof part !== "number" || !Number.isInteger(part) || part < 0 || part >= chain.length) return bad(where, "a loop is the index of an exception of the chain until this one.");
11648
+ task.put(chain[part]);
11649
+ continue;
11650
+ }
11651
+ if (kind === "share") {
11652
+ if (typeof part !== "number" || !Number.isInteger(part) || part < 0 || part >= held.length) return bad(where, "a share is the index of a list or a record of parts of the walk until this one.");
11653
+ task.put(held[part]);
11654
+ continue;
11655
+ }
11656
+ if (kind === "list" || kind === "record") {
11657
+ const items = kind === "list" ? listTasks(part, where, held, task.put) : recordTasks(part, where, held, task.put);
11658
+ if (!items.ok) return items;
11659
+ for (let index = items.value.length - 1; index >= 0; index -= 1) tasks.push(items.value[index]);
11660
+ continue;
11661
+ }
11662
+ const value = kind === "exception" ? open(part, where) : readTerm(kit, part, where);
11663
+ if (!value.ok) return value;
11664
+ task.put(value.value);
11665
+ }
11666
+ return ok(cause);
11667
+ }
11668
+ /**
11669
+ * This function reads the field of a cause: `cause`, `exception`, `loop` or `causeParts`. A value of `causeParts` is a
11670
+ * list of parts, the part `record` or the part `share`, and no other part (D87, D88).
11671
+ */
11672
+ function linkTask(kind, data, where, put) {
11673
+ if (kind !== "causeParts") return ok({
11674
+ kind,
11675
+ data,
11676
+ where,
11677
+ put
11678
+ });
11679
+ if (Array.isArray(data)) return ok({
11680
+ kind: "list",
11681
+ data,
11682
+ where,
11683
+ put
11684
+ });
11685
+ const key = isRecord(data) && Object.keys(data).length === 1 ? Object.keys(data)[0] : void 0;
11686
+ if (isRecord(data) && (key === "record" || key === "share")) return ok({
11687
+ kind: key,
11688
+ data: data[key],
11689
+ where: [...where, key],
11690
+ put
11691
+ });
11692
+ return bad(where, "a cause of parts is a list of parts, the part record or the part share.");
11693
+ }
11694
+ /**
11695
+ * This function reads one value of a field in `parts`, in `hidden` or in a record of parts. A list is a list of parts,
11696
+ * and another value is one part.
11697
+ */
11698
+ function slotTask(data, where, item, put) {
11699
+ return Array.isArray(data) ? ok({
11700
+ kind: "list",
11701
+ data,
11702
+ where,
11703
+ put
11704
+ }) : partTask(data, where, item, put);
11705
+ }
11706
+ /**
11707
+ * This function gives a list of parts its length at once, and it gives the tasks of its items. Thus the mark `dropped`
11708
+ * leaves a hole at its place, and each later item keeps its index (D78). The list goes in `held` for a share (D88).
11709
+ */
11710
+ function listTasks(data, where, held, put) {
11711
+ const items = data;
11712
+ const list = [];
11713
+ list.length = items.length;
11714
+ held.push(list);
11715
+ put(list);
11716
+ const tasks = [];
11717
+ for (let item = 0; item < items.length; item += 1) {
11718
+ const task = slotTask(items[item], [...where, item], true, (value) => {
11719
+ list[item] = value;
11720
+ });
11721
+ if (!task.ok) return task;
11722
+ tasks.push(task.value);
11723
+ }
11724
+ return ok(tasks);
11725
+ }
11726
+ /**
11727
+ * This function gives a record of parts a new plain record (D82). It gives the tasks of its fields in the order of
11728
+ * the keys. Each key gets its place at once, thus the record keeps the order of the keys. The record goes in `held`
11729
+ * for a share (D88).
11730
+ */
11731
+ function recordTasks(data, where, held, put) {
11732
+ if (!isRecord(data)) return bad(where, "a record of parts is a record.");
11733
+ const record = {};
11734
+ held.push(record);
11735
+ put(record);
11736
+ const tasks = [];
11737
+ for (const key of Object.keys(data)) {
11738
+ const show = (value) => {
11739
+ Object.defineProperty(record, key, {
11740
+ value,
11741
+ writable: true,
11742
+ enumerable: true,
11743
+ configurable: true
11744
+ });
11745
+ };
11746
+ const task = slotTask(data[key], [...where, key], false, show);
11747
+ if (!task.ok) return task;
11748
+ show(void 0);
11749
+ tasks.push(task.value);
11750
+ }
11751
+ return ok(tasks);
11752
+ }
11753
+ /**
11754
+ * This function reads one part: a record with only one of the fields `value`, `exception`, `loop`, `record` and
11755
+ * `share`. An item of a list can also be the mark `{ "dropped": true }`.
11756
+ */
11757
+ function partTask(data, where, item, put) {
11758
+ const keys = isRecord(data) ? Object.keys(data) : [];
11759
+ const kind = keys[0];
11760
+ const mark = kind === "dropped" && item && isRecord(data) && data[kind] === true;
11761
+ if (!isRecord(data) || keys.length !== 1 || kind === void 0 || !(PARTS$1.includes(kind) || mark)) return bad(where, "a field of parts is a part or a list of parts. A part has only one of the fields value, exception, loop, record and share, or an item is the mark dropped.");
11762
+ return ok({
11763
+ kind,
11764
+ data: data[kind],
11765
+ where: [...where, kind],
11766
+ put
11767
+ });
11768
+ }
11769
+ /** The fields of the JSON form of an exception that give its cause. */
11770
+ const LINKS = /* @__PURE__ */ Object.freeze([
11771
+ "cause",
11772
+ "exception",
11773
+ "loop",
11774
+ "causeParts"
11775
+ ]);
11776
+ /** The fields of the JSON form of a part of a field in `parts` or `hidden`. */
11777
+ const PARTS$1 = /* @__PURE__ */ Object.freeze([
11778
+ "value",
11779
+ "exception",
11780
+ "loop",
11781
+ "record",
11782
+ "share"
11783
+ ]);
11784
+ /** This function reads the JSON form of one effect again. */
11785
+ function readEntry(kit, data, place) {
11786
+ if (!isRecord(data) || typeof data["address"] !== "string" || typeof data["kind"] !== "string" || typeof data["waited"] !== "boolean" || !Object.hasOwn(data, "payload")) return bad(place, "an effect is a record with the texts address and kind, a payload, and the truth value waited.");
11787
+ for (const key of Object.keys(data)) if (key !== "address" && key !== "kind" && key !== "payload" && key !== "outcome" && key !== "waited") return bad(place, `an effect has no field ${key}.`);
11788
+ const payload = readTerm(kit, data["payload"], [...place, "payload"]);
11789
+ if (!payload.ok) return payload;
11790
+ const head = {
11791
+ address: data["address"],
11792
+ kind: data["kind"],
11793
+ payload: payload.value,
11794
+ waited: data["waited"]
11795
+ };
11796
+ if (!Object.hasOwn(data, "outcome")) return ok(head);
11797
+ const raw = data["outcome"];
11798
+ const at = [...place, "outcome"];
11799
+ if (isRecord(raw) && raw["ok"] === true && Object.hasOwn(raw, "value") && Object.keys(raw).length === 2) {
11800
+ const value = readTerm(kit, raw["value"], [...at, "value"]);
11801
+ return value.ok ? ok({
11802
+ ...head,
11803
+ outcome: ok(value.value)
11804
+ }) : value;
11805
+ }
11806
+ if (isRecord(raw) && raw["ok"] === false && Object.keys(raw).length === 2) {
11807
+ const error = readError(kit, raw["error"], [...at, "error"]);
11808
+ return error.ok ? ok({
11809
+ ...head,
11810
+ outcome: {
11811
+ ok: false,
11812
+ error: error.value
11813
+ }
11814
+ }) : error;
11815
+ }
11816
+ return bad(at, "an outcome is a record with ok true and a value, or with ok false and an error.");
11817
+ }
11818
+ /**
11819
+ * This function reads the JSON form of a log again (RUN.REPLAY-JSON). It reads each term document with the formula kit
11820
+ * and the domains of the machine. A cause in the field `exception` becomes an exception with that name and message.
11821
+ * The exception gets its fields and the chain of its causes again, also a cycle (RUN.REPLAY-CAUSES). A list gets a
11822
+ * hole at the place of the mark `dropped`, thus each later item keeps its index (D78). Each share of a list or a record
11823
+ * gives the same object (RUN.REPLAY-SHARED).
11824
+ *
11825
+ * @param machine - The machine of the run, or only its domains.
11826
+ * @param data - The JSON form, for example from `JSON.parse` of a golden file.
11827
+ * @returns The log for `replayer`, or `#VALUE!` with the place of the first field that it cannot read.
11828
+ */
11829
+ function decodeLog(machine, data) {
11830
+ if (!isRecord(data) || data["version"] !== 1) return bad([], "the form is a record with the version 1.");
11831
+ const list = data["effects"];
11832
+ const order = data["settles"];
11833
+ if (!Array.isArray(list) || !Array.isArray(order) || Object.keys(data).length !== 3) return bad([], "the form has only the version and the lists effects and settles.");
11834
+ const domains = machine.domains;
11835
+ const kit = {
11836
+ ...formulaMachine(),
11837
+ ...domains === void 0 ? {} : { domains }
11838
+ };
11839
+ const effects = [];
11840
+ for (let index = 0; index < list.length; index += 1) {
11841
+ const entry = readEntry(kit, list[index], ["effects", index]);
11842
+ if (!entry.ok) return entry;
11843
+ effects.push(entry.value);
11844
+ }
11845
+ const settles = [];
11846
+ for (let index = 0; index < order.length; index += 1) {
11847
+ const settle = order[index];
11848
+ if (!isRecord(settle) || typeof settle["all"] !== "string" || !Number.isInteger(settle["item"]) || Object.keys(settle).length !== 2) return bad(["settles", index], "a settle is a record with only the text all and the whole number item.");
11849
+ settles.push({
11850
+ all: settle["all"],
11851
+ item: settle["item"]
11852
+ });
11853
+ }
11854
+ return ok({
11855
+ effects,
11856
+ settles
11857
+ });
11858
+ }
9953
11859
  //#endregion
9954
11860
  //#region src/agree.ts
9955
11861
  /** The tiers that `agree` compares when its options name none. */
@@ -10221,18 +12127,12 @@ function agree(machine, doc, context = makeContext(), options = {}) {
10221
12127
  function watched(perform) {
10222
12128
  const effects = [];
10223
12129
  const settles = [];
10224
- const inner = perform[JOURNAL];
10225
- const settled = (all, item) => {
12130
+ const journal = relay(perform, (all, item) => {
10226
12131
  settles.push({
10227
12132
  all,
10228
12133
  item
10229
12134
  });
10230
- inner?.settled?.(all, item);
10231
- };
10232
- const journal = inner?.next === void 0 ? { settled } : {
10233
- settled,
10234
- next: (all, waiting) => inner.next?.(all, waiting)
10235
- };
12135
+ });
10236
12136
  const host = (effect) => {
10237
12137
  effects.push(effect);
10238
12138
  return perform(effect);
@@ -10254,6 +12154,82 @@ function settlesDiffer(a, b) {
10254
12154
  if (x?.all !== y?.all || x?.item !== y?.item) return `The wait ${index} settles ${settleText(x)} in the plan, and ${settleText(y)} in the tier.`;
10255
12155
  }
10256
12156
  }
12157
+ /** The roots beside `self` that a value without static reads keeps whole (READS.KEPT). */
12158
+ const KEPT_ROOTS = /* @__PURE__ */ Object.freeze([
12159
+ "names",
12160
+ "world",
12161
+ "event",
12162
+ "caps"
12163
+ ]);
12164
+ /**
12165
+ * This function tells if the plan does not know the reads of a run. A value without static reads keeps each root
12166
+ * (READS.KEPT), thus the list holds a kept read of each whole root.
12167
+ */
12168
+ function readsUnknown(reads) {
12169
+ return KEPT_ROOTS.every((root) => reads.some((read) => read.kept === true && read.path.length === 1 && read.path[0] === root));
12170
+ }
12171
+ /**
12172
+ * This function gives the reads that `agreeRun` compares: the free reads of the resolutions (RUN.AGREES-READS). A
12173
+ * kept read is the bound of the plan for the later reads of a value, and the reference has no such bound.
12174
+ */
12175
+ function resolutions(reads) {
12176
+ return reads.filter((read) => read.free && read.kept !== true);
12177
+ }
12178
+ function pathText(path) {
12179
+ if (path === void 0) return "no read";
12180
+ try {
12181
+ return JSON.stringify(path);
12182
+ } catch {
12183
+ return path.map(String).join(", ");
12184
+ }
12185
+ }
12186
+ /**
12187
+ * This function gives the rule of a comparison of reads. The rule of the caller answers first. Each tier makes its
12188
+ * own nodes of a tree and its own adopted things. Thus two host things are the same when they have the same label,
12189
+ * and they are nodes or have the same JSON object.
12190
+ */
12191
+ function sameThing(equal) {
12192
+ return (a, b) => {
12193
+ const told = equal?.(a, b);
12194
+ if (told !== void 0) return told;
12195
+ if (!isHostThing(a) || !isHostThing(b)) return void 0;
12196
+ if (a.label !== b.label) return false;
12197
+ if (a.label.startsWith("node ")) return true;
12198
+ try {
12199
+ return Object.is(a.toJson(), b.toJson());
12200
+ } catch {
12201
+ return false;
12202
+ }
12203
+ };
12204
+ }
12205
+ /** This function gives the difference of what two reads reached, or `undefined` when they agree. */
12206
+ function reachedDiffers(a, b, equal, strict) {
12207
+ if (a.ok && b.ok) return sameValue(a.value, b.value, equal) ? void 0 : "The read reaches another value in the tier.";
12208
+ if (!a.ok && !b.ok) {
12209
+ if (a.error.code !== b.error.code) return `The read gives ${a.error.code} in the plan, and ${b.error.code} in the tier.`;
12210
+ return strict && a.error.reason !== b.error.reason ? `The read gives ${a.error.code} with another reason in the tier: "${b.error.reason}" for "${a.error.reason}".` : void 0;
12211
+ }
12212
+ if (!b.ok) return `The read reaches a value in the plan, and ${b.error.code} in the tier.`;
12213
+ return `The read gives ${a.error.code} in the plan, and a value in the tier.`;
12214
+ }
12215
+ /**
12216
+ * This function gives the first difference of the reads of the plan and of a tier, or `undefined` when they agree
12217
+ * (RUN.AGREES-READS). Only the free reads of the resolutions compare, in their order. When the plan does not know its
12218
+ * reads, the function compares nothing.
12219
+ */
12220
+ function readsDiffer(plan, tier, options) {
12221
+ if (readsUnknown(plan)) return void 0;
12222
+ const a = resolutions(plan);
12223
+ const b = resolutions(tier);
12224
+ const equal = sameThing(options.equal);
12225
+ for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
12226
+ const x = a[index];
12227
+ const y = b[index];
12228
+ if (x === void 0 || y === void 0 || !sameValue(x.path, y.path, equal)) return `The free read ${index} is ${pathText(x?.path)} in the plan, and ${pathText(y?.path)} in the tier.`;
12229
+ const why = reachedDiffers(x.reached, y.reached, equal, options.strict === true);
12230
+ if (why !== void 0) return `The free read ${index} of ${pathText(x.path)} differs. ${why}`;
12231
+ }
12232
+ }
10257
12233
  /**
10258
12234
  * This function compares the run of a document in a plan with its run in other tiers (RUN.AGREES). First the plan
10259
12235
  * starts the run with a recorder around the host. Then each tier replays the log of that run. These tiers are the
@@ -10262,6 +12238,13 @@ function settlesDiffer(a, b) {
10262
12238
  * The rules of `agree` compare the results and the effects, with their addresses and outcomes. A tier must also
10263
12239
  * settle the waits of each `all` in the order of the plan, thus a replay keeps the order of the waits.
10264
12240
  *
12241
+ * The reference run must also give the free reads of the plan, in their order (RUN.AGREES-READS). Another replay of
12242
+ * the plan records these reads. A kept read does not compare. When the plan keeps each root, its reads are not known,
12243
+ * and no read compares.
12244
+ *
12245
+ * One replayer of the log serves each tier and the replay for the reads (RUN.AGREES-ONE-REPLAYER). The replayer keeps
12246
+ * no state of a run (RUN.REPLAY-RUNS), thus each tier replays the same log as with a replayer of its own.
12247
+ *
10265
12248
  * @param machine - The world, the evaluators and the runners.
10266
12249
  * @param doc - The document.
10267
12250
  * @param context - The names and the capabilities at the root.
@@ -10285,17 +12268,24 @@ async function agreeRun(machine, doc, context = makeContext(), options = {}) {
10285
12268
  const result = await plan.run(context, { perform: first.perform });
10286
12269
  const saw = observe?.();
10287
12270
  const log = recording.log();
12271
+ let planReads;
12272
+ let compared;
12273
+ const replay = replayer(log);
10288
12274
  for (const tier of options.tiers ?? DEFAULT_TIERS) {
10289
12275
  if (tier === "fixed") continue;
10290
- const replay = watched(replayer(log));
10291
- const host = { perform: replay.perform };
12276
+ const tierReplay = watched(replay);
12277
+ const host = { perform: tierReplay.perform };
10292
12278
  let other;
10293
- if (tier === "reference") other = await referenceRun(machine, doc, context, {
10294
- ...declared,
10295
- ...host,
10296
- ...options.definitions === void 0 ? {} : { definitions: options.definitions }
10297
- });
10298
- else if (tier === "traced") other = (await run(machine, doc, context, {
12279
+ let tierReads;
12280
+ if (tier === "reference") {
12281
+ tierReads = [];
12282
+ other = await referenceRun(machine, doc, context, {
12283
+ ...declared,
12284
+ ...host,
12285
+ reads: tierReads,
12286
+ ...options.definitions === void 0 ? {} : { definitions: options.definitions }
12287
+ });
12288
+ } else if (tier === "traced") other = (await run(machine, doc, context, {
10299
12289
  ...declared,
10300
12290
  ...host
10301
12291
  })).result;
@@ -10307,7 +12297,20 @@ async function agreeRun(machine, doc, context = makeContext(), options = {}) {
10307
12297
  const compareCalls = observe !== void 0 && tier !== "folds";
10308
12298
  const calls = observe?.();
10309
12299
  if (overflowed(result) || overflowed(other)) continue;
10310
- const why = resultDiffers(result, other, options) ?? effectsDiffer(first.effects, replay.effects, options) ?? settlesDiffer(first.settles, replay.settles) ?? (compareCalls && !sameValue(saw, calls, options.equal) ? "The host saw other calls in the tier." : void 0);
12300
+ let why = resultDiffers(result, other, options) ?? effectsDiffer(first.effects, tierReplay.effects, options) ?? settlesDiffer(first.settles, tierReplay.settles) ?? (compareCalls && !sameValue(saw, calls, options.equal) ? "The host saw other calls in the tier." : void 0);
12301
+ if (why === void 0 && tierReads !== void 0) {
12302
+ if (planReads === void 0) {
12303
+ const reads = [];
12304
+ await plan.run(context, {
12305
+ perform: replay,
12306
+ reads
12307
+ });
12308
+ observe?.();
12309
+ planReads = reads;
12310
+ }
12311
+ why = readsDiffer(planReads, tierReads, options);
12312
+ if (why === void 0 && !readsUnknown(planReads)) compared = resolutions(planReads);
12313
+ }
10311
12314
  if (why !== void 0) return {
10312
12315
  ok: false,
10313
12316
  tier,
@@ -10316,10 +12319,15 @@ async function agreeRun(machine, doc, context = makeContext(), options = {}) {
10316
12319
  reason: why
10317
12320
  };
10318
12321
  }
10319
- return {
12322
+ return compared === void 0 ? {
10320
12323
  ok: true,
10321
12324
  result,
10322
12325
  effects: first.effects
12326
+ } : {
12327
+ ok: true,
12328
+ result,
12329
+ effects: first.effects,
12330
+ reads: compared
10323
12331
  };
10324
12332
  }
10325
12333
  //#endregion
@@ -10738,7 +12746,8 @@ const ORDER = [
10738
12746
  "C7",
10739
12747
  "C8",
10740
12748
  "local",
10741
- "agree"
12749
+ "agree",
12750
+ "truth"
10742
12751
  ];
10743
12752
  /** A function in the results of the probe parts. It gives the count of its arguments. */
10744
12753
  const PROBE_FN = (...args) => args.length;
@@ -11616,14 +13625,41 @@ function examine(env, sample, contract) {
11616
13625
  if (env.runner) for (const scenario of scenariosOf(env, sample, contract, true)) checkShot(env, sample, contract, scenario, shoot(env, code, sample, scenario));
11617
13626
  }
11618
13627
  /**
13628
+ * This function checks the declared truth of a profile (D86). The function `truthy` must give `true` or `false` for
13629
+ * each member of `truthType`, and it must not throw. The members come from the lists `values` of the domains of the
13630
+ * type. A type without such a list gets the values of the results of the palette that are its members.
13631
+ */
13632
+ function checkTruth(env, code, probe) {
13633
+ const truth = declaredTruthOf(code);
13634
+ if (truth === void 0) return;
13635
+ const domains = env.machine.domains;
13636
+ if (typeIssues(truth.truthType, domains).length > 0) return;
13637
+ const samples = env.results.flatMap((result) => result.ok ? [result.value] : []);
13638
+ const of = (value) => `the member ${valueText(value)} of the truth type ${typeText(truth.truthType)}`;
13639
+ for (const value of membersOf(truth.truthType, domains, samples)) {
13640
+ let given;
13641
+ try {
13642
+ given = truth.truthy(value);
13643
+ } catch (error) {
13644
+ report(env, "truth", `The function truthy of the profile throws for ${of(value)}: ${describe(error)}`, () => probe(value));
13645
+ return;
13646
+ }
13647
+ if (typeof given === "boolean") continue;
13648
+ report(env, "truth", `The function truthy of the profile gives ${given === void 0 ? "no truth" : valueText(given)} for ${of(value)}. A truth is true or false.`, () => probe(value));
13649
+ return;
13650
+ }
13651
+ }
13652
+ /**
11619
13653
  * This function examines one evaluator or runner of a machine against the obligations of host code (K92, D36). It
11620
13654
  * starts the code directly, without the kernel, with probe parts and a probe runtime. It generates probe documents from
11621
13655
  * the contract of each kind that names the code, and it gives the probe parts chosen and random results.
11622
13656
  *
11623
13657
  * The checks follow the obligations C1 to C8 of `docs/SEMANTICS.md`. Two more checks follow the premises of the
11624
13658
  * simulation of the plan. The check `local` finds state that stays from one call to the next. The check `agree` compares
11625
- * compiled code with its definition. The
11626
- * finding of an obligation names the first probe that breaks it. An empty list means that each probe conforms.
13659
+ * compiled code with its definition. The finding of an obligation names the first probe that breaks it. An empty list
13660
+ * means that each probe conforms.
13661
+ *
13662
+ * The check `truth` tests the declared truth of a formula profile (D86).
11627
13663
  *
11628
13664
  * @param machine - The machine with the code and the world of the kinds.
11629
13665
  * @param name - The name of the evaluator or of the runner. A runner wins over an evaluator of the same name.
@@ -11654,14 +13690,34 @@ function conforms(machine, name, options = {}) {
11654
13690
  found: /* @__PURE__ */ new Map()
11655
13691
  };
11656
13692
  const types = options.types ?? typesNaming(machine.world, name, verb);
13693
+ let first;
11657
13694
  if (types.length === 0) throw new Error(`No kind of the world names ${name} for the verb ${verb}. Give the types of the probe documents in the option types.`);
11658
13695
  for (const type of types) {
11659
13696
  const found = lookupKind(machine.world, type);
11660
13697
  if (!found.ok) throw new Error(`The world has no kind for the type ${typeName(type)}.`);
11661
13698
  const contract = contractOf(env, found.kind, found.path, options.caps);
11662
13699
  const extra = own(options.values, typeName(type)) ?? own(options.values, found.path.join(".")) ?? [];
11663
- for (const sample of samplesOf(type, found.path, found.kind, contract, extra)) examine(env, sample, contract);
13700
+ for (const sample of samplesOf(type, found.path, found.kind, contract, extra)) {
13701
+ first ??= sample;
13702
+ examine(env, sample, contract);
13703
+ }
11664
13704
  }
13705
+ checkTruth(env, code, (value) => first === void 0 ? {
13706
+ type: typeName(types[0]),
13707
+ doc: {
13708
+ type: types[0],
13709
+ value: null
13710
+ },
13711
+ results: {},
13712
+ waits: [],
13713
+ caps: NO_CAPS,
13714
+ running: runner
13715
+ } : probeOf(first, {
13716
+ results: first.split.parts.map(() => ok(value)),
13717
+ waits: [],
13718
+ caps: NO_CAPS,
13719
+ running: runner
13720
+ }));
11665
13721
  return ORDER.filter((obligation) => env.found.has(obligation)).map((obligation) => env.found.get(obligation));
11666
13722
  }
11667
13723
  //#endregion
@@ -13271,6 +15327,6 @@ function typeFromSamples(values, options = {}) {
13271
15327
  return samplesAt(values, options.closed === true, 0);
13272
15328
  }
13273
15329
  //#endregion
13274
- export { ATTRIBUTE_RUNGS, CAPS_TYPE, CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, JOURNAL, 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, agree, agreeRun, agreeSchedule, ask, attributeTrace, capKeys, check, checkLatent, checkSteps, checkWorld, classify, components, conforms, context, cycles, dataEdges, decodeDomain, decodeValue, derefStep, describe, docEquals, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, 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, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stored, syntaxFormat, tag, thrown, toJson, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
15330
+ export { ATTRIBUTE_RUNGS, CAPS_TYPE, CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, JOURNAL, 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, ask, attributeTrace, capKeys, check, checkLatent, checkSteps, checkWorld, classify, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, 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, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stored, syntaxFormat, tag, thrown, toJson, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
13275
15331
 
13276
15332
  //# sourceMappingURL=index.js.map