@mark1russell7/coeval 0.25.1 → 0.26.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/coeval",
4
- "version": "0.25.1",
4
+ "version": "0.26.0",
5
5
  "description": "coeval: the kernel of declarative languages. Documents in envelopes, a ladder that finds the evaluator, kind contracts, compiled plans, a static kit, a formula kit and a run side with capabilities.",
6
6
  "type": "module",
7
7
  "main": "./build/index.js",
package/src/agree.ts CHANGED
@@ -5,8 +5,9 @@ import { type CheckOptions, typeCheck } from "./static.ts";
5
5
  import { isPrecise, member, typeText } from "./types.ts";
6
6
  import { boundariesOf } from "./typing.ts";
7
7
  import { type Effect, type Machine, type Perform, type Read, type TraceNode, JOURNAL, evaluate, makeContext, prepare, run, sharedCopy } from "./evaluate.ts";
8
- import { Held, isClosure } from "./formula.ts";
8
+ import { type FormulaProfile, Held, isClosure } from "./formula.ts";
9
9
  import { type Definitions, reference, referenceRun } from "./reference.ts";
10
+ import { stepper } from "./stepper.ts";
10
11
  import { type ReplaySettle, recorder, relay, replayer } from "./replay.ts";
11
12
 
12
13
  /**
@@ -21,7 +22,7 @@ import { type ReplaySettle, recorder, relay, replayer } from "./replay.ts";
21
22
  * each such name, and then with the context of `agree`. `agreeRun` does not have this tier.
22
23
  * - `other`: the second tier of a language, from the option `other`.
23
24
  */
24
- export type Tier = "reference" | "traced" | "again" | "folds" | "fixed" | "other";
25
+ export type Tier = "reference" | "traced" | "again" | "folds" | "fixed" | "stepper" | "other";
25
26
 
26
27
  /** What a second tier gives: its result, and its effects when it records them. */
