@mark1russell7/coeval 0.3.2 → 0.3.3

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.3.2",
4
+ "version": "0.3.3",
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/evaluate.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type Envelope, type Json, type Key, type TypeRef, isEnvelope, typeName } from "./doc.ts";
2
- import { splitParts } from "./parts.ts";
2
+ import { type Split, splitParts } from "./parts.ts";
3
3
  import { ask, type Answer } from "./ladder.ts";
4
4
  import { type Lookup, type Side, type World, lookupKind } from "./world.ts";
5
5
  import { type ErrorCode, type EvalError, type Result, fail, ok, placed, thrown, describe } from "./errors.ts";
@@ -905,39 +905,70 @@ function compileNode(c: Compiler, value: unknown, place: readonly Key[], declare
905
905
  parts,
906
906
  place,
907
907
  machine: c.machine,
908
- fill: (items) => (split.parts.length === 0 ? doc.value : split.fill(items)),
908
+ fill: fillOf(split, doc),
909
909
  };
910
910
  if (runner !== undefined) {
911
911
  const inner: RunCode = isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill);
912
- const run: RunCode = function* (ctx, rt) {
913
- try {
914
- return placed(yield* inner(ctx, rt), place);
915
- } catch (error) {
916
- return placed(thrown(error, `the runner ${name}`), place);
917
- }
918
- };
919
- const code: Code = (ctx, rt) =>
920
- rt.running
921
- ? fail("#CALC!", `${kindText} waits for effects, and its parent cannot wait. Give the parent a runner.`, { place })
922
- : drive(run(ctx, rt));
923
- return finish(c, meta, code, run);
912
+ const run = placedRun(inner, place, name);
913
+ return finish(c, meta, runnerCode(run, place, kindText), run);
924
914
  }
925
915
 
926
916
  const inner: Code = isCompiledEvaluator(evaluator as Evaluator)
927
917
  ? (evaluator as CompiledEvaluator).compile(input)
928
918
  : interpret(evaluator as EvalFn, input, split.fill);
929
- const code: Code = (ctx, rt) => {
919
+ const code = placedCode(inner, place, name);
920
+ return finish(c, meta, code, runOf(code));
921
+ }
922
+
923
+ /*
924
+ * The helpers below make the closures that a plan keeps. Each one has its own small scope. A closure that a
925
+ * compilation made in its own scope keeps each variable of that scope that any closure there reads, for example
926
+ * the split of the value. Thus a plan with these helpers keeps only its code.
927
+ */
928
+
929
+ /** This function gives the code of a document: the code of its evaluator, with the place of each error and of each exception. */
930
+ function placedCode(inner: Code, place: readonly Key[], name: string): Code {
931
+ return (ctx, rt) => {
930
932
  try {
931
933
  return placed(inner(ctx, rt), place);
932
934
  } catch (error) {
933
935
  return placed(thrown(error, `the evaluator ${name}`), place);
934
936
  }
935
937
  };
936
- return finish(c, meta, code, function* (ctx, rt) {
938
+ }
939
+
940
+ /** This function gives the steps of a runner, with the place of each error and of each exception. */
941
+ function placedRun(inner: RunCode, place: readonly Key[], name: string): RunCode {
942
+ return function* (ctx, rt) {
943
+ try {
944
+ return placed(yield* inner(ctx, rt), place);
945
+ } catch (error) {
946
+ return placed(thrown(error, `the runner ${name}`), place);
947
+ }
948
+ };
949
+ }
950
+
951
+ /** This function gives the code of a runner in an evaluation: its steps, which cannot wait. */
952
+ function runnerCode(run: RunCode, place: readonly Key[], kindText: string): Code {
953
+ return (ctx, rt) =>
954
+ rt.running
955
+ ? fail("#CALC!", `${kindText} waits for effects, and its parent cannot wait. Give the parent a runner.`, { place })
956
+ : drive(run(ctx, rt));
957
+ }
958
+
959
+ /** This function gives the steps of a run of an evaluator. The code runs at the first step, and it does not wait. */
960
+ function runOf(code: Code): RunCode {
961
+ return function* (ctx, rt) {
937
962
  return code(ctx, rt);
938
- });
963
+ };
964
+ }
965
+
966
+ /** This function gives the fill of a compile input: the value with an item in the place of each part. */
967
+ function fillOf(split: Extract<Split, { readonly ok: true }>, doc: Envelope): <P>(items: readonly P[]) => unknown {
968
+ return (items) => (split.parts.length === 0 ? doc.value : split.fill(items));
939
969
  }
940
970
 
971
+
941
972
  function interpret(fn: EvalFn, input: CompileInput, fill: <P>(handles: readonly P[]) => unknown): Code {
942
973
  const { kind, typePath, doc, data, place } = input;
943
974
  const compiled = input.parts;
@@ -1021,16 +1052,21 @@ export function prepare(machine: Machine, doc: unknown, options: PrepareOptions
1021
1052
  };
1022
1053
  }
1023
1054
  const compiled: CompiledPart = { key: "", path: [], code: root.code, run: root.run };
1055
+ return planOf(machine, c.traced, compiled);
1056
+ }
1057
+
1058
+ /** This function makes the object of a plan. Its closures keep only the machine and the compiled root. */
1059
+ function planOf(machine: Machine, traced: boolean, root: CompiledPart): Plan {
1024
1060
  return {
1025
1061
  machine,
1026
- traced: c.traced,
1027
- root: compiled,
1062
+ traced,
1063
+ root,
1028
1064
  evaluate(context: Context = makeContext(), evalOptions?: EvalOptions): Result {
1029
- const s = new Session(machine, false, c.traced, undefined, undefined, evalOptions?.effects);
1065
+ const s = new Session(machine, false, traced, undefined, undefined, evalOptions?.effects);
1030
1066
  return root.code(rootContext(machine, context), s);
1031
1067
  },
1032
1068
  run(context: Context = makeContext(), runOptions: RunOptions = {}): Promise<Result> {
1033
- const s = new Session(machine, true, c.traced, runOptions.perform, runOptions.signal, undefined);
1069
+ const s = new Session(machine, true, traced, runOptions.perform, runOptions.signal, undefined);
1034
1070
  return driveWaiting(root.run(rootContext(machine, context), s), runOptions.signal);
1035
1071
  },
1036
1072
  };