@mark1russell7/coeval 0.24.0 → 0.25.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/README.md +3 -2
- package/build/index.d.ts +201 -7
- package/build/index.d.ts.map +1 -1
- package/build/index.js +720 -110
- package/build/index.js.map +1 -1
- package/package.json +3 -3
- package/src/agree.ts +105 -2
- package/src/evaluate.ts +49 -5
- package/src/formula.ts +62 -6
- package/src/index.ts +7 -3
- package/src/merge.ts +130 -10
- package/src/reference.ts +13 -2
- package/src/schedule.ts +11 -2
- package/src/static.ts +53 -4
- package/src/stdlib.ts +44 -18
- package/src/syntax.ts +114 -19
- package/src/types.ts +65 -0
- package/src/typing.ts +147 -12
package/build/index.js
CHANGED
|
@@ -1353,6 +1353,61 @@ function narrowAt(type, path, at, narrowed, domains) {
|
|
|
1353
1353
|
...form.closed ? { closed: true } : {}
|
|
1354
1354
|
};
|
|
1355
1355
|
}
|
|
1356
|
+
/** This function gives the type of a value that is a member of both types. The result is the narrower known type. */
|
|
1357
|
+
function meetOf(type, proved, domains) {
|
|
1358
|
+
if (isUnknown(proved, domains)) return type;
|
|
1359
|
+
const form = formOf(type, domains);
|
|
1360
|
+
if (form.t === "one") return { one: form.values.filter((value) => member(value, proved, domains)) };
|
|
1361
|
+
return !isUnknown(type, domains) && isPrecise(type, domains) && fits(type, proved, domains) ? type : proved;
|
|
1362
|
+
}
|
|
1363
|
+
/** This function gives the type of a value of the first type that is not a member of the second type. */
|
|
1364
|
+
function withoutOf(type, removed, domains) {
|
|
1365
|
+
if (isUnknown(removed, domains)) return type;
|
|
1366
|
+
const form = formOf(type, domains);
|
|
1367
|
+
if (form.t === "one") return { one: form.values.filter((value) => !member(value, removed, domains)) };
|
|
1368
|
+
if (form.t === "union") {
|
|
1369
|
+
const members = form.members.map((each) => withoutOf(each, removed, domains)).filter((each) => each !== "never");
|
|
1370
|
+
return members.length === 0 ? "never" : members.length === 1 ? members[0] : { union: members };
|
|
1371
|
+
}
|
|
1372
|
+
return isPrecise(type, domains) && fits(type, removed, domains) ? "never" : type;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* This function gives a type with one proof at a path (STATIC.OCCURRENCE). A path that leaves the records of the type
|
|
1376
|
+
* gives the type back. A fact about a field also tells if the field exists. A value of a type without `undefined`
|
|
1377
|
+
* exists. An optional field without a remaining type does not.
|
|
1378
|
+
*
|
|
1379
|
+
* @param type - The type of the value at the first `at` keys of the path.
|
|
1380
|
+
* @param proof - The proof.
|
|
1381
|
+
* @param at - The number of keys of the path that the type already holds.
|
|
1382
|
+
* @param domains - The domains of the machine.
|
|
1383
|
+
* @returns The narrowed type.
|
|
1384
|
+
*/
|
|
1385
|
+
function narrowType(type, proof, at, domains) {
|
|
1386
|
+
if (at === proof.path.length) {
|
|
1387
|
+
if (proof.fact === "is") return meetOf(type, proof.type, domains);
|
|
1388
|
+
return proof.fact === "not" ? withoutOf(type, proof.type, domains) : type;
|
|
1389
|
+
}
|
|
1390
|
+
const form = formOf(type, domains);
|
|
1391
|
+
const key = proof.path[at];
|
|
1392
|
+
if (form.t !== "record" || !Object.hasOwn(form.fields, key)) return type;
|
|
1393
|
+
const before = form.fields[key];
|
|
1394
|
+
const optional = new Set(form.optional);
|
|
1395
|
+
let after = narrowType(before, proof, at + 1, domains);
|
|
1396
|
+
if (at + 1 === proof.path.length && optional.has(key)) {
|
|
1397
|
+
if (proof.fact === "present" || proof.fact === "is" && !member(void 0, proof.type, domains)) optional.delete(key);
|
|
1398
|
+
else if (proof.fact === "absent" || after === "never") after = void 0;
|
|
1399
|
+
}
|
|
1400
|
+
const fields = {};
|
|
1401
|
+
for (const name of Object.keys(form.fields)) if (name !== key) setOwn$6(fields, name, form.fields[name]);
|
|
1402
|
+
if (after !== void 0) setOwn$6(fields, key, after);
|
|
1403
|
+
else if (form.closed) optional.delete(key);
|
|
1404
|
+
else setOwn$6(fields, key, "never");
|
|
1405
|
+
return {
|
|
1406
|
+
record: fields,
|
|
1407
|
+
...optional.size === 0 ? {} : { optional: [...optional] },
|
|
1408
|
+
...form.closed ? { closed: true } : {}
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1356
1411
|
/**
|
|
1357
1412
|
* This function is the split rule of `fits` (TYPE.FITS-FINITE, D84, TYPE.FITS-PATH, D89). A record type fits when each
|
|
1358
1413
|
* record of its split fits. A split takes the first field in the order of `splitsOf`. Each member of the field gives a
|
|
@@ -1568,7 +1623,7 @@ const MAX_TEXT_VALUES = 8;
|
|
|
1568
1623
|
/** The most characters of one JSON value in the text of a type. */
|
|
1569
1624
|
const MAX_TEXT_VALUE = 40;
|
|
1570
1625
|
/** This function gives a short text of a JSON value for the text of a type. */
|
|
1571
|
-
function valueText$
|
|
1626
|
+
function valueText$2(value) {
|
|
1572
1627
|
let text;
|
|
1573
1628
|
try {
|
|
1574
1629
|
text = JSON.stringify(value) ?? String(value);
|
|
@@ -1590,7 +1645,7 @@ function textAt(type, depth, wrap) {
|
|
|
1590
1645
|
if (term === "one") {
|
|
1591
1646
|
if (!Array.isArray(type["one"])) return "unknown";
|
|
1592
1647
|
const values = type["one"];
|
|
1593
|
-
const shown = values.slice(0, MAX_TEXT_VALUES).map(valueText$
|
|
1648
|
+
const shown = values.slice(0, MAX_TEXT_VALUES).map(valueText$2);
|
|
1594
1649
|
return group(values.length > MAX_TEXT_VALUES ? [...shown, `… ${values.length - MAX_TEXT_VALUES} more`] : shown);
|
|
1595
1650
|
}
|
|
1596
1651
|
if (term === "fn") {
|
|
@@ -1882,6 +1937,12 @@ var MergeError = class extends Error {
|
|
|
1882
1937
|
}
|
|
1883
1938
|
};
|
|
1884
1939
|
const NONE$2 = /* @__PURE__ */ new Set();
|
|
1940
|
+
/** The verbs that the kernel reads. Thus no language owns them (COMPOSE.PIRACY). */
|
|
1941
|
+
const KERNEL_VERBS = /* @__PURE__ */ new Set([
|
|
1942
|
+
"eval",
|
|
1943
|
+
"deref",
|
|
1944
|
+
"step"
|
|
1945
|
+
]);
|
|
1885
1946
|
function keyOf(path) {
|
|
1886
1947
|
return JSON.stringify(path.map(String));
|
|
1887
1948
|
}
|
|
@@ -2072,16 +2133,123 @@ function mergeEntry(m, earlier, later, path, part, replaces) {
|
|
|
2072
2133
|
m.clash(path, part, a === b ? `Two parts give two different ${a === "an alias" ? "aliases" : "kinds"}.` : `One part gives ${a}, and the other part gives ${b}.`);
|
|
2073
2134
|
return earlier;
|
|
2074
2135
|
}
|
|
2075
|
-
function
|
|
2136
|
+
function worldDraft() {
|
|
2137
|
+
return {
|
|
2138
|
+
kinds: {},
|
|
2139
|
+
defaults: {},
|
|
2140
|
+
owners: /* @__PURE__ */ new Map(),
|
|
2141
|
+
entries: []
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* This function gives a copy of a table with a change to the kind at a path, as `replaces` names the path. It gives
|
|
2146
|
+
* `undefined` when no kind is at the path. An alias is not a kind.
|
|
2147
|
+
*/
|
|
2148
|
+
function changeKind(table, path, change) {
|
|
2149
|
+
const [first, key, ...rest] = path;
|
|
2150
|
+
if (String(first) === "fallback" && key === void 0) return table.fallback === void 0 ? void 0 : {
|
|
2151
|
+
...table,
|
|
2152
|
+
fallback: change(table.fallback)
|
|
2153
|
+
};
|
|
2154
|
+
if (String(first) !== "kinds" || key === void 0) return void 0;
|
|
2155
|
+
const entry = own$2(table.kinds, String(key));
|
|
2156
|
+
const next = rest.length === 0 ? isKind(entry) ? change(entry) : void 0 : isNamespace(entry) ? changeKind(entry, rest, change) : void 0;
|
|
2157
|
+
if (next === void 0) return void 0;
|
|
2158
|
+
const kinds = { ...table.kinds };
|
|
2159
|
+
setOwn$5(kinds, String(key), next);
|
|
2160
|
+
return {
|
|
2161
|
+
...table,
|
|
2162
|
+
kinds
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
/**
|
|
2166
|
+
* This function adds the entries of `extends` to the kinds of a draft. A later part can give the kind, thus this step
|
|
2167
|
+
* reads the whole draft. Without `m`, it reports no conflict: a function part sees the entries of the parts before it.
|
|
2168
|
+
*/
|
|
2169
|
+
function addVerbs(draft, m) {
|
|
2170
|
+
let table = draft.fallback === void 0 ? { kinds: draft.kinds } : {
|
|
2171
|
+
kinds: draft.kinds,
|
|
2172
|
+
fallback: draft.fallback
|
|
2173
|
+
};
|
|
2174
|
+
for (const entry of draft.entries) {
|
|
2175
|
+
if (!entry.allowed && !entry.replaced) {
|
|
2176
|
+
m?.clash(entry.path, entry.part, "A part adds a verb that it does not own to a kind that it does not give.");
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
const next = changeKind(table, entry.kind, (kind) => {
|
|
2180
|
+
const verbs = { ...kind.verbs };
|
|
2181
|
+
const earlier = own$2(verbs, entry.verb);
|
|
2182
|
+
if (earlier === void 0) m?.give(entry.path, entry.part);
|
|
2183
|
+
else if (entry.replaced) m?.replace(entry.path, entry.part);
|
|
2184
|
+
else if (earlier !== entry.code) m?.clash(entry.path, entry.part, "Two parts give two different evaluators for this verb of this kind.");
|
|
2185
|
+
if (earlier === void 0 || entry.replaced) setOwn$5(verbs, entry.verb, entry.code);
|
|
2186
|
+
return {
|
|
2187
|
+
...kind,
|
|
2188
|
+
verbs
|
|
2189
|
+
};
|
|
2190
|
+
});
|
|
2191
|
+
if (next !== void 0) table = next;
|
|
2192
|
+
else if (!entry.replaced) m?.clash(entry.path, entry.part, "A part adds a verb to a path without a kind.");
|
|
2193
|
+
}
|
|
2194
|
+
return table;
|
|
2195
|
+
}
|
|
2196
|
+
function worldOf(draft, m) {
|
|
2197
|
+
const table = addVerbs(draft, m);
|
|
2076
2198
|
const world = {
|
|
2077
|
-
kinds: { ...
|
|
2199
|
+
kinds: { ...table.kinds },
|
|
2078
2200
|
defaults: { ...draft.defaults }
|
|
2079
2201
|
};
|
|
2080
|
-
return
|
|
2202
|
+
return table.fallback === void 0 ? world : {
|
|
2081
2203
|
...world,
|
|
2082
|
-
fallback:
|
|
2204
|
+
fallback: table.fallback
|
|
2083
2205
|
};
|
|
2084
2206
|
}
|
|
2207
|
+
/** This function records the verbs that a part owns, and the entries that it adds to kinds. */
|
|
2208
|
+
function mergeVerbs(m, draft, part, index, replaces, base) {
|
|
2209
|
+
const owned = part.verbs ?? [];
|
|
2210
|
+
for (const verb of owned) {
|
|
2211
|
+
const path = [
|
|
2212
|
+
...base,
|
|
2213
|
+
"verbs",
|
|
2214
|
+
verb
|
|
2215
|
+
];
|
|
2216
|
+
const owner = draft.owners.get(verb);
|
|
2217
|
+
if (replaces.has(keyOf(path))) {
|
|
2218
|
+
draft.owners.set(verb, part);
|
|
2219
|
+
m.replace(path, index);
|
|
2220
|
+
} else if (KERNEL_VERBS.has(verb)) m.clash(path, index, "The kernel owns this verb.");
|
|
2221
|
+
else if (owner === void 0) {
|
|
2222
|
+
draft.owners.set(verb, part);
|
|
2223
|
+
m.give(path, index);
|
|
2224
|
+
} else if (!same(owner, part)) m.clash(path, index, "Two parts own this verb.");
|
|
2225
|
+
}
|
|
2226
|
+
const table = part.fallback === void 0 ? { kinds: part.kinds ?? {} } : {
|
|
2227
|
+
kinds: part.kinds ?? {},
|
|
2228
|
+
fallback: part.fallback
|
|
2229
|
+
};
|
|
2230
|
+
for (const { kind, verbs } of part.extends ?? []) {
|
|
2231
|
+
const gives = changeKind(table, kind, (found) => found) !== void 0;
|
|
2232
|
+
for (const verb of Object.keys(verbs)) {
|
|
2233
|
+
const code = verbs[verb];
|
|
2234
|
+
if (code === void 0) continue;
|
|
2235
|
+
const path = [
|
|
2236
|
+
...base,
|
|
2237
|
+
...kind,
|
|
2238
|
+
"verbs",
|
|
2239
|
+
verb
|
|
2240
|
+
];
|
|
2241
|
+
draft.entries.push({
|
|
2242
|
+
kind,
|
|
2243
|
+
verb,
|
|
2244
|
+
code,
|
|
2245
|
+
path,
|
|
2246
|
+
part: index,
|
|
2247
|
+
allowed: gives || owned.includes(verb),
|
|
2248
|
+
replaced: replaces.has(keyOf(path))
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2085
2253
|
function mergeWorldInto(m, draft, part, index, replaces, base) {
|
|
2086
2254
|
if (part === void 0) return;
|
|
2087
2255
|
if (part.kinds !== void 0) mergeEntries(m, draft.kinds, part.kinds, [...base, "kinds"], index, replaces);
|
|
@@ -2093,6 +2261,7 @@ function mergeWorldInto(m, draft, part, index, replaces, base) {
|
|
|
2093
2261
|
], index, replaces, Object.is, "Two parts give two different defaults for this verb.");
|
|
2094
2262
|
const fallback = mergeFallback(m, draft.fallback, part.fallback, [...base, "fallback"], index, replaces);
|
|
2095
2263
|
if (fallback !== void 0) draft.fallback = fallback;
|
|
2264
|
+
mergeVerbs(m, draft, part, index, replaces, base);
|
|
2096
2265
|
}
|
|
2097
2266
|
/**
|
|
2098
2267
|
* This function merges worlds into one world, in the order of the parts. It does not change a part.
|
|
@@ -2102,6 +2271,8 @@ function mergeWorldInto(m, draft, part, index, replaces, base) {
|
|
|
2102
2271
|
* - The defaults merge verb by verb, and the world keeps one fallback.
|
|
2103
2272
|
* - Each other pair of entries at one path is a conflict, unless the later part names the path in `replaces`.
|
|
2104
2273
|
* Then the later entry wins, with no merge below it.
|
|
2274
|
+
* - The entries of `extends` join their kinds after each part, thus the order of the parts does not change them. A
|
|
2275
|
+
* verb that a part does not own on a kind that it does not give is a conflict (COMPOSE.PIRACY).
|
|
2105
2276
|
*
|
|
2106
2277
|
* A part can be a function of the merge of the parts before it (`prev`, as an overlay of Nix). Thus a part can read
|
|
2107
2278
|
* the entry that it replaces.
|
|
@@ -2112,16 +2283,14 @@ function mergeWorldInto(m, draft, part, index, replaces, base) {
|
|
|
2112
2283
|
*/
|
|
2113
2284
|
function mergeWorlds(...parts) {
|
|
2114
2285
|
const m = new Merger();
|
|
2115
|
-
const draft =
|
|
2116
|
-
kinds: {},
|
|
2117
|
-
defaults: {}
|
|
2118
|
-
};
|
|
2286
|
+
const draft = worldDraft();
|
|
2119
2287
|
parts.forEach((input, index) => {
|
|
2120
2288
|
const part = typeof input === "function" ? input(worldOf(draft)) : input;
|
|
2121
2289
|
mergeWorldInto(m, draft, part, index, new Set((part.replaces ?? []).map(keyOf)), []);
|
|
2122
2290
|
});
|
|
2291
|
+
const world = worldOf(draft, m);
|
|
2123
2292
|
if (m.conflicts.length > 0) throw new MergeError(m.conflicts);
|
|
2124
|
-
return
|
|
2293
|
+
return world;
|
|
2125
2294
|
}
|
|
2126
2295
|
/** The fields of a machine that merge by their own rules. Each other field is one value, or a conflict. */
|
|
2127
2296
|
const TABLES = /* @__PURE__ */ new Set([
|
|
@@ -2174,12 +2343,12 @@ function composeFacts(hooks, replaced) {
|
|
|
2174
2343
|
}
|
|
2175
2344
|
};
|
|
2176
2345
|
}
|
|
2177
|
-
function machineOf(draft) {
|
|
2346
|
+
function machineOf(draft, m) {
|
|
2178
2347
|
const known = composeKnown(draft.hooks, draft.replaced);
|
|
2179
2348
|
const facts = composeFacts(draft.factHooks, draft.replaced);
|
|
2180
2349
|
return {
|
|
2181
2350
|
...draft.rest,
|
|
2182
|
-
world: worldOf(draft.world),
|
|
2351
|
+
world: worldOf(draft.world, m),
|
|
2183
2352
|
evaluators: { ...draft.evaluators },
|
|
2184
2353
|
...draft.runners === void 0 ? {} : { runners: { ...draft.runners } },
|
|
2185
2354
|
...draft.derefs === void 0 ? {} : { derefs: { ...draft.derefs } },
|
|
@@ -2253,10 +2422,7 @@ function checkHidden(m, draft) {
|
|
|
2253
2422
|
function mergeMachines(...parts) {
|
|
2254
2423
|
const m = new Merger();
|
|
2255
2424
|
const draft = {
|
|
2256
|
-
world:
|
|
2257
|
-
kinds: {},
|
|
2258
|
-
defaults: {}
|
|
2259
|
-
},
|
|
2425
|
+
world: worldDraft(),
|
|
2260
2426
|
evaluators: {},
|
|
2261
2427
|
hooks: [],
|
|
2262
2428
|
factHooks: [],
|
|
@@ -2297,8 +2463,9 @@ function mergeMachines(...parts) {
|
|
|
2297
2463
|
}
|
|
2298
2464
|
});
|
|
2299
2465
|
checkHidden(m, draft);
|
|
2466
|
+
const machine = machineOf(draft, m);
|
|
2300
2467
|
if (m.conflicts.length > 0) throw new MergeError(m.conflicts);
|
|
2301
|
-
return
|
|
2468
|
+
return machine;
|
|
2302
2469
|
}
|
|
2303
2470
|
/** This function removes the entry at a path from a table of entries. It gives the same table when no entry is there. */
|
|
2304
2471
|
function removeEntry(entries, path) {
|
|
@@ -4812,7 +4979,8 @@ function compileNode(c, value, place, declared, depth, address = false) {
|
|
|
4812
4979
|
} catch (error) {
|
|
4813
4980
|
return failingWith(c, meta, placed(thrown(error, `the runner ${name}`), place));
|
|
4814
4981
|
}
|
|
4815
|
-
const
|
|
4982
|
+
const guard = guardOf(c, place);
|
|
4983
|
+
const run = placedRun(guard === void 0 ? inner : guardRun(inner, guard, c.machine.domains), place, name);
|
|
4816
4984
|
return finish$1(c, meta, runnerCode(run, place, kindText), run);
|
|
4817
4985
|
}
|
|
4818
4986
|
let inner;
|
|
@@ -4821,7 +4989,8 @@ function compileNode(c, value, place, declared, depth, address = false) {
|
|
|
4821
4989
|
} catch (error) {
|
|
4822
4990
|
return failingWith(c, meta, placed(thrown(error, `the evaluator ${name}`), place));
|
|
4823
4991
|
}
|
|
4824
|
-
const
|
|
4992
|
+
const guard = guardOf(c, place);
|
|
4993
|
+
const done = finish$1(c, meta, guard !== void 0 ? placedCode(guardCode(inner, guard, c.machine.domains), place, name) : TOTAL.has(inner) ? inner : placedCode(inner, place, name), void 0);
|
|
4825
4994
|
if (frees === void 0 || kind === void 0 || !pureCode(c, envelope, kind, typePath, name, quick)) return done;
|
|
4826
4995
|
const free = freeOf(doc, kind, split.parts, frees);
|
|
4827
4996
|
if (free === void 0) return done;
|
|
@@ -5217,6 +5386,29 @@ function gated(rules, part) {
|
|
|
5217
5386
|
* This function gives the steps of a runner, with the place of each error and of each exception. The steps get the
|
|
5218
5387
|
* context that its grant permits (CAP.NARROW-CODE).
|
|
5219
5388
|
*/
|
|
5389
|
+
/** This function gives the key of a place in the guards of a plan. */
|
|
5390
|
+
function guardKey(place) {
|
|
5391
|
+
return JSON.stringify(place.map(String));
|
|
5392
|
+
}
|
|
5393
|
+
/** This function gives the type of the boundary at a place, when the plan has one (PLAN.GUARD). */
|
|
5394
|
+
function guardOf(c, place) {
|
|
5395
|
+
return c.guards?.get(guardKey(place));
|
|
5396
|
+
}
|
|
5397
|
+
/** This function gives the result of a part of a boundary: a value that is not a member gives `#VALUE!` (PLAN.GUARD). */
|
|
5398
|
+
function guarded(result, type, domains) {
|
|
5399
|
+
if (!result.ok || member(result.value, type, domains)) return result;
|
|
5400
|
+
return fail("#VALUE!", `The value is not a member of ${typeText(type)}, the type of its boundary.`);
|
|
5401
|
+
}
|
|
5402
|
+
/** This function adds the test of a boundary to the code of a part. */
|
|
5403
|
+
function guardCode(inner, type, domains) {
|
|
5404
|
+
return (ctx, rt) => guarded(inner(ctx, rt), type, domains);
|
|
5405
|
+
}
|
|
5406
|
+
/** This function adds the test of a boundary to the steps of a part. */
|
|
5407
|
+
function guardRun(inner, type, domains) {
|
|
5408
|
+
return function* (ctx, rt) {
|
|
5409
|
+
return guarded(yield* inner(ctx, rt), type, domains);
|
|
5410
|
+
};
|
|
5411
|
+
}
|
|
5220
5412
|
function placedRun(inner, place, name) {
|
|
5221
5413
|
return function* (ctx, rt) {
|
|
5222
5414
|
try {
|
|
@@ -5417,6 +5609,7 @@ function prepare(machine, doc, options = {}) {
|
|
|
5417
5609
|
const traced = options.trace === true;
|
|
5418
5610
|
const fold = !traced && options.fold !== false;
|
|
5419
5611
|
const fixed = fold ? fixedNamesOf(options.fixed?.names) : void 0;
|
|
5612
|
+
const guards = options.guards === void 0 || options.guards.length === 0 ? void 0 : new Map(options.guards.map((each) => [guardKey(each.place), each.type]));
|
|
5420
5613
|
const c = {
|
|
5421
5614
|
machine,
|
|
5422
5615
|
traced,
|
|
@@ -5424,7 +5617,8 @@ function prepare(machine, doc, options = {}) {
|
|
|
5424
5617
|
verb,
|
|
5425
5618
|
noAnswer,
|
|
5426
5619
|
fold,
|
|
5427
|
-
fixed
|
|
5620
|
+
fixed,
|
|
5621
|
+
guards
|
|
5428
5622
|
};
|
|
5429
5623
|
let root;
|
|
5430
5624
|
try {
|
|
@@ -5537,7 +5731,8 @@ function evaluate(machine, doc, context = makeContext(), options) {
|
|
|
5537
5731
|
const plan = prepare(machine, doc, {
|
|
5538
5732
|
trace: true,
|
|
5539
5733
|
...declaredType === void 0 ? {} : { declaredType },
|
|
5540
|
-
...given.verb === void 0 ? {} : { verb: given.verb }
|
|
5734
|
+
...given.verb === void 0 ? {} : { verb: given.verb },
|
|
5735
|
+
...given.guards === void 0 ? {} : { guards: given.guards }
|
|
5541
5736
|
});
|
|
5542
5737
|
const ctx = rootContext(machine, context);
|
|
5543
5738
|
const s = new Session(machine, ctx.caps, false, true, given.perform, void 0, void 0, readingOf(given.reads, ctx));
|
|
@@ -5558,6 +5753,7 @@ async function run(machine, doc, context = makeContext(), options = {}) {
|
|
|
5558
5753
|
const plan = prepare(machine, doc, {
|
|
5559
5754
|
trace: true,
|
|
5560
5755
|
...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
|
|
5756
|
+
...options.guards === void 0 ? {} : { guards: options.guards },
|
|
5561
5757
|
...options.verb === void 0 ? {} : { verb: options.verb }
|
|
5562
5758
|
});
|
|
5563
5759
|
const ctx = rootContext(machine, context);
|
|
@@ -5928,7 +6124,8 @@ const STD_WORLD = {
|
|
|
5928
6124
|
* A literal in a place that takes a document gets its data envelope (K159, D65). Such a place is a part of `if`,
|
|
5929
6125
|
* `list`, `seq` or `pure`, the value of `write`, or the whole text. The document after a header name is such a place
|
|
5930
6126
|
* too. Thus `list(1, "a")` evaluates to `[1, "a"]`. The forms `add`, `multiply` and `greater` write an operator document that its operator
|
|
5931
|
-
* does not write, for example `add(5)` (K163).
|
|
6127
|
+
* does not write, for example `add(5)` (K163). The field `with` of `handle` is a field of data, thus each clause is a
|
|
6128
|
+
* record between braces in a list between brackets (D177).
|
|
5932
6129
|
*
|
|
5933
6130
|
* A host with more kinds spreads this profile and adds its forms to `calls.forms`. `STD_SYNTAX` stays the profile of
|
|
5934
6131
|
* the formula kit.
|
|
@@ -6068,6 +6265,18 @@ const WORLD_SYNTAX = /* @__PURE__ */ Object.freeze({
|
|
|
6068
6265
|
kind: "tree.quote",
|
|
6069
6266
|
args: "literal"
|
|
6070
6267
|
},
|
|
6268
|
+
{
|
|
6269
|
+
name: "handle",
|
|
6270
|
+
kind: "handle",
|
|
6271
|
+
args: "named",
|
|
6272
|
+
fields: [
|
|
6273
|
+
"with",
|
|
6274
|
+
"return",
|
|
6275
|
+
"body"
|
|
6276
|
+
],
|
|
6277
|
+
data: ["with"],
|
|
6278
|
+
wrap: ["return", "body"]
|
|
6279
|
+
},
|
|
6071
6280
|
{
|
|
6072
6281
|
name: "add",
|
|
6073
6282
|
kind: "add"
|
|
@@ -6135,11 +6344,17 @@ const STD_EVALUATORS = {
|
|
|
6135
6344
|
const [a, b] = values;
|
|
6136
6345
|
return ok((a ?? 0) > (b ?? 0));
|
|
6137
6346
|
},
|
|
6138
|
-
"ref.resolve": ({ data,
|
|
6139
|
-
if (!Array.isArray(data) || data.length === 0)
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6347
|
+
"ref.resolve": { compile: ({ data, machine }) => {
|
|
6348
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
6349
|
+
const bad = fail("#VALUE!", "The value of ref is a path: a list that starts with a root, for example [\"names\", \"a\"].");
|
|
6350
|
+
return () => bad;
|
|
6351
|
+
}
|
|
6352
|
+
const path = compilePath(machine, data);
|
|
6353
|
+
return (ctx, rt) => {
|
|
6354
|
+
const found = resolveCompiled(rt, ctx, path);
|
|
6355
|
+
return found.ok ? ok(valueOfThing(found.thing)) : fail(found.code, found.reason);
|
|
6356
|
+
};
|
|
6357
|
+
} },
|
|
6143
6358
|
"tree.node": (input) => treeNode(input, void 0)
|
|
6144
6359
|
};
|
|
6145
6360
|
/** The brand of a node of the decorated tree. Its value is the state that the kit reads. */
|
|
@@ -6524,6 +6739,7 @@ function leaderOnHost(n, key, rule, host) {
|
|
|
6524
6739
|
/**
|
|
6525
6740
|
* This function gives an attribute of a node with circular attributes, or an attribute in an open fixed point (D113).
|
|
6526
6741
|
* The memo and the marks of the node do not hold the attribute. An open fixed point does not use the cells of the host.
|
|
6742
|
+
* With the cells of a host, only a circular attribute comes here outside a fixed point. A plain attribute takes its cell.
|
|
6527
6743
|
*/
|
|
6528
6744
|
function circularRead(n, key) {
|
|
6529
6745
|
const rule = circularRule(n.tree, key);
|
|
@@ -6938,7 +7154,7 @@ function treeThing(input, place, build, outer, host) {
|
|
|
6938
7154
|
const text = attributeText(key, type, place);
|
|
6939
7155
|
if (marks.has(key)) return busyAt(state, key);
|
|
6940
7156
|
if (tree === void 0 && up?.tree === void 0 && !parts.some((item) => item.key === key)) return void 0;
|
|
6941
|
-
if (
|
|
7157
|
+
if (openPoint !== void 0 || circular && circularRule(tree, key) !== void 0) return circularRead(state, key);
|
|
6942
7158
|
marks.set(key, BUSY);
|
|
6943
7159
|
demands.push({
|
|
6944
7160
|
cells: marks,
|
|
@@ -7270,6 +7486,26 @@ function isOp(value) {
|
|
|
7270
7486
|
return typeof value === "string" || Array.isArray(value) && value.every(isKey);
|
|
7271
7487
|
}
|
|
7272
7488
|
/**
|
|
7489
|
+
* This function gives the runner of an `if` with its own truth (RUN.IF-TRUTH). A branch can wait for the host, thus a
|
|
7490
|
+
* language with the function `truthy` of a profile does not need a copy of `if`. A missing test and a test without a
|
|
7491
|
+
* truth give `#VALUE!`, a failed test gives its failure, and a missing branch gives `null`.
|
|
7492
|
+
*
|
|
7493
|
+
* @param truth - The function that gives the truth of a value, or `undefined` for a value without a truth.
|
|
7494
|
+
* @returns The runner.
|
|
7495
|
+
*/
|
|
7496
|
+
function ifRunner(truth) {
|
|
7497
|
+
return function* ({ parts }) {
|
|
7498
|
+
const test = parts.find((part) => part.key === "test");
|
|
7499
|
+
if (test === void 0) return fail("#VALUE!", "if needs a test.");
|
|
7500
|
+
const chosen = yield* test.evaluate();
|
|
7501
|
+
if (!chosen.ok) return chosen;
|
|
7502
|
+
const held = truth(chosen.value);
|
|
7503
|
+
if (held === void 0) return fail("#VALUE!", "The test of if must give a truth value.");
|
|
7504
|
+
const branch = parts.find((part) => part.key === (held ? "then" : "else"));
|
|
7505
|
+
return branch === void 0 ? ok(null) : yield* branch.evaluate();
|
|
7506
|
+
};
|
|
7507
|
+
}
|
|
7508
|
+
/**
|
|
7273
7509
|
* The runners of the standard world, by name: the kinds that can hold effects. Each one evaluates its parts in
|
|
7274
7510
|
* order. In a run, an effect ends before the next step starts.
|
|
7275
7511
|
*/
|
|
@@ -7337,15 +7573,7 @@ const STD_RUNNERS = {
|
|
|
7337
7573
|
}
|
|
7338
7574
|
});
|
|
7339
7575
|
},
|
|
7340
|
-
"control.if":
|
|
7341
|
-
const test = parts.find((part) => part.key === "test");
|
|
7342
|
-
if (test === void 0) return fail("#VALUE!", "if needs a test.");
|
|
7343
|
-
const chosen = yield* test.evaluate();
|
|
7344
|
-
if (!chosen.ok) return chosen;
|
|
7345
|
-
if (typeof chosen.value !== "boolean") return fail("#VALUE!", "The test of if must give a truth value.");
|
|
7346
|
-
const branch = parts.find((part) => part.key === (chosen.value === true ? "then" : "else"));
|
|
7347
|
-
return branch === void 0 ? ok(null) : yield* branch.evaluate();
|
|
7348
|
-
},
|
|
7576
|
+
"control.if": /* @__PURE__ */ ifRunner((value) => typeof value === "boolean" ? value : void 0),
|
|
7349
7577
|
"list.all": function* ({ parts }) {
|
|
7350
7578
|
const all = yield* inOrder(parts);
|
|
7351
7579
|
return "error" in all ? all.error : ok(all.values);
|
|
@@ -7768,6 +7996,31 @@ const CONSTRUCTS = [
|
|
|
7768
7996
|
* narrows the capabilities for each part, thus the host does not give this type.
|
|
7769
7997
|
*/
|
|
7770
7998
|
const CAPS_TYPE = { list: { union: ["text", { list: { union: ["text", "number"] } }] } };
|
|
7999
|
+
/**
|
|
8000
|
+
* This function gives the boundaries of a check. A part with an imprecise type at a position that needs a type is a
|
|
8001
|
+
* boundary. A read of a known type is a boundary too, because the check trusts the root types (PLAN.GUARD-BOUNDARY).
|
|
8002
|
+
*
|
|
8003
|
+
* @param typing - The places of a check of types.
|
|
8004
|
+
* @param domains - The domains of the machine.
|
|
8005
|
+
* @returns The boundaries, in the order of the document.
|
|
8006
|
+
*/
|
|
8007
|
+
function boundariesOf(typing, domains) {
|
|
8008
|
+
const found = [];
|
|
8009
|
+
for (const item of typing.places) if (item.expected !== void 0 && item.expected !== "unknown" && !isPrecise(item.type, domains)) found.push({
|
|
8010
|
+
place: item.place,
|
|
8011
|
+
type: item.expected
|
|
8012
|
+
});
|
|
8013
|
+
else if (item.read === true && item.type !== "unknown") found.push({
|
|
8014
|
+
place: item.place,
|
|
8015
|
+
type: item.type
|
|
8016
|
+
});
|
|
8017
|
+
return found;
|
|
8018
|
+
}
|
|
8019
|
+
/** The result of a test that proves nothing. */
|
|
8020
|
+
const NO_PROOFS$1 = {
|
|
8021
|
+
yes: [],
|
|
8022
|
+
no: []
|
|
8023
|
+
};
|
|
7771
8024
|
/** The roots that can change, as a rule gives them in `PartType.roots`. */
|
|
7772
8025
|
const CHANGING = [
|
|
7773
8026
|
"self",
|
|
@@ -7787,11 +8040,15 @@ function pathKey(path) {
|
|
|
7787
8040
|
function ruleOf(machine, name) {
|
|
7788
8041
|
if (name === void 0 || machine.runners !== void 0 && Object.hasOwn(machine.runners, name)) return void 0;
|
|
7789
8042
|
const evaluator = Object.hasOwn(machine.evaluators, name) ? machine.evaluators[name] : void 0;
|
|
7790
|
-
const rule = typeof evaluator === "object" && evaluator !== null ? evaluator.type : void 0;
|
|
8043
|
+
const rule = typeof evaluator === "object" && evaluator !== null || typeof evaluator === "function" ? evaluator.type : void 0;
|
|
7791
8044
|
return typeof rule === "object" && rule !== null && typeof rule.synth === "function" ? rule : void 0;
|
|
7792
8045
|
}
|
|
7793
|
-
/** This function gives the order of the parts of a document
|
|
7794
|
-
function orderOf(node, nodes) {
|
|
8046
|
+
/** This function gives the order of the parts of a document. The part `first` of the rule comes first, or else the parts that give the names of a rule `keysAt`. */
|
|
8047
|
+
function orderOf(node, nodes, first) {
|
|
8048
|
+
if (first !== void 0) {
|
|
8049
|
+
const isFirst = (index) => String(nodes[index].visit.slot[0]) === first;
|
|
8050
|
+
return [...node.children.filter(isFirst), ...node.children.filter((index) => !isFirst(index))];
|
|
8051
|
+
}
|
|
7795
8052
|
const sources = (node.visit.kind?.scope ?? []).flatMap((rule) => "keysAt" in rule.names ? [rule.names.keysAt] : []);
|
|
7796
8053
|
if (sources.length === 0 || node.children.length < 2) return node.children;
|
|
7797
8054
|
const gives = (index) => {
|
|
@@ -7815,7 +8072,7 @@ function message(error) {
|
|
|
7815
8072
|
* @param rootTypes - The types of the roots and of the names of the host.
|
|
7816
8073
|
* @returns The type of the root, the type issues in the order of the document, and the type of each document.
|
|
7817
8074
|
*/
|
|
7818
|
-
function typePass(machine, nodes, verb, expect, rootTypes = {}) {
|
|
8075
|
+
function typePass(machine, nodes, verb, expect, rootTypes = {}, hasEffect = () => false) {
|
|
7819
8076
|
if (nodes.length === 0) return {
|
|
7820
8077
|
type: "unknown",
|
|
7821
8078
|
issues: [],
|
|
@@ -7827,6 +8084,29 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
|
|
|
7827
8084
|
const types = new Array(nodes.length);
|
|
7828
8085
|
const needed = new Array(nodes.length);
|
|
7829
8086
|
const seen = /* @__PURE__ */ new Set();
|
|
8087
|
+
const inputs = new Array(nodes.length);
|
|
8088
|
+
let changes;
|
|
8089
|
+
const rootsChange = () => changes ??= nodes.some(hasEffect);
|
|
8090
|
+
const narrowed = (names, roots, proofs) => {
|
|
8091
|
+
let nextNames = names;
|
|
8092
|
+
let nextRoots = roots;
|
|
8093
|
+
for (const proof of proofs) {
|
|
8094
|
+
const head = proof.path[0];
|
|
8095
|
+
if (head === "names") {
|
|
8096
|
+
const name = proof.path[1];
|
|
8097
|
+
if (name === void 0) continue;
|
|
8098
|
+
if (nextNames === names) nextNames = new Map(names);
|
|
8099
|
+
nextNames.set(name, narrowType(nextNames.get(name) ?? "unknown", proof, 2, domains));
|
|
8100
|
+
} else if ((head === "self" || head === "world" || head === "event") && !rootsChange()) nextRoots = {
|
|
8101
|
+
...nextRoots,
|
|
8102
|
+
[head]: narrowType(nextRoots[head], proof, 1, domains)
|
|
8103
|
+
};
|
|
8104
|
+
}
|
|
8105
|
+
return {
|
|
8106
|
+
names: nextNames,
|
|
8107
|
+
roots: nextRoots
|
|
8108
|
+
};
|
|
8109
|
+
};
|
|
7830
8110
|
const issueAt = (index, problem) => {
|
|
7831
8111
|
const visit = nodes[index].visit;
|
|
7832
8112
|
const issue = {
|
|
@@ -7864,19 +8144,30 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
|
|
|
7864
8144
|
typeOf: (path) => typed.get(pathKey(path)) ?? "unknown",
|
|
7865
8145
|
nameType: (name) => names.get(name),
|
|
7866
8146
|
rootType: (root) => root === "caps" ? CAPS_TYPE : root === "self" || root === "world" || root === "event" ? roots[root] : "unknown",
|
|
7867
|
-
contract: (type, what) => contract(index, type, what)
|
|
8147
|
+
contract: (type, what) => contract(index, type, what),
|
|
8148
|
+
readOf: (path) => {
|
|
8149
|
+
const key = pathKey(path);
|
|
8150
|
+
const part = node.children.find((child) => pathKey(nodes[child].visit.slot) === key);
|
|
8151
|
+
const read = part === void 0 ? void 0 : ruleOf(machine, nodes[part].evaluator)?.reads;
|
|
8152
|
+
return read === void 0 || nodes[part].marked ? void 0 : read(inputs[part]);
|
|
8153
|
+
},
|
|
8154
|
+
provenBy: (path) => frame.proven?.get(pathKey(path)) ?? NO_PROOFS$1
|
|
7868
8155
|
};
|
|
7869
|
-
|
|
8156
|
+
inputs[index] = input;
|
|
8157
|
+
const rule = node.marked ? void 0 : ruleOf(machine, node.evaluator);
|
|
8158
|
+
const frame = {
|
|
7870
8159
|
index,
|
|
7871
|
-
rule
|
|
8160
|
+
rule,
|
|
7872
8161
|
input,
|
|
7873
|
-
order: orderOf(node, nodes),
|
|
8162
|
+
order: orderOf(node, nodes, rule?.first),
|
|
7874
8163
|
next: 0,
|
|
7875
8164
|
typed,
|
|
7876
8165
|
needs,
|
|
7877
8166
|
names,
|
|
7878
|
-
roots
|
|
8167
|
+
roots,
|
|
8168
|
+
proven: void 0
|
|
7879
8169
|
};
|
|
8170
|
+
return frame;
|
|
7880
8171
|
};
|
|
7881
8172
|
const ruleFailed = (frame, error) => {
|
|
7882
8173
|
issueAt(frame.index, { reason: `The type rule of ${nodes[frame.index].evaluator ?? "the evaluator"} fails: ${message(error)}` });
|
|
@@ -7924,12 +8215,22 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
|
|
|
7924
8215
|
if (contracts && node.expect !== void 0) need(contract(child, node.expect, `expected type of the ${what}`), what);
|
|
7925
8216
|
if (part.expect !== void 0) need(part.expect, part.what ?? what);
|
|
7926
8217
|
let names = frame.names;
|
|
8218
|
+
let kept = frame.roots;
|
|
8219
|
+
if (part.narrow !== void 0 && part.narrow.length > 0) {
|
|
8220
|
+
const after = narrowed(names, kept, part.narrow);
|
|
8221
|
+
names = after.names;
|
|
8222
|
+
kept = after.roots;
|
|
8223
|
+
if (part.keep === true) {
|
|
8224
|
+
frame.names = names;
|
|
8225
|
+
frame.roots = kept;
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
7927
8228
|
if (node.bound.length > 0) {
|
|
7928
8229
|
const copy = new Map(names);
|
|
7929
8230
|
for (const name of node.bound) copy.set(name, part.names !== void 0 && Object.hasOwn(part.names, name) ? part.names[name] : "unknown");
|
|
7930
8231
|
names = copy;
|
|
7931
8232
|
}
|
|
7932
|
-
let roots = frame.rule === void 0 ? UNKNOWN_ROOTS :
|
|
8233
|
+
let roots = frame.rule === void 0 ? UNKNOWN_ROOTS : kept;
|
|
7933
8234
|
const changes = part.roots;
|
|
7934
8235
|
if (typeof changes === "object" && changes !== null) {
|
|
7935
8236
|
const copy = { ...roots };
|
|
@@ -7964,13 +8265,23 @@ function typePass(machine, nodes, verb, expect, rootTypes = {}) {
|
|
|
7964
8265
|
}
|
|
7965
8266
|
types[frame.index] = type;
|
|
7966
8267
|
needed[frame.index] = frame.needs.length === 0 ? void 0 : frame.needs[frame.needs.length - 1].type;
|
|
7967
|
-
stack[stack.length - 1]
|
|
8268
|
+
const parent = stack[stack.length - 1];
|
|
8269
|
+
if (parent === void 0) continue;
|
|
8270
|
+
const key = pathKey(node.visit.slot);
|
|
8271
|
+
parent.typed.set(key, type);
|
|
8272
|
+
if (parent.rule?.usesProofs === true && frame.rule?.proves !== void 0) try {
|
|
8273
|
+
(parent.proven ??= /* @__PURE__ */ new Map()).set(key, frame.rule.proves(frame.input));
|
|
8274
|
+
} catch (error) {
|
|
8275
|
+
ruleFailed(frame, error);
|
|
8276
|
+
}
|
|
7968
8277
|
}
|
|
7969
8278
|
const places = nodes.map((node, index) => {
|
|
7970
8279
|
const want = needed[index];
|
|
8280
|
+
const read = !node.marked && ruleOf(machine, node.evaluator)?.read === true;
|
|
7971
8281
|
const entry = {
|
|
7972
8282
|
type: types[index] ?? "unknown",
|
|
7973
|
-
...want === void 0 ? {} : { expected: want }
|
|
8283
|
+
...want === void 0 ? {} : { expected: want },
|
|
8284
|
+
...read ? { read } : {}
|
|
7974
8285
|
};
|
|
7975
8286
|
Object.defineProperty(entry, "place", {
|
|
7976
8287
|
enumerable: true,
|
|
@@ -9482,11 +9793,13 @@ function walk(world, doc, visit, options = {}) {
|
|
|
9482
9793
|
continue;
|
|
9483
9794
|
}
|
|
9484
9795
|
const { sees, later } = scopesOf(kind.scope, doc.value, split.parts);
|
|
9796
|
+
const grantRules = kind.caps !== void 0 && kind.caps.some((rule) => rule.rule === "grant") ? kind.caps : void 0;
|
|
9485
9797
|
for (let index = split.parts.length - 1; index >= 0; index -= 1) {
|
|
9486
9798
|
const slot = split.parts[index];
|
|
9487
9799
|
const extra = sees[index] ?? [];
|
|
9488
9800
|
const hidden = later[index] ?? [];
|
|
9489
|
-
const grants = partGrants(
|
|
9801
|
+
const grants = grantRules === void 0 ? void 0 : partGrants(grantRules, slot.path, doc.value);
|
|
9802
|
+
const granted = grants !== void 0 && grants.length > 0 ? grants : void 0;
|
|
9490
9803
|
stack.push({
|
|
9491
9804
|
value: slot.item,
|
|
9492
9805
|
place: slot.path.length === 0 ? item.place : {
|
|
@@ -9504,8 +9817,8 @@ function walk(world, doc, visit, options = {}) {
|
|
|
9504
9817
|
address: slot.address === true,
|
|
9505
9818
|
slot: slot.path,
|
|
9506
9819
|
parent: here,
|
|
9507
|
-
caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : [...partCaps(kind.caps, slot.path, item.caps), ...
|
|
9508
|
-
handled:
|
|
9820
|
+
caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : granted === void 0 ? partCaps(kind.caps, slot.path, item.caps) : [...partCaps(kind.caps, slot.path, item.caps), ...granted],
|
|
9821
|
+
handled: granted === void 0 ? item.handled : [...item.handled ?? [], ...granted],
|
|
9509
9822
|
bound: extra,
|
|
9510
9823
|
expect: slot.expect
|
|
9511
9824
|
});
|
|
@@ -9595,6 +9908,28 @@ function mapRefs(world, doc, change, options = {}) {
|
|
|
9595
9908
|
return out;
|
|
9596
9909
|
}
|
|
9597
9910
|
/**
|
|
9911
|
+
* This function changes the documents of a document, from the root to the parts (STATIC.MAPDOCS). The function
|
|
9912
|
+
* `change` reads only the original documents. It decides at each node, and it can stop at a node. The kinds of a
|
|
9913
|
+
* position come from the world, thus this function names no kind. The document is not changed: the function gives a
|
|
9914
|
+
* new document that shares each part without a change.
|
|
9915
|
+
*
|
|
9916
|
+
* @param world - The world of the kinds.
|
|
9917
|
+
* @param doc - The document, as JSON.
|
|
9918
|
+
* @param change - The function that gives the answer for each visit. See `DocChange`.
|
|
9919
|
+
* @param options - The type of a bare root value, and the names that the host binds at the root.
|
|
9920
|
+
* @returns The new document, or `doc` itself when no document changes.
|
|
9921
|
+
*/
|
|
9922
|
+
function mapDocs(world, doc, change, options = {}) {
|
|
9923
|
+
let out = doc;
|
|
9924
|
+
walk(world, doc, (visit) => {
|
|
9925
|
+
const next = change(visit);
|
|
9926
|
+
if (next === void 0 || next === "skip") return next;
|
|
9927
|
+
out = setAt(out, visit.at, next.to);
|
|
9928
|
+
return next.into === true ? void 0 : "skip";
|
|
9929
|
+
}, options);
|
|
9930
|
+
return out;
|
|
9931
|
+
}
|
|
9932
|
+
/**
|
|
9598
9933
|
* This function gives the parts that the code of a runner evaluates itself, without a wait (RUN.DRIVES, D119). The
|
|
9599
9934
|
* answer of the hook `facts` for the code wins over the contract. The contract describes only the code of its kind for
|
|
9600
9935
|
* `eval`. Without a declaration, the runner passes each wait of its parts through.
|
|
@@ -9737,7 +10072,8 @@ function check(machine, doc, options = {}) {
|
|
|
9737
10072
|
function typeCheck(machine, doc, options = {}) {
|
|
9738
10073
|
const nodes = [];
|
|
9739
10074
|
const issues = checkAll(machine, doc, options, nodes);
|
|
9740
|
-
const
|
|
10075
|
+
const verb = options.verb ?? "eval";
|
|
10076
|
+
const pass = typePass(machine, nodes, verb, options.expect, options.rootTypes, (node) => declaredEffects(node.visit, verb, machine, node.evaluator).length > 0);
|
|
9741
10077
|
return {
|
|
9742
10078
|
type: pass.type,
|
|
9743
10079
|
issues: pass.issues.length === 0 ? issues : [...issues, ...pass.issues],
|
|
@@ -10742,6 +11078,13 @@ function decodeValue(machine, doc) {
|
|
|
10742
11078
|
return prepare(machine, doc, { declaredType: "lit" }).evaluate(makeContext());
|
|
10743
11079
|
}
|
|
10744
11080
|
// src/formula.ts
|
|
11081
|
+
/** The most proofs that one test keeps. A proof only adds knowledge, thus the check can leave one out. */
|
|
11082
|
+
const MAX_PROOFS = 32;
|
|
11083
|
+
/** The result of a test that proves nothing. */
|
|
11084
|
+
const NO_PROOFS = {
|
|
11085
|
+
yes: [],
|
|
11086
|
+
no: []
|
|
11087
|
+
};
|
|
10745
11088
|
/** The mark of a field that the profile leaves out of a record. */
|
|
10746
11089
|
const SKIPPED = /* @__PURE__ */ Symbol("skipped");
|
|
10747
11090
|
/** The value of a name whose binding failed. A reference to the name gives the error. */
|
|
@@ -11142,6 +11485,11 @@ function formulaTypes(profile) {
|
|
|
11142
11485
|
type: sig.to,
|
|
11143
11486
|
what: `result of a signature of ops.${name}`
|
|
11144
11487
|
});
|
|
11488
|
+
if (sig.proves !== void 0) out.push({
|
|
11489
|
+
at: [...at, "proves"],
|
|
11490
|
+
type: sig.proves,
|
|
11491
|
+
what: `proved type of a signature of ops.${name}`
|
|
11492
|
+
});
|
|
11145
11493
|
const earlier = list.slice(0, index).findIndex((other) => isSignature(other) && sameParams(other, sig));
|
|
11146
11494
|
if (earlier >= 0) out.push({
|
|
11147
11495
|
at,
|
|
@@ -11152,7 +11500,30 @@ function formulaTypes(profile) {
|
|
|
11152
11500
|
return out;
|
|
11153
11501
|
};
|
|
11154
11502
|
const logic = (word) => ({
|
|
11155
|
-
|
|
11503
|
+
usesProofs: true,
|
|
11504
|
+
part: (input, path) => {
|
|
11505
|
+
const index = Number(path[0]);
|
|
11506
|
+
const part = truthPart(input, `term ${index + 1} of ${word}`);
|
|
11507
|
+
if (index === 0) return part;
|
|
11508
|
+
const before = input.provenBy([index - 1]);
|
|
11509
|
+
return {
|
|
11510
|
+
...part,
|
|
11511
|
+
narrow: word === "and" ? before.yes : before.no,
|
|
11512
|
+
keep: true
|
|
11513
|
+
};
|
|
11514
|
+
},
|
|
11515
|
+
proves: (input) => {
|
|
11516
|
+
const each = input.paths.map((path) => input.provenBy(path));
|
|
11517
|
+
const all = (side) => each.flatMap((proven) => proven[side]).slice(0, MAX_PROOFS);
|
|
11518
|
+
const one = each.length === 1 ? each[0] : void 0;
|
|
11519
|
+
return word === "and" ? {
|
|
11520
|
+
yes: all("yes"),
|
|
11521
|
+
no: one?.no ?? []
|
|
11522
|
+
} : {
|
|
11523
|
+
yes: one?.yes ?? [],
|
|
11524
|
+
no: all("no")
|
|
11525
|
+
};
|
|
11526
|
+
},
|
|
11156
11527
|
synth: (input) => {
|
|
11157
11528
|
if (!logicValue) return "bool";
|
|
11158
11529
|
if (input.paths.length === 0) return { one: [word === "and"] };
|
|
@@ -11161,39 +11532,47 @@ function formulaTypes(profile) {
|
|
|
11161
11532
|
});
|
|
11162
11533
|
return {
|
|
11163
11534
|
"formula.lit": { synth: (input) => valueType(input.doc.value) },
|
|
11164
|
-
"formula.ref": {
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
const
|
|
11173
|
-
if (!
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
continue;
|
|
11535
|
+
"formula.ref": {
|
|
11536
|
+
read: true,
|
|
11537
|
+
reads: (input) => {
|
|
11538
|
+
const path = input.doc.value;
|
|
11539
|
+
if (input.address || !Array.isArray(path) || path.length === 0) return void 0;
|
|
11540
|
+
return path.every((step) => typeof step === "string") ? path : void 0;
|
|
11541
|
+
},
|
|
11542
|
+
synth: (input, report) => {
|
|
11543
|
+
const path = input.doc.value;
|
|
11544
|
+
if (input.address || !Array.isArray(path) || path.length === 0) return "unknown";
|
|
11545
|
+
const domains = input.machine.domains;
|
|
11546
|
+
const plain = input.machine.plain === true;
|
|
11547
|
+
let type;
|
|
11548
|
+
let start;
|
|
11549
|
+
if (path[0] === "names") {
|
|
11550
|
+
const name = path[1];
|
|
11551
|
+
if (!isKey(name) || !plain && HEADER_KEYS.has(String(name))) return "unknown";
|
|
11552
|
+
type = input.nameType(String(name)) ?? "unknown";
|
|
11553
|
+
start = 2;
|
|
11554
|
+
} else {
|
|
11555
|
+
type = input.rootType(String(path[0]));
|
|
11556
|
+
start = 1;
|
|
11187
11557
|
}
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11558
|
+
for (let index = start;; index += 1) {
|
|
11559
|
+
if (isUnknown(type, domains) || !plain && holdsEnvelope(type, domains)) return "unknown";
|
|
11560
|
+
if (index >= path.length) return type;
|
|
11561
|
+
const step = path[index];
|
|
11562
|
+
if (!isKey(step)) {
|
|
11563
|
+
type = walkType(input, step, type);
|
|
11564
|
+
continue;
|
|
11565
|
+
}
|
|
11566
|
+
const next = stepType(type, step, domains, input.contract);
|
|
11567
|
+
if ("missing" in next) {
|
|
11568
|
+
const fields = next.missing.length === 0 ? "" : ` Its fields are ${listText(next.missing)}.`;
|
|
11569
|
+
report({ reason: `The value at ${path.slice(0, index).map(stepText).join(".")} has no field ${String(step)}.${fields}` });
|
|
11570
|
+
return "unknown";
|
|
11571
|
+
}
|
|
11572
|
+
type = next.type;
|
|
11193
11573
|
}
|
|
11194
|
-
type = next.type;
|
|
11195
11574
|
}
|
|
11196
|
-
}
|
|
11575
|
+
},
|
|
11197
11576
|
"formula.record": {
|
|
11198
11577
|
part: (input, path) => {
|
|
11199
11578
|
const want = fieldOf(input.expected, String(path[0]), input.machine.domains);
|
|
@@ -11303,11 +11682,16 @@ function formulaTypes(profile) {
|
|
|
11303
11682
|
type: truth,
|
|
11304
11683
|
what: "truth type of the profile"
|
|
11305
11684
|
}] : [],
|
|
11685
|
+
first: "test",
|
|
11686
|
+
usesProofs: true,
|
|
11306
11687
|
part: (input, path) => {
|
|
11307
11688
|
if (path[0] === "test") return truthPart(input, "test of if");
|
|
11308
|
-
|
|
11689
|
+
const proven = input.provenBy(["test"]);
|
|
11690
|
+
const narrow = path[0] === "then" ? proven.yes : proven.no;
|
|
11691
|
+
return isUnknown(input.expected, input.machine.domains) ? { narrow } : {
|
|
11309
11692
|
expect: input.expected,
|
|
11310
|
-
what: `${String(path[0])} branch of if
|
|
11693
|
+
what: `${String(path[0])} branch of if`,
|
|
11694
|
+
narrow
|
|
11311
11695
|
};
|
|
11312
11696
|
},
|
|
11313
11697
|
synth: (input) => {
|
|
@@ -11320,6 +11704,41 @@ function formulaTypes(profile) {
|
|
|
11320
11704
|
"formula.or": logic("or"),
|
|
11321
11705
|
"formula.op": {
|
|
11322
11706
|
declared: sigsDeclared,
|
|
11707
|
+
proves: (input) => {
|
|
11708
|
+
const sigs = signatures(input)?.sigs;
|
|
11709
|
+
const sig = sigs?.length === 1 ? sigs[0] : void 0;
|
|
11710
|
+
if (sig === void 0 || sig.proves === void 0 && sig.present !== true || input.paths.length === 0) return NO_PROOFS;
|
|
11711
|
+
const path = input.readOf(input.paths[0]);
|
|
11712
|
+
if (path === void 0) return NO_PROOFS;
|
|
11713
|
+
const yes = [];
|
|
11714
|
+
const no = [];
|
|
11715
|
+
if (sig.proves !== void 0 && typeIssues(input.contract(sig.proves, `proved type of ops.${nameOf(input)}`), input.machine.domains).length === 0) {
|
|
11716
|
+
yes.push({
|
|
11717
|
+
path,
|
|
11718
|
+
fact: "is",
|
|
11719
|
+
type: sig.proves
|
|
11720
|
+
});
|
|
11721
|
+
no.push({
|
|
11722
|
+
path,
|
|
11723
|
+
fact: "not",
|
|
11724
|
+
type: sig.proves
|
|
11725
|
+
});
|
|
11726
|
+
}
|
|
11727
|
+
if (sig.present === true) {
|
|
11728
|
+
yes.push({
|
|
11729
|
+
path,
|
|
11730
|
+
fact: "present"
|
|
11731
|
+
});
|
|
11732
|
+
no.push({
|
|
11733
|
+
path,
|
|
11734
|
+
fact: "absent"
|
|
11735
|
+
});
|
|
11736
|
+
}
|
|
11737
|
+
return {
|
|
11738
|
+
yes,
|
|
11739
|
+
no
|
|
11740
|
+
};
|
|
11741
|
+
},
|
|
11323
11742
|
part: (input, path) => {
|
|
11324
11743
|
const read = signatures(input);
|
|
11325
11744
|
if (read === void 0 || read.sigs.length !== 1) return {};
|
|
@@ -13107,10 +13526,23 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
|
|
|
13107
13526
|
}
|
|
13108
13527
|
};
|
|
13109
13528
|
/**
|
|
13529
|
+
* The definition of the standard evaluator `ref.resolve` (REF.RESOLVE, D133). It resolves the steps of the path at each
|
|
13530
|
+
* evaluation. The plan compiles the same path one time.
|
|
13531
|
+
*/
|
|
13532
|
+
const refDefinition = ({ data, resolve: walk }) => {
|
|
13533
|
+
if (!Array.isArray(data) || data.length === 0) return fail("#VALUE!", "The value of ref is a path: a list that starts with a root, for example [\"names\", \"a\"].");
|
|
13534
|
+
const found = walk(data);
|
|
13535
|
+
return found.ok ? ok(valueOfThing(found.thing)) : fail(found.code, found.reason);
|
|
13536
|
+
};
|
|
13537
|
+
/**
|
|
13110
13538
|
* The definitions of the reference for the evaluators of the standard machine that need their own reading. The
|
|
13111
|
-
* reference uses them for the standard evaluators, also without the option `definitions`. It holds `tree.node
|
|
13539
|
+
* reference uses them for the standard evaluators, also without the option `definitions`. It holds `tree.node` and
|
|
13540
|
+
* `ref.resolve`. A host that wraps `ref.resolve` wraps this function, because the standard evaluator is compiled.
|
|
13112
13541
|
*/
|
|
13113
|
-
const STD_DEFINITIONS = { evaluators: {
|
|
13542
|
+
const STD_DEFINITIONS = { evaluators: {
|
|
13543
|
+
"tree.node": treeDefinition,
|
|
13544
|
+
"ref.resolve": refDefinition
|
|
13545
|
+
} };
|
|
13114
13546
|
const CLOSURE$1 = /* @__PURE__ */ Symbol.for("coeval.closure");
|
|
13115
13547
|
/** This function sets an own field, also the field `__proto__` (SHAPE.PROTO). */
|
|
13116
13548
|
function setField$1(target, key, value) {
|
|
@@ -14702,6 +15134,14 @@ function readsUnknown(reads) {
|
|
|
14702
15134
|
function resolutions(reads) {
|
|
14703
15135
|
return reads.filter((read) => read.free && read.kept !== true);
|
|
14704
15136
|
}
|
|
15137
|
+
/** This function gives the text of a value of a trace. It does not throw for a bigint or a record with a cycle. */
|
|
15138
|
+
function valueText$1(value) {
|
|
15139
|
+
try {
|
|
15140
|
+
return JSON.stringify(value) ?? describe(value);
|
|
15141
|
+
} catch {
|
|
15142
|
+
return describe(value);
|
|
15143
|
+
}
|
|
15144
|
+
}
|
|
14705
15145
|
function pathText(path) {
|
|
14706
15146
|
if (path === void 0) return "no read";
|
|
14707
15147
|
try {
|
|
@@ -14857,6 +15297,96 @@ async function agreeRun(machine, doc, context = makeContext(), options = {}) {
|
|
|
14857
15297
|
reads: compared
|
|
14858
15298
|
};
|
|
14859
15299
|
}
|
|
15300
|
+
/** The type errors of the kernel, by the evaluator that gives them (STATIC.TYPES-AGREE). */
|
|
15301
|
+
const TYPE_ERRORS = {
|
|
15302
|
+
"formula.op": "#NAME?",
|
|
15303
|
+
"formula.if": "#VALUE!",
|
|
15304
|
+
"formula.and": "#VALUE!",
|
|
15305
|
+
"formula.or": "#VALUE!"
|
|
15306
|
+
};
|
|
15307
|
+
/**
|
|
15308
|
+
* This function examines the agreement rule for types (STATIC.TYPES-AGREE, D148). A document with no issue evaluates
|
|
15309
|
+
* with a trace. Each value of the trace is a member of the type of its place. A value of a precise type is also a member
|
|
15310
|
+
* of the type that its position needs. No document with precise parts gives a type error of the kernel.
|
|
15311
|
+
*
|
|
15312
|
+
* A language imports this function for its own property tests, with `agree`. A failure tells that a signature, a type
|
|
15313
|
+
* rule, a cover or a root type does not hold. A value that breaks a position of an imprecise type ends the promise, and
|
|
15314
|
+
* the result then has `checked: false` (TYPE.GRADUAL).
|
|
15315
|
+
*
|
|
15316
|
+
* @param machine - The world and the code of the evaluators, with their type rules.
|
|
15317
|
+
* @param doc - The document.
|
|
15318
|
+
* @param context - The context. Its roots are members of the root types.
|
|
15319
|
+
* @param options - The options of `check`, with the root types, and `guards`.
|
|
15320
|
+
* @returns The agreement, or the first place that breaks it.
|
|
15321
|
+
*/
|
|
15322
|
+
function agreeTypes(machine, doc, context = makeContext(), options = {}) {
|
|
15323
|
+
const typing = typeCheck(machine, doc, options);
|
|
15324
|
+
if (typing.issues.length > 0) return {
|
|
15325
|
+
ok: true,
|
|
15326
|
+
checked: false,
|
|
15327
|
+
values: 0
|
|
15328
|
+
};
|
|
15329
|
+
const keyOf = (path) => JSON.stringify(path.map(String));
|
|
15330
|
+
const places = new Map(typing.places.map((item) => [keyOf(item.place), item]));
|
|
15331
|
+
const domains = machine.domains;
|
|
15332
|
+
const guards = options.guards === true ? boundariesOf(typing, domains) : void 0;
|
|
15333
|
+
const stack = [evaluate(machine, doc, context, {
|
|
15334
|
+
...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
|
|
15335
|
+
...guards === void 0 ? {} : { guards }
|
|
15336
|
+
}).trace];
|
|
15337
|
+
const nodes = [];
|
|
15338
|
+
while (stack.length > 0) {
|
|
15339
|
+
const node = stack.pop();
|
|
15340
|
+
nodes.push(node);
|
|
15341
|
+
stack.push(...node.children);
|
|
15342
|
+
}
|
|
15343
|
+
for (const node of nodes) {
|
|
15344
|
+
const place = places.get(keyOf(node.path));
|
|
15345
|
+
if (place?.expected === void 0 || !node.result.ok || isPrecise(place.type, domains)) continue;
|
|
15346
|
+
if (!member(node.result.value, place.expected, domains)) return {
|
|
15347
|
+
ok: true,
|
|
15348
|
+
checked: false,
|
|
15349
|
+
values: 0
|
|
15350
|
+
};
|
|
15351
|
+
}
|
|
15352
|
+
let values = 0;
|
|
15353
|
+
for (const node of nodes.reverse()) {
|
|
15354
|
+
const place = places.get(keyOf(node.path));
|
|
15355
|
+
if (place === void 0) continue;
|
|
15356
|
+
const at = node.path.map(String);
|
|
15357
|
+
if (!node.result.ok) {
|
|
15358
|
+
const parts = node.children.map((child) => places.get(keyOf(child.path)));
|
|
15359
|
+
const decided = node.children.every((child) => child.result.ok) && parts.every((part) => part?.expected !== void 0 && isPrecise(part.type, domains));
|
|
15360
|
+
const code = TYPE_ERRORS[node.answer.evaluator ?? ""];
|
|
15361
|
+
if (decided && node.result.error.code === code) return {
|
|
15362
|
+
ok: false,
|
|
15363
|
+
clause: "error",
|
|
15364
|
+
place: at,
|
|
15365
|
+
reason: `The document gives ${code}, but it checks with no issue.`
|
|
15366
|
+
};
|
|
15367
|
+
continue;
|
|
15368
|
+
}
|
|
15369
|
+
const value = node.result.value;
|
|
15370
|
+
values += 1;
|
|
15371
|
+
if (!member(value, place.type, domains)) return {
|
|
15372
|
+
ok: false,
|
|
15373
|
+
clause: "value",
|
|
15374
|
+
place: at,
|
|
15375
|
+
reason: `The value ${valueText$1(value)} is not a member of ${typeText(place.type)}.`
|
|
15376
|
+
};
|
|
15377
|
+
if (place.expected !== void 0 && !member(value, place.expected, domains)) return {
|
|
15378
|
+
ok: false,
|
|
15379
|
+
clause: "argument",
|
|
15380
|
+
place: at,
|
|
15381
|
+
reason: `The value ${valueText$1(value)} is not a member of the needed type ${typeText(place.expected)}.`
|
|
15382
|
+
};
|
|
15383
|
+
}
|
|
15384
|
+
return {
|
|
15385
|
+
ok: true,
|
|
15386
|
+
checked: true,
|
|
15387
|
+
values
|
|
15388
|
+
};
|
|
15389
|
+
}
|
|
14860
15390
|
// src/codec-laws.ts
|
|
14861
15391
|
/** The order of the laws in the list of findings. */
|
|
14862
15392
|
const ORDER$1 = [
|
|
@@ -15280,6 +15810,13 @@ function compileConstructs(given, ops) {
|
|
|
15280
15810
|
constructKinds
|
|
15281
15811
|
};
|
|
15282
15812
|
}
|
|
15813
|
+
/** This function examines the field `domain` of a call form (D141). A form `literal` of `ext.domain` needs a name, and each other form refuses it. */
|
|
15814
|
+
function compileDomain(given, args) {
|
|
15815
|
+
const writes = args === "literal" && given.kind === "ext.domain";
|
|
15816
|
+
if (writes && (typeof given.domain !== "string" || given.domain === "")) throw new TypeError(`The call form "${given.name}" of ext.domain needs the name of its domain.`);
|
|
15817
|
+
if (!writes && given.domain !== void 0) throw new TypeError(`The call form "${given.name}" takes no domain: only a form literal of ext.domain has one.`);
|
|
15818
|
+
return given.domain;
|
|
15819
|
+
}
|
|
15283
15820
|
/** This function examines the field `wrap` of a call form (K159). A name that is not a field of the form throws. */
|
|
15284
15821
|
function compileWrap(given, args) {
|
|
15285
15822
|
const wrap = given.wrap;
|
|
@@ -15291,6 +15828,16 @@ function compileWrap(given, args) {
|
|
|
15291
15828
|
return new Set(wrap);
|
|
15292
15829
|
}
|
|
15293
15830
|
/** This function gives the types of the data envelopes of a profile (K159), or `undefined` without them. */
|
|
15831
|
+
/** This function examines the field `data` of a call form (D177). Each name is a field of the form, and no name is in `wrap`. */
|
|
15832
|
+
function compileData(given, wrap) {
|
|
15833
|
+
const data = given.data ?? [];
|
|
15834
|
+
if (data.length > 0 && given.fields === void 0) throw new TypeError(`The call form "${given.name}" takes data only with fields.`);
|
|
15835
|
+
for (const name of data) {
|
|
15836
|
+
if (given.fields?.includes(name) !== true) throw new TypeError(`The call form "${given.name}" has no field ${name} for its data.`);
|
|
15837
|
+
if (wrap === true || wrap !== false && wrap.has(name)) throw new TypeError(`The call form "${given.name}" has the field ${name} in wrap and in data.`);
|
|
15838
|
+
}
|
|
15839
|
+
return new Set(data);
|
|
15840
|
+
}
|
|
15294
15841
|
function compileEnvelopes(given) {
|
|
15295
15842
|
if (given === void 0) return void 0;
|
|
15296
15843
|
const out = {};
|
|
@@ -15327,17 +15874,22 @@ function compileProfile(profile) {
|
|
|
15327
15874
|
if (!FORM_ARGS.includes(args)) throw new TypeError(`The call form "${given.name}" has the unknown arguments ${String(args)}.`);
|
|
15328
15875
|
if (args === "fields" !== (given.fields !== void 0) && args !== "named") throw new TypeError(`The call form "${given.name}" with the arguments ${args} ${args === "fields" ? "needs" : "takes no"} fields.`);
|
|
15329
15876
|
if (given.min !== void 0 && (args === "named" || args === "literal")) throw new TypeError(`The call form "${given.name}" with the arguments ${args} takes no min.`);
|
|
15877
|
+
const wrap = compileWrap(given, args);
|
|
15330
15878
|
const form = {
|
|
15331
15879
|
name: given.name,
|
|
15332
15880
|
type,
|
|
15333
15881
|
args,
|
|
15334
15882
|
fields: given.fields,
|
|
15335
15883
|
min: given.min ?? given.fields?.length ?? 0,
|
|
15336
|
-
wrap
|
|
15884
|
+
wrap,
|
|
15885
|
+
domain: compileDomain(given, args),
|
|
15886
|
+
data: compileData(given, wrap)
|
|
15337
15887
|
};
|
|
15338
15888
|
forms.set(form.name, form);
|
|
15339
15889
|
addTo(formsByKind, key, form);
|
|
15340
15890
|
}
|
|
15891
|
+
const brackets = [...forms.values()].some((form) => form.data.size > 0);
|
|
15892
|
+
for (const symbol of brackets ? [...ops.prefixSymbols, ...ops.binarySymbols] : []) if (/^[[\]{}]/.test(symbol)) throw new TypeError(`The operator "${symbol}" reads the text of a field of data.`);
|
|
15341
15893
|
const compiled = {
|
|
15342
15894
|
...ops,
|
|
15343
15895
|
numbers: literals.numbers ?? true,
|
|
@@ -15369,7 +15921,8 @@ function compileProfile(profile) {
|
|
|
15369
15921
|
...ops.opWords,
|
|
15370
15922
|
...roots
|
|
15371
15923
|
]),
|
|
15372
|
-
maxDepth: profile.maxDepth ?? 256
|
|
15924
|
+
maxDepth: profile.maxDepth ?? 256,
|
|
15925
|
+
brackets
|
|
15373
15926
|
};
|
|
15374
15927
|
compiledProfiles.set(profile, compiled);
|
|
15375
15928
|
return compiled;
|
|
@@ -15828,7 +16381,7 @@ var Parser = class {
|
|
|
15828
16381
|
}
|
|
15829
16382
|
/** This method stops at a token where a group or a list must end. A list can also continue with its separator. */
|
|
15830
16383
|
noEnd(close, list) {
|
|
15831
|
-
const closer = close
|
|
16384
|
+
const closer = closerName(close);
|
|
15832
16385
|
const before = list ? `"${this.syn.separator}" or a ` : "";
|
|
15833
16386
|
return this.stop(`A ${before}closing ${closer} is missing.`, this.pos, this.tokenLength());
|
|
15834
16387
|
}
|
|
@@ -15853,16 +16406,31 @@ var Parser = class {
|
|
|
15853
16406
|
this.pos += 1;
|
|
15854
16407
|
return args;
|
|
15855
16408
|
}
|
|
15856
|
-
if (this.pos >= this.text.length) this.stop(`A closing ${close
|
|
16409
|
+
if (this.pos >= this.text.length) this.stop(`A closing ${closerName(close)} is missing.`, open, 1);
|
|
15857
16410
|
this.noEnd(close, true);
|
|
15858
16411
|
}
|
|
15859
16412
|
}
|
|
15860
16413
|
/**
|
|
15861
|
-
* This method reads the
|
|
15862
|
-
*
|
|
16414
|
+
* This method reads the argument of a field of data (D177): a list between brackets, a record between braces, or a
|
|
16415
|
+
* document. A literal in it stays its data.
|
|
15863
16416
|
*/
|
|
15864
|
-
|
|
15865
|
-
|
|
16417
|
+
data() {
|
|
16418
|
+
this.skip();
|
|
16419
|
+
const start = this.pos;
|
|
16420
|
+
const c = this.text[start];
|
|
16421
|
+
if (c !== "[" && c !== "{") return this.bound();
|
|
16422
|
+
this.depth += 1;
|
|
16423
|
+
if (this.depth > this.syn.maxDepth) this.stop(`The text is deeper than ${String(this.syn.maxDepth)} levels.`, start, 0);
|
|
16424
|
+
const value = c === "[" ? this.argumentsOf(() => this.data(), "]") : this.entries(void 0, true);
|
|
16425
|
+
this.depth -= 1;
|
|
16426
|
+
return value;
|
|
16427
|
+
}
|
|
16428
|
+
/**
|
|
16429
|
+
* This method reads the entries `key: expr` into a record. The record is the arguments of a form `named`
|
|
16430
|
+
* (SYNTAX.RECORD), or the entries between braces (SYNTAX.RECORD-TEXT). It is also a record of data (D177).
|
|
16431
|
+
*/
|
|
16432
|
+
entries(form, data = false) {
|
|
16433
|
+
const owner = data ? "record of data" : form === void 0 ? "record" : `form ${form.name}`;
|
|
15866
16434
|
const value = {};
|
|
15867
16435
|
const entry = () => {
|
|
15868
16436
|
this.skip();
|
|
@@ -15872,9 +16440,10 @@ var Parser = class {
|
|
|
15872
16440
|
this.skip();
|
|
15873
16441
|
if (key === void 0 || this.text[this.pos] !== ":") this.stop(`Each ${form === void 0 ? "entry" : "argument"} of the ${owner} is a key, a ":" and a document.`, at, Math.max(end - at, this.tokenLength()));
|
|
15874
16442
|
if (form?.fields !== void 0 && !form.fields.includes(key)) this.stop(`The form ${form.name} has no field ${key}.`, at, end - at);
|
|
16443
|
+
if (data && key === "type") this.stop("A record of data has no key type, because the key type makes a document.", at, end - at);
|
|
15875
16444
|
if (Object.hasOwn(value, key)) this.stop(`The ${owner} has the field ${key} two times.`, at, end - at);
|
|
15876
16445
|
this.pos += 1;
|
|
15877
|
-
const arg = this.bound();
|
|
16446
|
+
const arg = data || form?.data.has(key) === true ? this.data() : this.bound();
|
|
15878
16447
|
setOwn$1(value, key, form !== void 0 && wraps(form, key) ? envelop(this.syn, arg) : arg);
|
|
15879
16448
|
};
|
|
15880
16449
|
this.argumentsOf(entry, form === void 0 ? "}" : ")");
|
|
@@ -15883,11 +16452,19 @@ var Parser = class {
|
|
|
15883
16452
|
call(name, start, nameLength) {
|
|
15884
16453
|
const form = this.syn.forms.get(name);
|
|
15885
16454
|
if (form?.args === "named") return opDoc(form, this.entries(form));
|
|
15886
|
-
|
|
16455
|
+
let index = 0;
|
|
16456
|
+
const args = this.argumentsOf(() => {
|
|
16457
|
+
const key = form?.fields?.[index];
|
|
16458
|
+
index += 1;
|
|
16459
|
+
return key !== void 0 && form?.data.has(key) === true ? this.data() : this.bound();
|
|
16460
|
+
});
|
|
15887
16461
|
if (form?.args === "literal") {
|
|
15888
16462
|
const [only] = args;
|
|
15889
16463
|
if (args.length !== 1 || !isScalar(only)) this.stop(`The form ${name} takes one literal that JSON writes.`, start, this.pos - start);
|
|
15890
|
-
return opDoc(form, only
|
|
16464
|
+
return opDoc(form, form.domain === void 0 ? only : {
|
|
16465
|
+
domain: form.domain,
|
|
16466
|
+
data: only
|
|
16467
|
+
});
|
|
15891
16468
|
}
|
|
15892
16469
|
if (form !== void 0) {
|
|
15893
16470
|
const most = form.fields?.length ?? Number.POSITIVE_INFINITY;
|
|
@@ -15913,15 +16490,20 @@ var Parser = class {
|
|
|
15913
16490
|
/** The end of a recovery. The class `Recovery` throws it, and its method `run` catches it. */
|
|
15914
16491
|
var End = class {};
|
|
15915
16492
|
function hasBraces(syn) {
|
|
15916
|
-
return syn.constructs.record !== void 0 || syn.constructs.let !== void 0;
|
|
16493
|
+
return syn.constructs.record !== void 0 || syn.constructs.let !== void 0 || syn.brackets;
|
|
16494
|
+
}
|
|
16495
|
+
/** This function gives the name of a closer in a message. */
|
|
16496
|
+
function closerName(close) {
|
|
16497
|
+
return close === ")" ? "parenthesis" : close === "]" ? "bracket" : "brace";
|
|
15917
16498
|
}
|
|
15918
16499
|
/** This function gives the closer of an opening bracket of a profile, or `undefined` for each other character. */
|
|
15919
16500
|
function closerOf(syn, c) {
|
|
15920
16501
|
if (c === "(") return ")";
|
|
16502
|
+
if (c === "[" && syn.brackets) return "]";
|
|
15921
16503
|
return c === "{" && hasBraces(syn) ? "}" : void 0;
|
|
15922
16504
|
}
|
|
15923
16505
|
function isCloser(syn, c) {
|
|
15924
|
-
return c === ")" || c === "}" && hasBraces(syn);
|
|
16506
|
+
return c === ")" || c === "]" && syn.brackets || c === "}" && hasBraces(syn);
|
|
15925
16507
|
}
|
|
15926
16508
|
/** This function gives the position after a quoted text at `at`, or after one other character. An open quote gives `Infinity`. */
|
|
15927
16509
|
function pastToken(syn, text, at) {
|
|
@@ -16164,6 +16746,7 @@ function refShape(syn, value) {
|
|
|
16164
16746
|
}
|
|
16165
16747
|
function callName(syn, keys) {
|
|
16166
16748
|
if (keys.length === 0 || !keys.every((key) => typeof key === "string" && NAME.test(key))) return void 0;
|
|
16749
|
+
if (keys.length > 1 && !syn.fields) return void 0;
|
|
16167
16750
|
const name = keys.join(".");
|
|
16168
16751
|
if (syn.forms.has(name) || syn.opWords.has(keys[0])) return void 0;
|
|
16169
16752
|
return syn.ops === true || syn.ops.has(name) ? name : void 0;
|
|
@@ -16186,10 +16769,16 @@ function wrappedShape(syn, doc) {
|
|
|
16186
16769
|
const literal = literalShape(syn, doc.value);
|
|
16187
16770
|
return literal.tag === "text" ? literal : void 0;
|
|
16188
16771
|
}
|
|
16772
|
+
/** This function tells if a value of `ext.domain` is a record with this domain and its data, and no other key. */
|
|
16773
|
+
function holdsDomain(value, domain) {
|
|
16774
|
+
return isRecord(value) && value["domain"] === domain && Object.hasOwn(value, "data") && Object.keys(value).length === 2;
|
|
16775
|
+
}
|
|
16189
16776
|
function formShape(syn, form, value) {
|
|
16190
16777
|
if (form.args === "literal") {
|
|
16191
|
-
if (!
|
|
16192
|
-
const
|
|
16778
|
+
if (form.domain !== void 0 && !holdsDomain(value, form.domain)) return void 0;
|
|
16779
|
+
const data = form.domain === void 0 ? value : value["data"];
|
|
16780
|
+
if (!isScalar(data)) return void 0;
|
|
16781
|
+
const literal = literalShape(syn, data);
|
|
16193
16782
|
return literal.tag === "text" ? {
|
|
16194
16783
|
tag: "text",
|
|
16195
16784
|
text: `${form.name}(${literal.text})`
|
|
@@ -16205,7 +16794,8 @@ function formShape(syn, form, value) {
|
|
|
16205
16794
|
args: keys.map((key) => [
|
|
16206
16795
|
key,
|
|
16207
16796
|
value[key],
|
|
16208
|
-
wraps(form, key)
|
|
16797
|
+
wraps(form, key),
|
|
16798
|
+
form.data.has(key)
|
|
16209
16799
|
]),
|
|
16210
16800
|
named: true
|
|
16211
16801
|
};
|
|
@@ -16232,7 +16822,8 @@ function formShape(syn, form, value) {
|
|
|
16232
16822
|
args: present.map((key) => [
|
|
16233
16823
|
key,
|
|
16234
16824
|
value[key],
|
|
16235
|
-
wraps(form, key)
|
|
16825
|
+
wraps(form, key),
|
|
16826
|
+
form.data.has(key)
|
|
16236
16827
|
])
|
|
16237
16828
|
};
|
|
16238
16829
|
}
|
|
@@ -16368,6 +16959,18 @@ function bracesText(syn, record, path, sub) {
|
|
|
16368
16959
|
if (!texts.ok) return texts;
|
|
16369
16960
|
return ok(`{${texts.value.map((text, index) => `${keyText(keys[index])}: ${text}`).join(`${syn.separator} `)}}`);
|
|
16370
16961
|
}
|
|
16962
|
+
/**
|
|
16963
|
+
* This function writes the argument of a field of data (D177): a list between brackets, or a record between braces.
|
|
16964
|
+
* The function `sub` writes a literal and a document. A record that is an envelope is a document.
|
|
16965
|
+
*/
|
|
16966
|
+
function dataText(syn, value, path, sub) {
|
|
16967
|
+
const each = (child, at) => dataText(syn, child, at, sub);
|
|
16968
|
+
if (Array.isArray(value)) {
|
|
16969
|
+
const texts = partTexts(value.map((item, index) => [index, item]), path, each);
|
|
16970
|
+
return texts.ok ? ok(`[${texts.value.join(`${syn.separator} `)}]`) : texts;
|
|
16971
|
+
}
|
|
16972
|
+
return isRecord(value) && !isEnvelope(value) && !Object.hasOwn(value, "type") ? bracesText(syn, value, path, each) : sub(value, path);
|
|
16973
|
+
}
|
|
16371
16974
|
/** This function writes a construct form (K145). */
|
|
16372
16975
|
function constructText(syn, shape, sub) {
|
|
16373
16976
|
if (shape.tag === "record") return bracesText(syn, shape.entries, [], sub);
|
|
@@ -16410,8 +17013,8 @@ function printNode(syn, doc, sub) {
|
|
|
16410
17013
|
return ok(texts.join("."));
|
|
16411
17014
|
}
|
|
16412
17015
|
const texts = [];
|
|
16413
|
-
for (const [key, arg, wrapped] of shape.args) {
|
|
16414
|
-
const result = sub(arg, [key], wrapped);
|
|
17016
|
+
for (const [key, arg, wrapped, data] of shape.args) {
|
|
17017
|
+
const result = data === true ? dataText(syn, arg, [key], sub) : sub(arg, [key], wrapped);
|
|
16415
17018
|
if (!result.ok) return result;
|
|
16416
17019
|
texts.push(shape.named === true ? `${keyText(String(key))}: ${result.value}` : result.value);
|
|
16417
17020
|
}
|
|
@@ -19286,6 +19889,7 @@ function schedule(machine, options = {}) {
|
|
|
19286
19889
|
let keptAt = -1;
|
|
19287
19890
|
const keptNodes = [];
|
|
19288
19891
|
let keptMet = false;
|
|
19892
|
+
let keptFrom = 0;
|
|
19289
19893
|
let count = 0;
|
|
19290
19894
|
let ahead = 0;
|
|
19291
19895
|
let wanted;
|
|
@@ -19356,7 +19960,10 @@ function schedule(machine, options = {}) {
|
|
|
19356
19960
|
const reader = stack[stack.length - 1];
|
|
19357
19961
|
const known = epoch.values.get(id);
|
|
19358
19962
|
if (known !== void 0) {
|
|
19359
|
-
if (reader !== void 0 && onOpen.has(id))
|
|
19963
|
+
if (reader !== void 0 && onOpen.has(id)) {
|
|
19964
|
+
if (keptAt >= 0 && order.get(id) < keptFrom) keptMet = true;
|
|
19965
|
+
else lower(reader, order.get(id));
|
|
19966
|
+
}
|
|
19360
19967
|
return known;
|
|
19361
19968
|
}
|
|
19362
19969
|
if (busy.has(id)) {
|
|
@@ -19560,9 +20167,11 @@ function schedule(machine, options = {}) {
|
|
|
19560
20167
|
keeping(read) {
|
|
19561
20168
|
const outer = keptAt;
|
|
19562
20169
|
const outerMet = keptMet;
|
|
20170
|
+
const outerFrom = keptFrom;
|
|
19563
20171
|
const from = keptNodes.length;
|
|
19564
20172
|
keptAt = stack.length;
|
|
19565
20173
|
keptMet = false;
|
|
20174
|
+
keptFrom = count;
|
|
19566
20175
|
try {
|
|
19567
20176
|
return read();
|
|
19568
20177
|
} finally {
|
|
@@ -19573,6 +20182,7 @@ function schedule(machine, options = {}) {
|
|
|
19573
20182
|
}
|
|
19574
20183
|
keptAt = outer;
|
|
19575
20184
|
keptMet = outerMet;
|
|
20185
|
+
keptFrom = outerFrom;
|
|
19576
20186
|
}
|
|
19577
20187
|
}
|
|
19578
20188
|
});
|
|
@@ -20556,6 +21166,6 @@ function samplesAt(values, closed, depth) {
|
|
|
20556
21166
|
function typeFromSamples(values, options = {}) {
|
|
20557
21167
|
return samplesAt(values, options.closed === true, 0);
|
|
20558
21168
|
}
|
|
20559
|
-
export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, GENERATION_LIMIT, Held, JOURNAL, MAX_SYNTAX_ISSUES, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, capKeys, check, checkCycles, checkLatent, checkStep, checkSteps, checkSyntax, checkWorld, circularOf, classify, codecLaws, collectOf, compilePath, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, documentKey, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partGrants, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, resolveCompiled, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
|
|
21169
|
+
export { ATTRIBUTE_RUNGS, CAPS_TYPE, CIRCULAR_LIMIT, CONSTRUCTS, ENVELOPE_KEYS, Failure, GENERATION_LIMIT, Held, JOURNAL, MAX_SYNTAX_ISSUES, MergeError, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_DEFINITIONS, STD_DOMAINS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_SYNTAX, STD_WALKERS, STD_WORLD, THING, WORLD_SYNTAX, agree, agreeRun, agreeSchedule, agreeTypes, argsKey, ask, atArgsOf, atRuleOf, attributeGraph, attributeTrace, attributeVertexId, boundariesOf, capKeys, check, checkCycles, checkLatent, checkStep, checkSteps, checkSyntax, checkWorld, circularOf, classify, codecLaws, collectOf, compilePath, components, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, derefStep, describe, docEquals, documentKey, durable, edgesOf, effectEdges, effectsOf, effectsOfVerb, encodeLog, encodeValue, entriesAsJson, equationType, evaluate, extendDomain, factsOf, fail, failures, field, fits, flatten, formulaDefinitions, formulaEvaluators, formulaFacts, formulaKinds, formulaKnown, formulaMachine, fromJson, generate, heights, ifRunner, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isStep, isTypeRef, join, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapDocs, mapRefs, member, mergeMachines, mergeWorlds, narrow, nearestWalker, necessary, nodeAt, nodeLayers, ok, parse, partCaps, partGrants, partsOf, pathMatches, permits, placeOf, placed, planner, prepare, print, printReads, random, recorder, ref, reference, referenceRun, refsOf, replayer, resolve, resolveCompiled, restrictMachine, restrictWorld, run, sameResult, sameValue, schedule, splitParts, stepLadder, stepOf, stepRank, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
|
|
20560
21170
|
|
|
20561
21171
|
//# sourceMappingURL=index.js.map
|