27
28
  export interface TierResult {
@@ -51,9 +52,11 @@ export interface AgreeOptions {
51
52
  readonly definitions?: Definitions;
52
53
  /**
53
54
  * The tiers to compare with the plan. The default is the reference, the traced evaluation, a second evaluation, the
54
- * plan with the other choice of folds and the plan with fixed names.
55
+ * plan with the other choice of folds and the plan with fixed names. The tier `stepper` is not a default.
55
56
  */
56
57
  readonly tiers?: readonly Exclude<Tier, "other">[];
58
+ /** The profile of the formula kit, for the tier `stepper`. */
59
+ readonly profile?: FormulaProfile;
57
60
  /**
58
61
  * This function gives the result of the second tier of a language, for example a compiler to loops.
59
62
  *
@@ -290,6 +293,8 @@ export function agree(machine: Machine, doc: unknown, context: Context = makeCon
290
293
  let otherEffects: Effect[] = [];
291
294
  if (tier === "reference") {
292
295
  other = reference(machine, doc, context, { ...declared, ...mock, effects: otherEffects, ...(options.definitions === undefined ? {} : { definitions: options.definitions }) });
296
+ } else if (tier === "stepper") {
297
+ other = stepper(machine, doc, context, { ...declared, ...mock, effects: otherEffects, ...(options.profile === undefined ? {} : { profile: options.profile }), ...(options.definitions === undefined ? {} : { definitions: options.definitions }) });
293
298
  } else if (tier === "traced") {
294
299
  const traced = evaluate(machine, doc, context, { ...declared, ...mock });
295
300
  other = traced.result;
@@ -509,8 +514,8 @@ export async function agreeRun(machine: Machine, doc: unknown, context: Context
509
514
  const replay = replayer(log);
510
515
 
511
516
  for (const tier of options.tiers ?? DEFAULT_TIERS) {
512
- // A run has no tier with fixed names (PLAN.FIXED).
513
- if (tier === "fixed") continue;
517
+ // A run has no tier with fixed names (PLAN.FIXED), and the stepper does no runs.
518
+ if (tier === "fixed" || tier === "stepper") continue;
514
519
  const tierReplay = watched(replay);
515
520
  const host = { perform: tierReplay.perform };
516
521
  let other: Result;
package/src/facts.ts CHANGED
@@ -185,7 +185,8 @@ export function codeFactsOf(machine: Machine, v: DocVisit, kind: Kind, verb: str
185
185
  *
186
186
  * - `reads`: each free reference, with the root and the keys of its path. A read under a lazy part has the mark
187
187
  * `lazy`, for example a read in a branch of `if`. A read after a step document has `exact: false`. A kind that
188
- * declares `reads` adds a read of each of its roots at each document of the kind. The first document of a tree
188
+ * declares `reads` adds a read of each of its roots at each document of the kind. A reference with a step document
189
+ * of the kind also has these reads (FACTS.STEP-READS). The first document of a tree
189
190
  * kind also gets the lazy reads of the equations of its kind (FACTS.EQUATIONS). A read from `self` or from a name
190
191
  * of a rung is not one of them, because it is not free (READS.EQUATION).
191
192
  * - `side` and `effects`: from the contract of each kind, for the verb of the facts.
@@ -232,6 +233,18 @@ export function factsOf(machine: Machine, doc: unknown, options: FactsOptions =
232
233
  reads.push(read);
233
234
  if (options.volatile?.(read) === true) volatile = true;
234
235
  };
236
+ /**
237
+ * This function adds a read of each declared root at the place of a document (FACTS.KIND-READS, FACTS.STEP-READS).
238
+ * It is one function for the facts, thus a visit makes no new function.
239
+ */
240
+ const declare = (list: readonly Root[] | undefined, node: DocVisit | undefined, lazy: boolean, place: DocVisit): void => {
241
+ if (list === undefined) return;
242
+ for (const root of list) {
243
+ // In an equation, the root self is the node, thus its read is not free (READS.EQUATION).
244
+ if (node !== undefined && root === "self") continue;
245
+ add({ root, keys: NONE, exact: true, lazy, address: false, path: [root], place: tight(place.place), at: tight(place.at) });
246
+ }
247
+ };
235
248
  /**
236
249
  * This function walks a document. Without `node`, it walks the document of the facts. With `node`, it walks an
237
250
  * equation of a tree kind, and each read gets the place of that node: the first document of the kind.
@@ -265,11 +278,7 @@ export function factsOf(machine: Machine, doc: unknown, options: FactsOptions =
265
278
  roots = answer?.reads;
266
279
  }
267
280
  // The code of the kind resolves each of these roots as a whole, at the place of its document (FACTS.KIND-READS).
268
- for (const root of roots ?? NONE) {
269
- // In an equation, the root self is the node, thus its read is not free (READS.EQUATION).
270
- if (node !== undefined && root === "self") continue;
271
- add({ root, keys: NONE, exact: true, lazy, address: false, path: [root], place: tight(place.place), at: tight(place.at) });
272
- }
281
+ declare(roots, node, lazy, place);
273
282
  // check and effectsOf read the declared effects with the same function (D27). The verb of the facts selects the
274
283
  // declaration: effects for eval, and the entry of verbEffects for another verb (D49, D111).
275
284
  // The answer of the hook for the code of eval wins over the contract, also for an own entry (D118).
@@ -322,6 +331,8 @@ export function factsOf(machine: Machine, doc: unknown, options: FactsOptions =
322
331
  const stepAnswer = walker.name === undefined ? undefined : hook?.(found.path, walker.name);
323
332
  if (walker.described) note(stepAnswer?.pure ?? found.kind.pure, stepAnswer?.volatile ?? found.kind.volatile);
324
333
  else note(stepAnswer?.pure, stepAnswer?.volatile);
334
+ // A walker can resolve a root of its own. The read has the place of the reference (FACTS.STEP-READS).
335
+ declare(stepAnswer?.reads ?? (walker.described ? found.kind.reads : undefined), node, lazy, place);
325
336
  }
326
337
  const first = path[1];
327
338
  // A reference to a name that a kind around it binds reads inside the document: it is not a read. The names of
package/src/formula.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type Json, type Key, docEquals, isKey, isRecord, typeName } from "./doc.ts";
2
2
  import { partsOf as docParts } from "./parts.ts";
3
3
  import type { Kind, KindFacts, LazyRule, WorldEntry } from "./world.ts";
4
- import { type CompiledPath, type Context, type Resolution, compilePath, valueOfThing, walkerOf } from "./deref.ts";
4
+ import { type CompiledPath, type Context, type Resolution, type Root, compilePath, valueOfThing, walkerOf } from "./deref.ts";
5
5
  import { type EvalError, type Failed, type Result, Failure, fail, ok, thrown } from "./errors.ts";
6
6
  import { type Code, type CompileInput, type CompiledEvaluator, type CompiledPart, type Evaluator, type Machine, type Runtime, resolveCompiled, totalCode } from "./evaluate.ts";
7
7
  import { type MachinePart, mergeMachines } from "./merge.ts";
@@ -51,6 +51,9 @@ export type ExtFn = (data: Json, context: Context, domains?: Readonly<Record<str
51
51
  * names no operation.
52
52
  * - `pureExt`: the pure extensions of `ext`, by their name, for `factsOf` and the folds of a plan (PLAN.FOLD, D47).
53
53
  * The default names no extension. A standard extension is pure without a name here.
54
+ * - `extReads`: the roots that an extension of `ext` reads from its context, by its name, for `factsOf`
55
+ * (FACTS.EXT-READS). A read of a root through the context refuses a fold, thus such a pure extension runs at each
56
+ * evaluation.
54
57
  * - `volatile`: the operations whose results can change while their arguments stay the same, for example a clock.
55
58
  * - `sigs`: the signatures of the operations, by their name, for a check of types (TYPE.SIGNATURE). A list gives
56
59
  * overloads. An operation without a signature takes and gives `unknown` (TYPE.GRADUAL).
@@ -74,6 +77,7 @@ export interface FormulaProfile {
74
77
  readonly combine?: (errors: readonly EvalError[]) => EvalError;
75
78
  readonly pure?: true | readonly string[];
76
79
  readonly pureExt?: readonly string[];
80
+ readonly extReads?: Readonly<Record<string, readonly Root[]>>;
77
81
  readonly volatile?: readonly string[];
78
82
  readonly sigs?: Readonly<Record<string, Signature | readonly Signature[]>> | ((name: string) => Signature | readonly Signature[] | undefined);
79
83
  }
@@ -776,6 +780,7 @@ const PROFILE_KEYS = /* @__PURE__ */ Object.freeze([
776
780
  "combine",
777
781
  "pure",
778
782
  "pureExt",
783
+ "extReads",
779
784
  "volatile",
780
785
  "sigs",
781
786
  ] as const satisfies readonly (keyof FormulaProfile)[]);
@@ -1285,7 +1290,11 @@ function makeFacts(profile: FormulaProfile, known: (path: readonly Key[], evalua
1285
1290
  if (code !== "formula.op" && code !== "formula.ext") return undefined;
1286
1291
  const name = path.slice(1).join(".");
1287
1292
  if (code === "formula.ext") {
1288
- if (profile.ext !== undefined && Object.hasOwn(profile.ext, name)) return pureExt.has(name) ? PURE : NOT_PURE;
1293
+ if (profile.ext !== undefined && Object.hasOwn(profile.ext, name)) {
1294
+ const facts = pureExt.has(name) ? PURE : NOT_PURE;
1295
+ const reads = profile.extReads !== undefined && Object.hasOwn(profile.extReads, name) ? profile.extReads[name] : undefined;
1296
+ return reads === undefined ? facts : { ...facts, reads };
1297
+ }
1289
1298
  return Object.hasOwn(STD_EXT, name) ? PURE : undefined;
1290
1299
  }
1291
1300
  // An operation that the language does not have gives #NAME?. The kit gives it no facts.
package/src/index.ts CHANGED
@@ -293,6 +293,7 @@ export {
293
293
  print,
294
294
  syntaxFormat,
295
295
  } from "./syntax.ts";
296
+ export { type Configuration, type Frame, type StepperOptions, stepper, stepperNext, stepperStart } from "./stepper.ts";
296
297
  export { type Definitions, type ReferenceOptions, type ReferenceRunOptions, STD_DEFINITIONS, formulaDefinitions, reference, referenceRun } from "./reference.ts";
297
298
  export { type AgreeOptions, type AgreeRunOptions, type Agreement, type AgreeTypesOptions, type TypeAgreement, agreeTypes, type Tier, type TierInput, type TierResult, agree, agreeRun, sameValue } from "./agree.ts";
298
299
  export { type ConformOptions, type ConformProbe, type Finding, type Obligation, conforms } from "./conform.ts";