@mark1russell7/coeval 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/build/index.d.ts +828 -249
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3138 -386
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/agree.ts +193 -21
- package/src/conform.ts +49 -5
- package/src/deref.ts +97 -14
- package/src/evaluate.ts +311 -35
- package/src/facts.ts +113 -78
- package/src/formula.ts +55 -10
- package/src/index.ts +33 -1
- package/src/meaning.ts +472 -0
- package/src/merge.ts +46 -14
- package/src/reads.ts +9 -2
- package/src/reference.ts +90 -14
- package/src/replay.ts +964 -18
- package/src/schedule.ts +14 -4
- package/src/static.ts +2 -2
- package/src/stdlib.ts +81 -6
- package/src/syntax.ts +357 -52
- package/src/types.ts +443 -16
package/src/facts.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { type Json, type Key, isEnvelope, isKey } from "./doc.ts";
|
|
2
|
-
import { type Kind, type LazyRule, type Side, type World, lookupKind } from "./world.ts";
|
|
2
|
+
import { type Kind, type LazyRule, type Side, type World, equationType, lookupKind } from "./world.ts";
|
|
3
3
|
import { answerOf } from "./ladder.ts";
|
|
4
4
|
import { pathMatches, splitParts } from "./parts.ts";
|
|
5
5
|
import { type Root, ROOTS, isRef } from "./deref.ts";
|
|
6
6
|
import type { Machine } from "./evaluate.ts";
|
|
7
|
-
import { type DocVisit, declaredEffects, walk } from "./static.ts";
|
|
7
|
+
import { type DocVisit, type WalkOptions, declaredEffects, equationsOf, walk } from "./static.ts";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* One read of a document: a free reference, with its marks (FACTS.READS). A plan resolves the path of the reference
|
|
@@ -27,9 +27,12 @@ export interface StaticRead {
|
|
|
27
27
|
readonly address: boolean;
|
|
28
28
|
/** The path of the reference: its root and its steps. */
|
|
29
29
|
readonly path: readonly Json[];
|
|
30
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* The keys from the root document to the reference document, through the parts. A read of an equation has the
|
|
32
|
+
* place of the first document of its tree kind (FACTS.EQUATIONS).
|
|
33
|
+
*/
|
|
31
34
|
readonly place: readonly Key[];
|
|
32
|
-
/** The keys from the root JSON value to the reference document. */
|
|
35
|
+
/** The keys from the root JSON value to the reference document, or to the document of the kind for an equation. */
|
|
33
36
|
readonly at: readonly Key[];
|
|
34
37
|
}
|
|
35
38
|
|
|
@@ -151,9 +154,11 @@ function partLazy(above: Above, parent: DocVisit, slot: readonly Key[]): boolean
|
|
|
151
154
|
*
|
|
152
155
|
* - `reads`: each free reference, with the root and the keys of its path. A read under a lazy part has the mark
|
|
153
156
|
* `lazy`, for example a read in a branch of `if`. A read after a step document has `exact: false`. A kind that
|
|
154
|
-
* declares `reads` adds a read of each of its roots at each document of the kind.
|
|
157
|
+
* declares `reads` adds a read of each of its roots at each document of the kind. The first document of a tree
|
|
158
|
+
* kind also gets the lazy reads of the equations of its kind (FACTS.EQUATIONS). A read from `self` or from a name
|
|
159
|
+
* of a rung is not one of them, because it is not free (READS.EQUATION).
|
|
155
160
|
* - `side` and `effects`: from the contract of each kind.
|
|
156
|
-
* - `pure`: each kind declares `pure`, and the document has no effect and is not volatile.
|
|
161
|
+
* - `pure`: each kind declares `pure`, also in an equation, and the document has no effect and is not volatile.
|
|
157
162
|
* - `volatile`: a kind, an operation or a step document declares `volatile`, or the host marks a read.
|
|
158
163
|
*
|
|
159
164
|
* The hook `facts` of the machine answers for a name that a fallback kind covers, for example an operation. Its
|
|
@@ -177,7 +182,6 @@ function partLazy(above: Above, parent: DocVisit, slot: readonly Key[]): boolean
|
|
|
177
182
|
export function factsOf(machine: Machine, doc: unknown, options: FactsOptions = {}): DocFacts {
|
|
178
183
|
const world = machine.world;
|
|
179
184
|
const hook = machine.facts;
|
|
180
|
-
const verb = options.verb ?? "eval";
|
|
181
185
|
const reads: StaticRead[] = [];
|
|
182
186
|
const effects: string[] = [];
|
|
183
187
|
const above = new Map<DocVisit, Above>();
|
|
@@ -185,82 +189,113 @@ export function factsOf(machine: Machine, doc: unknown, options: FactsOptions =
|
|
|
185
189
|
let pure = true;
|
|
186
190
|
let volatile = false;
|
|
187
191
|
let size = 0;
|
|
192
|
+
// The tree kinds whose equations the facts walked. The first document of each such kind gets their reads (FACTS.EQUATIONS).
|
|
193
|
+
let seen: Set<Kind> | undefined;
|
|
188
194
|
const note = (isPure: boolean | undefined, isVolatile: boolean | undefined): void => {
|
|
189
195
|
if (isPure !== true) pure = false;
|
|
190
196
|
if (isVolatile === true) volatile = true;
|
|
191
197
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
} else {
|
|
214
|
-
// The contract of the kind does not describe this code. Only the hook can.
|
|
215
|
-
note(answer?.pure, answer?.volatile);
|
|
216
|
-
above.set(v, { lazy, rules: answer?.lazy ?? EACH });
|
|
217
|
-
roots = answer?.reads;
|
|
218
|
-
}
|
|
219
|
-
// The code of the kind resolves each of these roots as a whole, at the place of its document (FACTS.KIND-READS).
|
|
220
|
-
for (const root of roots ?? NONE) {
|
|
221
|
-
const read: StaticRead = { root, keys: NONE, exact: true, lazy, address: false, path: [root], place: tight(v.place), at: tight(v.at) };
|
|
222
|
-
reads.push(read);
|
|
223
|
-
if (options.volatile?.(read) === true) volatile = true;
|
|
224
|
-
}
|
|
225
|
-
if (kind.side === "run") side = "run";
|
|
226
|
-
// check and effectsOf read the declared effects with the same function (D27).
|
|
227
|
-
for (const keys of declaredEffects(v)) {
|
|
228
|
-
const text = keys.join(".");
|
|
229
|
-
if (!effects.includes(text)) effects.push(text);
|
|
230
|
-
}
|
|
231
|
-
if (!isRef(v.doc)) return undefined;
|
|
232
|
-
const path = v.doc.value;
|
|
233
|
-
const root = path[0];
|
|
234
|
-
if (typeof root !== "string" || !(ROOTS as readonly string[]).includes(root)) return undefined;
|
|
235
|
-
let exact = true;
|
|
236
|
-
const keys: Key[] = [];
|
|
237
|
-
for (let index = 1; index < path.length; index += 1) {
|
|
238
|
-
const step = path[index];
|
|
239
|
-
if (exact && isKey(step)) {
|
|
240
|
-
keys.push(step);
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
exact = false;
|
|
244
|
-
// A step document runs the walker that the ladder finds for the verb step.
|
|
245
|
-
const found = isEnvelope(step) ? lookupKind(world, step.type) : undefined;
|
|
246
|
-
if (found?.ok !== true) {
|
|
198
|
+
const add = (read: StaticRead): void => {
|
|
199
|
+
reads.push(read);
|
|
200
|
+
if (options.volatile?.(read) === true) volatile = true;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* This function walks a document. Without `node`, it walks the document of the facts. With `node`, it walks an
|
|
204
|
+
* equation of a tree kind, and each read gets the place of that node: the first document of the kind.
|
|
205
|
+
*/
|
|
206
|
+
const scan = (term: unknown, walkOptions: WalkOptions, verb: string, node: DocVisit | undefined): void => {
|
|
207
|
+
walk(
|
|
208
|
+
world,
|
|
209
|
+
term,
|
|
210
|
+
(v) => {
|
|
211
|
+
if (node === undefined) size += 1;
|
|
212
|
+
const up = v.parent === undefined ? undefined : above.get(v.parent);
|
|
213
|
+
// An equation evaluates only when a demand reaches its attribute, thus each read of an equation is lazy (TREE.LAZY).
|
|
214
|
+
const lazy = node !== undefined || (up !== undefined && v.parent !== undefined && (up.lazy || partLazy(up, v.parent, v.slot)));
|
|
215
|
+
const place = node ?? v;
|
|
216
|
+
const kind = v.kind;
|
|
217
|
+
if (kind === undefined) {
|
|
218
|
+
// A kind that the world does not have gives #KIND?, and the walk does not visit its value.
|
|
247
219
|
pure = false;
|
|
248
|
-
|
|
220
|
+
above.set(v, { lazy, rules: undefined });
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
const code = codeOf(world, v.declared ? undefined : v.doc.own, kind, verb, "eval");
|
|
224
|
+
const answer = code.name === undefined ? undefined : hook?.(v.typePath ?? [], code.name);
|
|
225
|
+
let roots: readonly Root[] | undefined;
|
|
226
|
+
if (code.described) {
|
|
227
|
+
note(answer?.pure ?? kind.pure, answer?.volatile ?? kind.volatile);
|
|
228
|
+
above.set(v, { lazy, rules: answer?.lazy ?? kind.lazy });
|
|
229
|
+
roots = answer?.reads ?? kind.reads;
|
|
230
|
+
} else {
|
|
231
|
+
// The contract of the kind does not describe this code. Only the hook can.
|
|
232
|
+
note(answer?.pure, answer?.volatile);
|
|
233
|
+
above.set(v, { lazy, rules: answer?.lazy ?? EACH });
|
|
234
|
+
roots = answer?.reads;
|
|
249
235
|
}
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
236
|
+
// The code of the kind resolves each of these roots as a whole, at the place of its document (FACTS.KIND-READS).
|
|
237
|
+
for (const root of roots ?? NONE) {
|
|
238
|
+
// In an equation, the root self is the node, thus its read is not free (READS.EQUATION).
|
|
239
|
+
if (node !== undefined && root === "self") continue;
|
|
240
|
+
add({ root, keys: NONE, exact: true, lazy, address: false, path: [root], place: tight(place.place), at: tight(place.at) });
|
|
241
|
+
}
|
|
242
|
+
// An equation evaluates without capabilities, thus an effect in it never reaches the host. It is still not pure.
|
|
243
|
+
if (kind.side === "run") {
|
|
244
|
+
if (node === undefined) side = "run";
|
|
245
|
+
else pure = false;
|
|
246
|
+
}
|
|
247
|
+
// check and effectsOf read the declared effects with the same function (D27).
|
|
248
|
+
for (const keys of declaredEffects(v)) {
|
|
249
|
+
if (node !== undefined) {
|
|
250
|
+
pure = false;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const text = keys.join(".");
|
|
254
|
+
if (!effects.includes(text)) effects.push(text);
|
|
255
|
+
}
|
|
256
|
+
// The equations of a tree kind are code of the kind. The first document of the kind gets their reads (FACTS.EQUATIONS).
|
|
257
|
+
if (kind.tree !== undefined && !(seen ??= new Set()).has(kind)) {
|
|
258
|
+
seen.add(kind);
|
|
259
|
+
const of = equationType(kind);
|
|
260
|
+
for (const { term: equation, names } of equationsOf(kind)) scan(equation, of === undefined ? { names } : { names, declaredType: of }, "eval", place);
|
|
261
|
+
}
|
|
262
|
+
if (!isRef(v.doc)) return undefined;
|
|
263
|
+
const path = v.doc.value;
|
|
264
|
+
const root = path[0];
|
|
265
|
+
if (typeof root !== "string" || !(ROOTS as readonly string[]).includes(root)) return undefined;
|
|
266
|
+
// In an equation, the root self is the node, thus its read is not free. A step out of the tree reads the outer
|
|
267
|
+
// self through the node, and the read of the whole root self that the tree node makes covers it (TREE.SELF).
|
|
268
|
+
if (node !== undefined && root === "self") return undefined;
|
|
269
|
+
let exact = true;
|
|
270
|
+
const keys: Key[] = [];
|
|
271
|
+
for (let index = 1; index < path.length; index += 1) {
|
|
272
|
+
const step = path[index];
|
|
273
|
+
if (exact && isKey(step)) {
|
|
274
|
+
keys.push(step);
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
exact = false;
|
|
278
|
+
// A step document runs the walker that the ladder finds for the verb step.
|
|
279
|
+
const found = isEnvelope(step) ? lookupKind(world, step.type) : undefined;
|
|
280
|
+
if (found?.ok !== true) {
|
|
281
|
+
pure = false;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
const walker = codeOf(world, (step as { readonly own?: Readonly<Record<string, string>> }).own, found.kind, "step", "step");
|
|
285
|
+
const stepAnswer = walker.name === undefined ? undefined : hook?.(found.path, walker.name);
|
|
286
|
+
if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
|
|
287
|
+
else note(stepAnswer?.pure, stepAnswer?.volatile);
|
|
288
|
+
}
|
|
289
|
+
const first = path[1];
|
|
290
|
+
// A reference to a name that a kind around it binds reads inside the document: it is not a read. The names of
|
|
291
|
+
// an equation are names that its rung binds (TREE.DOWN, TREE.FOLD).
|
|
292
|
+
if (root === "names" && isKey(first) && v.names.has(String(first))) return undefined;
|
|
293
|
+
add({ root: root as Root, keys: tight(keys), exact, lazy, address: v.address === true, path, place: tight(place.place), at: tight(place.at) });
|
|
294
|
+
return undefined;
|
|
295
|
+
},
|
|
296
|
+
walkOptions,
|
|
297
|
+
);
|
|
298
|
+
};
|
|
299
|
+
scan(doc, options.declaredType === undefined ? {} : { declaredType: options.declaredType }, options.verb ?? "eval", undefined);
|
|
265
300
|
return { reads: tight(reads), side, effects: tight(effects), pure: pure && !volatile && effects.length === 0 && side === "derive", volatile, size };
|
|
266
301
|
}
|
package/src/formula.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { type CompiledPath, type Context, type Resolution, compilePath, valueOfT
|
|
|
4
4
|
import { type EvalError, type Failed, type Result, Failure, fail, ok, thrown } from "./errors.ts";
|
|
5
5
|
import { type Code, type CompileInput, type CompiledEvaluator, type CompiledPart, type Evaluator, type Machine, type Runtime, resolveCompiled, totalCode } from "./evaluate.ts";
|
|
6
6
|
import { type MachinePart, mergeMachines } from "./merge.ts";
|
|
7
|
-
import { type Domain, type ValueType, HEADER_KEYS, STD_DOMAINS, callable, fieldOf, fits, fnOf, holdsEnvelope, isPrecise, isUnknown, itemOf, join, member, stepType, typeText } from "./types.ts";
|
|
8
|
-
import type { TypeInput, TypeRule } from "./typing.ts";
|
|
7
|
+
import { type Domain, type ValueType, HEADER_KEYS, STD_DOMAINS, callable, fieldOf, fits, fnOf, holdsEnvelope, isPrecise, isUnknown, itemOf, join, member, stepType, typeIssues, typeText } from "./types.ts";
|
|
8
|
+
import type { PartType, TypeInput, TypeRule } from "./typing.ts";
|
|
9
9
|
import { decodeDomain, domainTypeOf } from "./codec.ts";
|
|
10
10
|
import { type StaticRead, factsOf } from "./facts.ts";
|
|
11
11
|
|
|
@@ -33,6 +33,9 @@ export type ExtFn = (data: Json, context: Context, domains?: Readonly<Record<str
|
|
|
33
33
|
* `ext.domain`.
|
|
34
34
|
* - `truthy`: the truth of a value for `if`, `and` and `or`. `undefined` is an error `#VALUE!`. The default
|
|
35
35
|
* accepts only `true` and `false`.
|
|
36
|
+
* - `truthType`: the value type of a truth for the own `truthy`, for a check of types (TYPE.TRUTH, D81). A test of
|
|
37
|
+
* `if` and each term of `and` and `or` must fit it. Without it, the check accepts each type there. A profile without
|
|
38
|
+
* `truthy` ignores it, because the default truth needs `bool`.
|
|
36
39
|
* - `otherwise`: the value of an `if` without `else`. The default is `null`. A profile with this key gives its value,
|
|
37
40
|
* also `undefined`.
|
|
38
41
|
* - `logic`: what `and` and `or` give: a truth value (the default), or the value that decided.
|
|
@@ -50,13 +53,15 @@ export type ExtFn = (data: Json, context: Context, domains?: Readonly<Record<str
|
|
|
50
53
|
* overloads. An operation without a signature takes and gives `unknown` (TYPE.GRADUAL).
|
|
51
54
|
*
|
|
52
55
|
* A check of types trusts the signatures. Each operation must give a member of the result of each signature that
|
|
53
|
-
* its arguments match. The hook `check` must keep each result in that type.
|
|
56
|
+
* its arguments match. The hook `check` must keep each result in that type. The function `truthy` must give a truth
|
|
57
|
+
* for each member of `truthType`.
|
|
54
58
|
*/
|
|
55
59
|
export interface FormulaProfile {
|
|
56
60
|
readonly ops?: Readonly<Record<string, OpFn>> | ((name: string) => OpFn | undefined);
|
|
57
61
|
readonly lazy?: Readonly<Record<string, LazyOp>>;
|
|
58
62
|
readonly ext?: Readonly<Record<string, ExtFn>>;
|
|
59
63
|
readonly truthy?: (value: unknown) => boolean | undefined;
|
|
64
|
+
readonly truthType?: ValueType;
|
|
60
65
|
readonly otherwise?: unknown;
|
|
61
66
|
readonly logic?: "boolean" | "value";
|
|
62
67
|
readonly omit?: (error: EvalError) => boolean;
|
|
@@ -266,12 +271,23 @@ function paramsOf(value: unknown): readonly string[] {
|
|
|
266
271
|
|
|
267
272
|
/**
|
|
268
273
|
* This function makes the type rules of the formula kit for one profile (TYPE.SYNTH, D25). Each evaluator of the kit
|
|
269
|
-
* holds its rule. The rules read the rules of the profile that change a type: `truthy`, `
|
|
270
|
-
* and `sigs`.
|
|
274
|
+
* holds its rule. The rules read the rules of the profile that change a type: `truthy`, `truthType`, `logic`,
|
|
275
|
+
* `otherwise`, `omit` and `sigs`.
|
|
271
276
|
*/
|
|
272
277
|
function formulaTypes(profile: FormulaProfile): Readonly<Record<string, TypeRule>> {
|
|
273
|
-
//
|
|
274
|
-
const
|
|
278
|
+
// The default truth needs a truth value. An own truth needs its declared type, or nothing without a declaration (D81).
|
|
279
|
+
const declared = profile.truthy !== undefined && profile.truthType !== undefined;
|
|
280
|
+
const truth: ValueType | undefined = profile.truthy === undefined ? "bool" : profile.truthType;
|
|
281
|
+
/**
|
|
282
|
+
* The need of a test or a term. The check examines a declared type of a truth as a contract, one time. A declared
|
|
283
|
+
* type with a problem needs nothing, thus one problem gives one issue.
|
|
284
|
+
*/
|
|
285
|
+
const truthPart = (input: TypeInput, what: string): PartType => {
|
|
286
|
+
if (truth === undefined) return {};
|
|
287
|
+
if (!declared) return { expect: truth, what };
|
|
288
|
+
const type = input.contract(truth, "truth type of the profile");
|
|
289
|
+
return typeIssues(type, input.machine.domains).length > 0 ? {} : { expect: type, what };
|
|
290
|
+
};
|
|
275
291
|
const logicValue = profile.logic === "value";
|
|
276
292
|
const otherwise = Object.hasOwn(profile, "otherwise") ? valueType(profile.otherwise) : "null";
|
|
277
293
|
const lookup = (name: string): readonly unknown[] | undefined => {
|
|
@@ -307,7 +323,7 @@ function formulaTypes(profile: FormulaProfile): Readonly<Record<string, TypeRule
|
|
|
307
323
|
return { sigs, bad: sigs.length !== raw.length };
|
|
308
324
|
};
|
|
309
325
|
const logic = (word: "and" | "or"): TypeRule => ({
|
|
310
|
-
part: (
|
|
326
|
+
part: (input, path) => truthPart(input, `term ${Number(path[0]) + 1} of ${word}`),
|
|
311
327
|
synth: (input) => {
|
|
312
328
|
if (!logicValue) return "bool";
|
|
313
329
|
// With the logic "value", the result is the term that decided, or the last term.
|
|
@@ -438,7 +454,7 @@ function formulaTypes(profile: FormulaProfile): Readonly<Record<string, TypeRule
|
|
|
438
454
|
|
|
439
455
|
"formula.if": {
|
|
440
456
|
part: (input, path) => {
|
|
441
|
-
if (path[0] === "test") return
|
|
457
|
+
if (path[0] === "test") return truthPart(input, "test of if");
|
|
442
458
|
return isUnknown(input.expected, input.machine.domains) ? {} : { expect: input.expected, what: `${String(path[0])} branch of if` };
|
|
443
459
|
},
|
|
444
460
|
synth: (input) => {
|
|
@@ -518,15 +534,43 @@ export function formulaEvaluators(profile: FormulaProfile = {}): Readonly<Record
|
|
|
518
534
|
return { ...kitOf(profile).evaluators };
|
|
519
535
|
}
|
|
520
536
|
|
|
537
|
+
/** The declared truth of a profile: its own `truthy` and its `truthType` (D81). */
|
|
538
|
+
export interface DeclaredTruth {
|
|
539
|
+
readonly truthy: (value: unknown) => boolean | undefined;
|
|
540
|
+
readonly truthType: ValueType;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/** The evaluators of the kit that read the truth of a value. */
|
|
544
|
+
const TRUTH_READERS: readonly string[] = ["formula.if", "formula.and", "formula.or"];
|
|
545
|
+
|
|
546
|
+
/** The declared truth of each evaluator of the kit that reads a truth, for `conforms` (D86). */
|
|
547
|
+
const truthByCode = /* @__PURE__ */ new WeakMap<object, DeclaredTruth>();
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* This function gives the declared truth of the profile of an evaluator of the kit (D86). Only `formula.if`,
|
|
551
|
+
* `formula.and` and `formula.or` of a profile with an own `truthy` and a `truthType` have one. The kernel does not
|
|
552
|
+
* export the function.
|
|
553
|
+
*
|
|
554
|
+
* @param code - The evaluator or the runner.
|
|
555
|
+
* @returns The declared truth, or `undefined`.
|
|
556
|
+
*/
|
|
557
|
+
export function declaredTruthOf(code: unknown): DeclaredTruth | undefined {
|
|
558
|
+
return (typeof code === "object" || typeof code === "function") && code !== null ? truthByCode.get(code) : undefined;
|
|
559
|
+
}
|
|
560
|
+
|
|
521
561
|
/** This function makes new evaluators of the formula kit for the fields of one profile. */
|
|
522
562
|
function makeEvaluators(profile: FormulaProfile): Readonly<Record<string, Evaluator>> {
|
|
523
563
|
const evaluators = formulaCode(profile);
|
|
524
564
|
const types = formulaTypes(profile);
|
|
565
|
+
const { truthy, truthType } = profile;
|
|
566
|
+
const truth = truthy === undefined || truthType === undefined ? undefined : { truthy, truthType };
|
|
525
567
|
const out: Record<string, Evaluator> = {};
|
|
526
568
|
for (const name of Object.keys(evaluators)) {
|
|
527
569
|
const evaluator = evaluators[name] as CompiledEvaluator;
|
|
528
570
|
const type = Object.hasOwn(types, name) ? types[name] : undefined;
|
|
529
|
-
|
|
571
|
+
const made = Object.freeze(type === undefined ? evaluator : { compile: evaluator.compile, type });
|
|
572
|
+
if (truth !== undefined && TRUTH_READERS.includes(name)) truthByCode.set(made, truth);
|
|
573
|
+
out[name] = made;
|
|
530
574
|
}
|
|
531
575
|
return Object.freeze(out);
|
|
532
576
|
}
|
|
@@ -537,6 +581,7 @@ const PROFILE_KEYS = /* @__PURE__ */ Object.freeze([
|
|
|
537
581
|
"lazy",
|
|
538
582
|
"ext",
|
|
539
583
|
"truthy",
|
|
584
|
+
"truthType",
|
|
540
585
|
"otherwise",
|
|
541
586
|
"logic",
|
|
542
587
|
"omit",
|
package/src/index.ts
CHANGED
|
@@ -174,8 +174,10 @@ export {
|
|
|
174
174
|
STD_RUNNERS,
|
|
175
175
|
STD_WALKERS,
|
|
176
176
|
STD_WORLD,
|
|
177
|
+
WORLD_SYNTAX,
|
|
177
178
|
attributeTrace,
|
|
178
179
|
nearestWalker,
|
|
180
|
+
placeOf,
|
|
179
181
|
} from "./stdlib.ts";
|
|
180
182
|
export {
|
|
181
183
|
type Edge,
|
|
@@ -237,8 +239,11 @@ export {
|
|
|
237
239
|
type ParseResult,
|
|
238
240
|
type SyntaxAssoc,
|
|
239
241
|
type SyntaxCalls,
|
|
242
|
+
type SyntaxEnvelopes,
|
|
240
243
|
type SyntaxFixity,
|
|
241
244
|
type SyntaxForm,
|
|
245
|
+
type SyntaxFormArgs,
|
|
246
|
+
type SyntaxHeader,
|
|
242
247
|
type SyntaxIssue,
|
|
243
248
|
type SyntaxLiterals,
|
|
244
249
|
type SyntaxOperator,
|
|
@@ -266,8 +271,35 @@ export {
|
|
|
266
271
|
edgesOf,
|
|
267
272
|
schedule,
|
|
268
273
|
} from "./schedule.ts";
|
|
274
|
+
export {
|
|
275
|
+
type AgreeScheduleOptions,
|
|
276
|
+
type ScheduleAgreement,
|
|
277
|
+
type ScheduleAgreementCounts,
|
|
278
|
+
type ScheduleEngine,
|
|
279
|
+
type ScheduleEngineFactory,
|
|
280
|
+
type ScheduleEngineStart,
|
|
281
|
+
agreeSchedule,
|
|
282
|
+
} from "./meaning.ts";
|
|
269
283
|
export { type GraphCycle, type GraphEdge, type GraphNode, type GraphOptions, type NodeGraph, components, cycles, heights, necessary, nodeLayers } from "./graph.ts";
|
|
270
|
-
export {
|
|
284
|
+
export {
|
|
285
|
+
type Recorder,
|
|
286
|
+
type ReplayCausePartsJson,
|
|
287
|
+
type ReplayEntry,
|
|
288
|
+
type ReplayEntryJson,
|
|
289
|
+
type ReplayErrorJson,
|
|
290
|
+
type ReplayExceptionJson,
|
|
291
|
+
type ReplayLog,
|
|
292
|
+
type ReplayLogJson,
|
|
293
|
+
type ReplayPartJson,
|
|
294
|
+
type ReplayPartsJson,
|
|
295
|
+
type ReplayOptions,
|
|
296
|
+
type ReplayResultJson,
|
|
297
|
+
type ReplaySettle,
|
|
298
|
+
decodeLog,
|
|
299
|
+
encodeLog,
|
|
300
|
+
recorder,
|
|
301
|
+
replayer,
|
|
302
|
+
} from "./replay.ts";
|
|
271
303
|
export { type GenerateOptions, type Random, generate, random, typesOf } from "./generate.ts";
|
|
272
304
|
export { type Domain, type DomainCodec, type TypeIssue, type ValueType, STD_DOMAINS, fits, join, member, typeIssues, typeText } from "./types.ts";
|
|
273
305
|
export { type PartType, type RootTypes, type TypeInput, type TypeProblem, type TypeRule, type Typed, CAPS_TYPE } from "./typing.ts";
|