@mark1russell7/coeval 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/build/index.d.ts +281 -222
- package/build/index.d.ts.map +1 -1
- package/build/index.js +100 -17
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/evaluate.ts +72 -3
- package/src/index.ts +3 -0
- package/src/static.ts +39 -7
- package/src/stdlib.ts +6 -2
- package/src/world.ts +24 -0
package/build/index.js
CHANGED
|
@@ -1281,6 +1281,52 @@ function narrow(parent, next) {
|
|
|
1281
1281
|
caps
|
|
1282
1282
|
};
|
|
1283
1283
|
}
|
|
1284
|
+
/** No capabilities. One list serves each masked part. */
|
|
1285
|
+
const NO_CAPS = Object.freeze([]);
|
|
1286
|
+
/** No capability rules. One list serves each part that no rule narrows. */
|
|
1287
|
+
const NO_RULES = Object.freeze([]);
|
|
1288
|
+
/**
|
|
1289
|
+
* This function gives the capabilities that two lists both permit. An effect is permitted by the result when each
|
|
1290
|
+
* list permits it. When the list `b` permits each capability of `a`, the result is the list `a` itself.
|
|
1291
|
+
*
|
|
1292
|
+
* @param a - The first list, for example the capabilities of a document.
|
|
1293
|
+
* @param b - The second list, for example the list of a rule `only`.
|
|
1294
|
+
* @returns The capabilities that both lists permit.
|
|
1295
|
+
*/
|
|
1296
|
+
function intersectCaps(a, b) {
|
|
1297
|
+
if (a.every((cap) => permits(b, cap))) return a;
|
|
1298
|
+
const out = [];
|
|
1299
|
+
for (const cap of b) if (permits(a, cap)) out.push(cap);
|
|
1300
|
+
for (const cap of a) if (permits(b, cap) && !permits(out, cap)) out.push(cap);
|
|
1301
|
+
return out;
|
|
1302
|
+
}
|
|
1303
|
+
/** This function gives the capability rules of a kind that cover a part and change its capabilities. */
|
|
1304
|
+
function rulesFor(rules, path) {
|
|
1305
|
+
if (rules === void 0 || rules.length === 0) return NO_RULES;
|
|
1306
|
+
const out = rules.filter((rule) => rule.rule !== "same" && (rule.in === void 0 || rule.in.some((pattern) => pathMatches(path, pattern))));
|
|
1307
|
+
return out.length === 0 ? NO_RULES : out;
|
|
1308
|
+
}
|
|
1309
|
+
/** This function applies the rules that cover a part to the capabilities of its document. */
|
|
1310
|
+
function capsUnder(rules, caps) {
|
|
1311
|
+
let out = caps;
|
|
1312
|
+
for (const rule of rules) {
|
|
1313
|
+
if (rule.rule === "mask") return NO_CAPS;
|
|
1314
|
+
if (rule.rule === "only") out = intersectCaps(out, rule.caps);
|
|
1315
|
+
}
|
|
1316
|
+
return out;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* This function gives the capabilities that a kind gives one of its parts, by the capability rules of its contract.
|
|
1320
|
+
* The kernel and the static kit both use it, thus a run and a check narrow the same way.
|
|
1321
|
+
*
|
|
1322
|
+
* @param rules - The capability rules of the kind (`Kind.caps`).
|
|
1323
|
+
* @param path - The path of the part in the value of the document.
|
|
1324
|
+
* @param caps - The capabilities of the document.
|
|
1325
|
+
* @returns The capabilities of the part: the same list or a smaller one.
|
|
1326
|
+
*/
|
|
1327
|
+
function partCaps(rules, path, caps) {
|
|
1328
|
+
return capsUnder(rulesFor(rules, path), caps);
|
|
1329
|
+
}
|
|
1284
1330
|
function selfLabel(self) {
|
|
1285
1331
|
try {
|
|
1286
1332
|
if (isHostThing(self)) return self.label;
|
|
@@ -1676,7 +1722,9 @@ function compileNode(c, value, place, declared, depth, address = false) {
|
|
|
1676
1722
|
}
|
|
1677
1723
|
const parts = split.parts.map((slot) => {
|
|
1678
1724
|
const item = slot.item;
|
|
1679
|
-
const
|
|
1725
|
+
const own = compileNode(c, item, place.concat(slot.path), slot.of, depth + 1, slot.address === true);
|
|
1726
|
+
const rules = rulesFor(kind?.caps, slot.path);
|
|
1727
|
+
const compiled = rules.length === 0 ? own : gated(rules, own);
|
|
1680
1728
|
const header = typeof item?.name === "string" && isEnvelope(item) ? item.name : void 0;
|
|
1681
1729
|
return header === void 0 ? {
|
|
1682
1730
|
key: slot.key,
|
|
@@ -1720,6 +1768,25 @@ function placedCode(inner, place, name) {
|
|
|
1720
1768
|
}
|
|
1721
1769
|
};
|
|
1722
1770
|
}
|
|
1771
|
+
/**
|
|
1772
|
+
* This function gives the code of a part that capability rules cover. The code narrows the context of the part by
|
|
1773
|
+
* the rules before the part starts.
|
|
1774
|
+
*/
|
|
1775
|
+
function gated(rules, part) {
|
|
1776
|
+
const inner = part.code;
|
|
1777
|
+
const steps = part.run;
|
|
1778
|
+
const under = (ctx) => {
|
|
1779
|
+
const caps = capsUnder(rules, ctx.caps);
|
|
1780
|
+
return caps === ctx.caps || caps.length === 0 && ctx.caps.length === 0 ? ctx : {
|
|
1781
|
+
...ctx,
|
|
1782
|
+
caps
|
|
1783
|
+
};
|
|
1784
|
+
};
|
|
1785
|
+
return {
|
|
1786
|
+
code: (ctx, rt) => inner(under(ctx), rt),
|
|
1787
|
+
run: (ctx, rt) => steps(under(ctx), rt)
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1723
1790
|
/** This function gives the steps of a runner, with the place of each error and of each exception. */
|
|
1724
1791
|
function placedRun(inner, place, name) {
|
|
1725
1792
|
return function* (ctx, rt) {
|
|
@@ -2146,6 +2213,7 @@ const STD_WORLD = {
|
|
|
2146
2213
|
view: "view.op"
|
|
2147
2214
|
},
|
|
2148
2215
|
parts: { shape: "list" },
|
|
2216
|
+
caps: [{ rule: "mask" }],
|
|
2149
2217
|
summary: "It evaluates its part without capabilities, thus an effect in it fails."
|
|
2150
2218
|
},
|
|
2151
2219
|
log: {
|
|
@@ -2158,6 +2226,7 @@ const STD_WORLD = {
|
|
|
2158
2226
|
of: "text"
|
|
2159
2227
|
},
|
|
2160
2228
|
side: "run",
|
|
2229
|
+
effects: ["log"],
|
|
2161
2230
|
summary: "It writes the result of its part to the log. This is an effect."
|
|
2162
2231
|
},
|
|
2163
2232
|
write: {
|
|
@@ -2170,6 +2239,7 @@ const STD_WORLD = {
|
|
|
2170
2239
|
fields: ["value"]
|
|
2171
2240
|
},
|
|
2172
2241
|
side: "run",
|
|
2242
|
+
effects: ["write"],
|
|
2173
2243
|
summary: "It writes the result of its part to the store, at its key. This is an effect."
|
|
2174
2244
|
}
|
|
2175
2245
|
},
|
|
@@ -2347,13 +2417,10 @@ const STD_RUNNERS = {
|
|
|
2347
2417
|
}
|
|
2348
2418
|
return ok(last);
|
|
2349
2419
|
},
|
|
2350
|
-
"control.pure": function* ({ parts
|
|
2420
|
+
"control.pure": function* ({ parts }) {
|
|
2351
2421
|
const only = parts[0];
|
|
2352
2422
|
if (only === void 0) return fail("#VALUE!", "pure needs one part.");
|
|
2353
|
-
return yield* only.evaluate(
|
|
2354
|
-
...context,
|
|
2355
|
-
caps: []
|
|
2356
|
-
});
|
|
2423
|
+
return yield* only.evaluate();
|
|
2357
2424
|
},
|
|
2358
2425
|
"control.if": function* ({ parts }) {
|
|
2359
2426
|
const test = parts.find((part) => part.key === "test");
|
|
@@ -2878,9 +2945,10 @@ var Visit = class {
|
|
|
2878
2945
|
kind;
|
|
2879
2946
|
typePath;
|
|
2880
2947
|
address;
|
|
2948
|
+
caps;
|
|
2881
2949
|
#place;
|
|
2882
2950
|
#at;
|
|
2883
|
-
constructor(place, at, doc, declared, depth, names, later, slot, parent, kind, typePath, address) {
|
|
2951
|
+
constructor(place, at, doc, declared, depth, names, later, slot, parent, kind, typePath, address, caps) {
|
|
2884
2952
|
this.doc = doc;
|
|
2885
2953
|
this.declared = declared;
|
|
2886
2954
|
this.depth = depth;
|
|
@@ -2891,6 +2959,7 @@ var Visit = class {
|
|
|
2891
2959
|
this.kind = kind;
|
|
2892
2960
|
this.typePath = typePath;
|
|
2893
2961
|
this.address = address;
|
|
2962
|
+
this.caps = caps;
|
|
2894
2963
|
this.#place = place;
|
|
2895
2964
|
this.#at = at;
|
|
2896
2965
|
}
|
|
@@ -2903,14 +2972,15 @@ var Visit = class {
|
|
|
2903
2972
|
};
|
|
2904
2973
|
/**
|
|
2905
2974
|
* This function visits each document of a document: the root and each part at each depth, by the contracts of the
|
|
2906
|
-
* kinds. A part of a kind that the world does not have is not visited.
|
|
2975
|
+
* kinds. A part of a kind that the world does not have is not visited. With capabilities in the options, the walk
|
|
2976
|
+
* narrows them for each part by the rules of its kind, as a run does. The walk uses no stack of the host for the
|
|
2907
2977
|
* depth, thus a deep document cannot overflow it. The time and the memory of a walk are linear in the size of the
|
|
2908
2978
|
* document. A visit makes the keys of its place and of its path only when a reader asks for them.
|
|
2909
2979
|
*
|
|
2910
2980
|
* @param world - The world of the kinds.
|
|
2911
2981
|
* @param doc - The document, as JSON.
|
|
2912
2982
|
* @param visit - The function that gets each document. It gives `"skip"` to not visit the parts of a document.
|
|
2913
|
-
* @param options - The type of a bare root value, the names
|
|
2983
|
+
* @param options - The type of a bare root value, the names, the capabilities and a function for the problems.
|
|
2914
2984
|
*/
|
|
2915
2985
|
function walk(world, doc, visit, options = {}) {
|
|
2916
2986
|
const stack = [{
|
|
@@ -2923,7 +2993,8 @@ function walk(world, doc, visit, options = {}) {
|
|
|
2923
2993
|
later: NO_NAMES,
|
|
2924
2994
|
address: false,
|
|
2925
2995
|
slot: [],
|
|
2926
|
-
parent: void 0
|
|
2996
|
+
parent: void 0,
|
|
2997
|
+
caps: options.caps
|
|
2927
2998
|
}];
|
|
2928
2999
|
while (stack.length > 0) {
|
|
2929
3000
|
const item = stack.pop();
|
|
@@ -2943,7 +3014,7 @@ function walk(world, doc, visit, options = {}) {
|
|
|
2943
3014
|
};
|
|
2944
3015
|
const found = lookupKind(world, doc.type);
|
|
2945
3016
|
const kind = found.ok ? found.kind : void 0;
|
|
2946
|
-
const here = new Visit(item.place, item.at, doc, envelope === void 0, item.depth, item.names, item.later, item.slot, item.parent, kind, found.ok ? found.path : void 0, item.address ? true : void 0);
|
|
3017
|
+
const here = new Visit(item.place, item.at, doc, envelope === void 0, item.depth, item.names, item.later, item.slot, item.parent, kind, found.ok ? found.path : void 0, item.address ? true : void 0, item.caps);
|
|
2947
3018
|
if (visit(here) === "skip" || kind === void 0) continue;
|
|
2948
3019
|
const split = splitParts(kind.parts, doc.value);
|
|
2949
3020
|
const base = envelope === void 0 ? item.at : {
|
|
@@ -2985,7 +3056,8 @@ function walk(world, doc, visit, options = {}) {
|
|
|
2985
3056
|
later: hidden.length === 0 ? item.later : /* @__PURE__ */ new Set([...item.later, ...hidden]),
|
|
2986
3057
|
address: slot.address === true,
|
|
2987
3058
|
slot: slot.path,
|
|
2988
|
-
parent: here
|
|
3059
|
+
parent: here,
|
|
3060
|
+
caps: item.caps === void 0 || kind.caps === void 0 ? item.caps : partCaps(kind.caps, slot.path, item.caps)
|
|
2989
3061
|
});
|
|
2990
3062
|
}
|
|
2991
3063
|
}
|
|
@@ -3073,6 +3145,15 @@ function mapRefs(world, doc, change, options = {}) {
|
|
|
3073
3145
|
return out;
|
|
3074
3146
|
}
|
|
3075
3147
|
/**
|
|
3148
|
+
* This function gives the reason of a `#CAP!`. When a kind around the document narrowed the capabilities, the
|
|
3149
|
+
* reason names the nearest such kind.
|
|
3150
|
+
*/
|
|
3151
|
+
function capReason(v, kind) {
|
|
3152
|
+
const text = kind.join(".");
|
|
3153
|
+
for (let up = v.parent; up !== void 0; up = up.parent) if (up.caps !== void 0 && permits(up.caps, kind)) return `The capabilities do not permit the effect ${text} here. The kind ${typeName(up.doc.type)} around it narrows them for its parts.`;
|
|
3154
|
+
return `The capabilities do not permit the effect ${text}.`;
|
|
3155
|
+
}
|
|
3156
|
+
/**
|
|
3076
3157
|
* This function checks a document before an evaluation, by the contracts of its kinds. It finds the problems
|
|
3077
3158
|
* that an evaluation finds when it reaches them:
|
|
3078
3159
|
*
|
|
@@ -3083,7 +3164,7 @@ function mapRefs(world, doc, change, options = {}) {
|
|
|
3083
3164
|
* - `#DEPTH!`: too much nesting.
|
|
3084
3165
|
* - `#REF!` and `#STEP?`: a bad path.
|
|
3085
3166
|
* - `#NAME?`: a name that nothing binds.
|
|
3086
|
-
* - `#CAP!`: an effect that the capabilities do not permit.
|
|
3167
|
+
* - `#CAP!`: an effect that the capabilities of its document do not permit. A kind around the document can narrow them.
|
|
3087
3168
|
*
|
|
3088
3169
|
* @param machine - The world and the code of the evaluators.
|
|
3089
3170
|
* @param doc - The document, as JSON.
|
|
@@ -3124,12 +3205,13 @@ function check(machine, doc, options = {}) {
|
|
|
3124
3205
|
reason: `No rung gives an evaluator for ${typeName(v.doc.type)}.`,
|
|
3125
3206
|
at: v.at
|
|
3126
3207
|
});
|
|
3127
|
-
|
|
3208
|
+
const caps = v.caps;
|
|
3209
|
+
if (caps !== void 0 && v.kind?.effects !== void 0) {
|
|
3128
3210
|
const kinds = v.kind.effects === "type" ? [v.typePath ?? []] : v.kind.effects.map((kind) => kind.split("."));
|
|
3129
|
-
for (const kind of kinds) if (!permits(
|
|
3211
|
+
for (const kind of kinds) if (!permits(caps, kind)) issues.push({
|
|
3130
3212
|
code: "#CAP!",
|
|
3131
3213
|
place: v.place,
|
|
3132
|
-
reason:
|
|
3214
|
+
reason: capReason(v, kind),
|
|
3133
3215
|
at: v.at
|
|
3134
3216
|
});
|
|
3135
3217
|
}
|
|
@@ -3187,6 +3269,7 @@ function check(machine, doc, options = {}) {
|
|
|
3187
3269
|
}, {
|
|
3188
3270
|
...options.declaredType === void 0 ? {} : { declaredType: options.declaredType },
|
|
3189
3271
|
...Array.isArray(options.names) ? { names: options.names } : {},
|
|
3272
|
+
...options.caps === void 0 ? {} : { caps: options.caps },
|
|
3190
3273
|
problem: (problem) => issues.push({
|
|
3191
3274
|
code: problem.code,
|
|
3192
3275
|
place: problem.place,
|
|
@@ -3712,6 +3795,6 @@ function formulaMachine(profile = {}, more = {}) {
|
|
|
3712
3795
|
};
|
|
3713
3796
|
}
|
|
3714
3797
|
//#endregion
|
|
3715
|
-
export { CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, ask, capKeys, check, checkSteps, classify, context, dataEdges, derefStep, describe, docEquals, effectEdges, entriesAsJson, evaluate, fail, failures, field, flatten, formulaEvaluators, formulaKinds, formulaMachine, fromJson, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, narrow, nearestWalker, nodeAt, ok, pathMatches, permits, placed, planner, prepare, ref, refsOf, resolve, run, splitParts, stored, tag, thrown, toJson, typeName, typePath, typed, valueOfThing, walk, worldThing };
|
|
3798
|
+
export { CONSTRUCTS, ENVELOPE_KEYS, Failure, Held, PARTS, PART_INFO, ROOTS, RUNGS, STD_CAPS, STD_EVALUATORS, STD_EXT, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD, THING, ask, capKeys, check, checkSteps, classify, context, dataEdges, derefStep, describe, docEquals, effectEdges, entriesAsJson, evaluate, fail, failures, field, flatten, formulaEvaluators, formulaKinds, formulaMachine, fromJson, intersectCaps, isAlias, isAllowedOrder, isClosure, isEnvelope, isHostThing, isKey, isKind, isNamespace, isRecord, isRef, isStackOverflow, isTypeRef, jsTruthy, kindDocument, kindNamed, kindOf, layers, looksLikeKind, lookupKind, makeContext, mapRefs, narrow, nearestWalker, nodeAt, ok, partCaps, pathMatches, permits, placed, planner, prepare, ref, refsOf, resolve, run, splitParts, stored, tag, thrown, toJson, typeName, typePath, typed, valueOfThing, walk, worldThing };
|
|
3716
3799
|
|
|
3717
3800
|
//# sourceMappingURL=index.js.map
|