@mark1russell7/coeval 0.26.0 → 0.27.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/build/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { mulberry32 } from "@mark1russell7/rigor-generators";
1
2
  // src/doc.ts
2
3
  /** The keys that an envelope can have. */
3
4
  const ENVELOPE_KEYS = [
@@ -2409,7 +2410,7 @@ function checkHidden(m, draft) {
2409
2410
  * - A runner hides the evaluator of its name. Thus one part must give both, or the merge gives a conflict.
2410
2411
  * - The hooks `known` compose in the order of the parts. A hook does not answer for a name that a later part replaces.
2411
2412
  * The hooks `facts` compose the same way, and the first answer that is not `undefined` wins.
2412
- * - Each other field, for example `permits`, `adopt`, `roots`, `plain` or `maxDepth`, is one value. Two different
2413
+ * - Each other field, for example `permits`, `adopt`, `roots`, `plain`, `maxDepth` or `maxWork`, is one value. Two different
2413
2414
  * values are a conflict. An absent field has no value.
2414
2415
  *
2415
2416
  * A conflict stops the merge, unless the later part names its path in `replaces`. A part can be a function of the
@@ -4324,6 +4325,20 @@ function placeText(place) {
4324
4325
  }
4325
4326
  return text;
4326
4327
  }
4328
+ /**
4329
+ * The most work of one evaluation for a machine without its own `maxWork` (WORK.LIMIT, D134). One application of a
4330
+ * closure is one point.
4331
+ */
4332
+ const WORK_LIMIT = 2e5;
4333
+ /**
4334
+ * This function gives the error of the limit of work. Each tier gives this error (WORK.AGREES).
4335
+ *
4336
+ * @param limit - The limit of the machine.
4337
+ * @returns The error.
4338
+ */
4339
+ function workFailure(limit) {
4340
+ return fail("#WORK!", `The work of one evaluation is more than ${limit} points. The field maxWork of the machine sets the limit.`).error;
4341
+ }
4327
4342
  function selfLabel(self) {
4328
4343
  try {
4329
4344
  if (isHostThing(self)) return self.label;
@@ -4457,7 +4472,12 @@ var Session = class {
4457
4472
  running;
4458
4473
  traced;
4459
4474
  perform;
4460
- signal;
4475
+ /**
4476
+ * The runtime of the root, on the runtime of an equation of a tree (WORK.EQUATION). The runtime of a root holds
4477
+ * itself after the end of its evaluation (WORK.AFTER, WORK.KEEPS), thus the end mark adds no field to the object.
4478
+ * Each runtime has this field, thus a tree and its equations have one object shape.
4479
+ */
4480
+ top;
4461
4481
  /**
4462
4482
  * The record of the reads. Without it, a resolution records nothing. A nested evaluation of an equation of a tree
4463
4483
  * shares the record of the evaluation around it (READS.EQUATION).
@@ -4479,18 +4499,38 @@ var Session = class {
4479
4499
  * root scope is made at the first effect or `all`, thus an evaluation without effects makes no scope.
4480
4500
  */
4481
4501
  scope;
4482
- constructor(machine, epoch, running, traced, perform, signal, effects, reading = void 0) {
4502
+ constructor(machine, epoch, running, traced, perform, top, effects, reading = void 0) {
4483
4503
  this.machine = machine;
4484
4504
  this.epoch = epoch;
4485
4505
  this.running = running;
4486
4506
  this.traced = traced;
4487
4507
  this.perform = perform;
4488
- this.signal = signal;
4508
+ this.top = top;
4489
4509
  this.reading = reading;
4490
4510
  this.list = effects;
4491
4511
  this.holder = traced ? holderNode() : void 0;
4492
4512
  this.current = this.holder;
4493
4513
  }
4514
+ /** This getter gives `true` for the runtime of an equation of a tree (WORK.NODE). */
4515
+ get nested() {
4516
+ const top = this.top;
4517
+ return top !== void 0 && top !== this;
4518
+ }
4519
+ /**
4520
+ * This function adds work to the count of the evaluation (WORK.LIMIT). One count is on the runtime of the root, thus
4521
+ * each equation of a tree adds to it. After the end of the evaluation, each entry from the host starts a new count
4522
+ * (WORK.AFTER).
4523
+ *
4524
+ * @param points - The work.
4525
+ * @throws {Failure} The error `#WORK!`, when the count is over the limit of the machine.
4526
+ */
4527
+ spend(points) {
4528
+ const root = this.top ?? this;
4529
+ const work = (root.top === root && (this.applying ?? 0) === 0 ? 0 : root.work ?? 0) + points;
4530
+ root.work = work;
4531
+ const limit = this.machine.maxWork ?? 2e5;
4532
+ if (work > limit) throw new Failure(workFailure(limit));
4533
+ }
4494
4534
  /** The effects of the evaluation, in their order. */
4495
4535
  get effects() {
4496
4536
  return this.list ??= [];
@@ -5103,6 +5143,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
5103
5143
  ...address ? { address: true } : {}
5104
5144
  };
5105
5145
  if (runner !== void 0) {
5146
+ c.keeps = true;
5106
5147
  let inner;
5107
5148
  try {
5108
5149
  inner = isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill, kind?.caps?.some((rule) => rule.rule === "grant") === true);
@@ -5113,6 +5154,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
5113
5154
  const run = placedRun(guard === void 0 ? inner : guardRun(inner, guard, c.machine.domains), place, name);
5114
5155
  return finish$2(c, meta, runnerCode(run, place, kindText), run);
5115
5156
  }
5157
+ if (!isCompiledEvaluator(evaluator) || evaluator.keeps === true) c.keeps = true;
5116
5158
  let inner;
5117
5159
  try {
5118
5160
  inner = isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill);
@@ -5186,6 +5228,8 @@ var Probe = class {
5186
5228
  running = false;
5187
5229
  /** `true` after the part asked for something that a fold cannot give. */
5188
5230
  refused = false;
5231
+ /** A node in a fold costs work, thus a tree stops the fold before it evaluates an equation (WORK.PREPARE). */
5232
+ nested = true;
5189
5233
  /** The count of the names that the part read. */
5190
5234
  reads = 0;
5191
5235
  /**
@@ -5253,6 +5297,11 @@ var Probe = class {
5253
5297
  keepsContext() {
5254
5298
  this.refused = true;
5255
5299
  }
5300
+ /** This function stops the fold at the first point of work, thus `prepare` does no such work (WORK.PREPARE). */
5301
+ spend() {
5302
+ this.refused = true;
5303
+ throw new Failure(workFailure(0));
5304
+ }
5256
5305
  };
5257
5306
  /**
5258
5307
  * This function makes a trap for a root of the context of a fold. Each read of a field calls `refuse`. A trap of the
@@ -5584,8 +5633,8 @@ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
5584
5633
  /**
5585
5634
  * This function evaluates a plan inside the evaluation of another runtime, for example an equation of a tree inside
5586
5635
  * the evaluation of its tree (READS.EQUATION). The plan gets its own runtime, as in `plan.evaluate`. The reads of the
5587
- * plan go in the record of the reads of `outer`. The context at the root of `outer` tells which reads are free
5588
- * (READS.FREE). Without such a record, the function gives `plan.evaluate(context)`.
5636
+ * plan go in the record of the reads of `outer`, and its work goes in the count of `outer` (WORK.EQUATION). The context
5637
+ * at the root of `outer` tells which reads are free (READS.FREE). Without a session, the function gives `plan.evaluate(context)`.
5589
5638
  *
5590
5639
  * @param plan - The plan.
5591
5640
  * @param context - The context of the plan.
@@ -5593,11 +5642,10 @@ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
5593
5642
  * @returns The result.
5594
5643
  */
5595
5644
  function evaluateWithin(plan, context, outer) {
5596
- const reading = outer instanceof Session ? outer.reading : void 0;
5597
- if (reading === void 0 || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
5645
+ if (!(outer instanceof Session) || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
5598
5646
  const machine = plan.machine;
5599
5647
  const ctx = rootContext(machine, context);
5600
- return plan.code(ctx, new Session(machine, ctx.caps, false, plan.traced, void 0, void 0, void 0, reading));
5648
+ return plan.code(ctx, new Session(machine, ctx.caps, false, plan.traced, void 0, outer.top ?? outer, void 0, outer.reading));
5601
5649
  }
5602
5650
  function interpret(fn, input, fill) {
5603
5651
  const { kind, typePath, doc, data, place, machine } = input;
@@ -5760,7 +5808,22 @@ function prepare(machine, doc, options = {}) {
5760
5808
  run: void 0
5761
5809
  };
5762
5810
  }
5763
- return new CompiledPlan(machine, c.traced, root.code, root.run);
5811
+ return new CompiledPlan(machine, c.traced, c.keeps === true ? endingCode(root.code) : root.code, root.run);
5812
+ }
5813
+ /**
5814
+ * This function gives the code of a plan with a document that can use its runtime after the end of the evaluation. The
5815
+ * code marks that end (WORK.KEEPS). Each other plan has no such step, thus the count adds nothing to a read.
5816
+ *
5817
+ * @param code - The code of the root.
5818
+ * @returns The code that marks the end.
5819
+ */
5820
+ function endingCode(code) {
5821
+ return (ctx, rt) => {
5822
+ const result = code(ctx, rt);
5823
+ const session = rt;
5824
+ session.top ??= session;
5825
+ return result;
5826
+ };
5764
5827
  }
5765
5828
  /**
5766
5829
  * The object of a plan (PLAN.LEAN). The code of `evaluate` and `run` is on the class, thus a plan keeps only its
@@ -5795,8 +5858,10 @@ var CompiledPlan = class {
5795
5858
  run(context = makeContext(), runOptions = {}) {
5796
5859
  const machine = this.machine;
5797
5860
  const ctx = rootContext(machine, context);
5798
- const s = new Session(machine, ctx.caps, true, this.traced, runOptions.perform, runOptions.signal, void 0, readingOf(runOptions.reads, ctx));
5799
- return driveWaiting(this.runCode()(ctx, s), runOptions.signal);
5861
+ const s = new Session(machine, ctx.caps, true, this.traced, runOptions.perform, void 0, void 0, readingOf(runOptions.reads, ctx));
5862
+ return driveWaiting(this.runCode()(ctx, s), runOptions.signal).finally(() => {
5863
+ s.top = s;
5864
+ });
5800
5865
  }
5801
5866
  };
5802
5867
  /**
@@ -5887,8 +5952,10 @@ async function run(machine, doc, context = makeContext(), options = {}) {
5887
5952
  ...options.verb === void 0 ? {} : { verb: options.verb }
5888
5953
  });
5889
5954
  const ctx = rootContext(machine, context);
5890
- const s = new Session(machine, ctx.caps, true, true, options.perform, options.signal, void 0, readingOf(options.reads, ctx));
5891
- return record(s, await driveWaiting(plan.runCode()(ctx, s), options.signal));
5955
+ const s = new Session(machine, ctx.caps, true, true, options.perform, void 0, void 0, readingOf(options.reads, ctx));
5956
+ const result = await driveWaiting(plan.runCode()(ctx, s), options.signal);
5957
+ s.top = s;
5958
+ return record(s, result);
5892
5959
  }
5893
5960
  /**
5894
5961
  * This function finds a node of a trace by its path.
@@ -6436,9 +6503,13 @@ function allValues(results) {
6436
6503
  const errors = results.filter((result) => !result.ok);
6437
6504
  const first = errors[0];
6438
6505
  if (first !== void 0 && errors.length === 1) return { error: first };
6439
- if (errors.length > 1) return { error: fail("#ARGS", `${errors.length} parts failed.`) };
6506
+ if (errors.length > 1) return { error: partsFailed(errors) };
6440
6507
  return { values: results.map((result) => result.ok ? result.value : null) };
6441
6508
  }
6509
+ /** This function gives the error of more than one failed part. */
6510
+ function partsFailed(errors) {
6511
+ return errors.find((result) => !result.ok && result.error.code === "#WORK!") ?? fail("#ARGS", `${errors.length} parts failed.`);
6512
+ }
6442
6513
  function numbers(values, kind) {
6443
6514
  const bad = values.findIndex((value) => !isNumber(value));
6444
6515
  if (bad !== -1) return fail("#VALUE!", `Part ${bad} of ${kind} is not a number.`);
@@ -6918,20 +6989,24 @@ function putField(target, key, value) {
6918
6989
  * This function gives a value with the JSON of each node of a tree in it. A list or a plain record is new only when
6919
6990
  * it holds a node. A container that holds itself stays as it is.
6920
6991
  */
6921
- function plainOf(value, path) {
6992
+ function plainOf(value, path, runtime) {
6993
+ if (typeof value !== "object" || value === null) return ok(value);
6922
6994
  const state = stateOf(value);
6995
+ const open = path.get(value);
6923
6996
  if (state !== void 0) {
6924
- if (path.has(value)) return fail("#CYCLE!", `The JSON of the node ${state.type} at [${state.place.join(", ")}] holds the node itself.`);
6997
+ if (open === true) return fail("#CYCLE!", `The JSON of the node ${state.type} at [${state.place.join(", ")}] holds the node itself.`);
6998
+ if (open === false) runtime?.spend?.(1);
6925
6999
  return state.json(path);
6926
7000
  }
6927
- if (typeof value !== "object" || value === null || path.has(value) || isHostThing(value)) return ok(value);
7001
+ if (open === true || isHostThing(value)) return ok(value);
6928
7002
  if (!Array.isArray(value) && !isRecord(value)) return ok(value);
6929
- path.add(value);
7003
+ if (open === false) runtime?.spend?.(1);
7004
+ path.set(value, true);
6930
7005
  try {
6931
7006
  if (Array.isArray(value)) {
6932
7007
  let list;
6933
7008
  for (let index = 0; index < value.length; index += 1) {
6934
- const item = plainOf(value[index], path);
7009
+ const item = plainOf(value[index], path, runtime);
6935
7010
  if (!item.ok) return item;
6936
7011
  if (item.value !== value[index]) (list ??= [...value])[index] = item.value;
6937
7012
  }
@@ -6940,7 +7015,7 @@ function plainOf(value, path) {
6940
7015
  const record = value;
6941
7016
  let out;
6942
7017
  for (const key of Object.keys(record)) {
6943
- const item = plainOf(record[key], path);
7018
+ const item = plainOf(record[key], path, runtime);
6944
7019
  if (!item.ok) return item;
6945
7020
  if (item.value === record[key]) continue;
6946
7021
  if (out === void 0) {
@@ -6951,7 +7026,7 @@ function plainOf(value, path) {
6951
7026
  }
6952
7027
  return ok(out ?? value);
6953
7028
  } finally {
6954
- path.delete(value);
7029
+ path.set(value, false);
6955
7030
  }
6956
7031
  }
6957
7032
  /**
@@ -7403,19 +7478,19 @@ function treeThing(input, place, build, outer, host) {
7403
7478
  };
7404
7479
  },
7405
7480
  json(path) {
7406
- path.add(node);
7481
+ path.set(node, true);
7407
7482
  try {
7408
7483
  const out = {};
7409
7484
  for (const part of parts) {
7410
7485
  const result = read(part.key);
7411
7486
  if (!result.ok) return result;
7412
- const value = plainOf(result.value, path);
7487
+ const value = plainOf(result.value, path, runtime);
7413
7488
  if (!value.ok) return value;
7414
7489
  putField(out, part.key, value.value);
7415
7490
  }
7416
7491
  return ok(out);
7417
7492
  } finally {
7418
- path.delete(node);
7493
+ path.set(node, false);
7419
7494
  }
7420
7495
  }
7421
7496
  };
@@ -7438,7 +7513,7 @@ function treeThing(input, place, build, outer, host) {
7438
7513
  return cell !== void 0 && !cell.busy && cell.result !== void 0;
7439
7514
  },
7440
7515
  toJson() {
7441
- const result = state.json(/* @__PURE__ */ new Set());
7516
+ const result = state.json(/* @__PURE__ */ new Map());
7442
7517
  if (!result.ok) throw new Failure(result.error);
7443
7518
  return result.value;
7444
7519
  }
@@ -7478,6 +7553,8 @@ const NO_HOPS = /* @__PURE__ */ Object.freeze({ hops: false });
7478
7553
  * The argument `host` gives the memo cells of the host (TREE.CELL), or `undefined` for the plain memo of each node.
7479
7554
  */
7480
7555
  function treeNode(input, host) {
7556
+ const runtime = input[RUNTIME];
7557
+ if (runtime?.nested === true) runtime.spend?.(8);
7481
7558
  const found = input.resolve(SELF_PATH, NO_HOPS);
7482
7559
  const outer = found.ok ? found.thing : void 0;
7483
7560
  const above = stateOf(outer);
@@ -7487,7 +7564,7 @@ function treeNode(input, host) {
7487
7564
  build.open = true;
7488
7565
  const root = treeThing(input, place, build, outer, host);
7489
7566
  try {
7490
- return stateOf(root).json(/* @__PURE__ */ new Set());
7567
+ return stateOf(root).json(/* @__PURE__ */ new Map());
7491
7568
  } finally {
7492
7569
  build.open = false;
7493
7570
  }
@@ -11279,8 +11356,11 @@ function setOwn$2(target, key, value) {
11279
11356
  });
11280
11357
  else target[key] = value;
11281
11358
  }
11282
- function compiled(compile) {
11283
- return { compile };
11359
+ function compiled(compile, keeps) {
11360
+ return keeps === void 0 ? { compile } : {
11361
+ compile,
11362
+ keeps
11363
+ };
11284
11364
  }
11285
11365
  /** This function evaluates parts in order. It gives the value of each part, or the first error. */
11286
11366
  function valuesOf(parts, ctx, rt) {
@@ -12008,7 +12088,7 @@ function makeEvaluators(profile) {
12008
12088
  const evaluator = evaluators[name];
12009
12089
  const type = Object.hasOwn(types, name) ? types[name] : void 0;
12010
12090
  const made = Object.freeze(type === void 0 ? evaluator : {
12011
- compile: evaluator.compile,
12091
+ ...evaluator,
12012
12092
  type
12013
12093
  });
12014
12094
  if (truth !== void 0 && TRUTH_READERS.includes(name)) truthByCode.set(made, truth);
@@ -12277,6 +12357,7 @@ function formulaCode(profile) {
12277
12357
  const closure = (...args) => {
12278
12358
  const level = (clock.applying ?? 0) + 1;
12279
12359
  if (level > limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
12360
+ rt.spend?.(1);
12280
12361
  clock.applying = level;
12281
12362
  try {
12282
12363
  const scope = { ...ctx.names };
@@ -12294,7 +12375,7 @@ function formulaCode(profile) {
12294
12375
  Object.defineProperty(closure, CLOSURE$3, { value: { params: names } });
12295
12376
  return ok(closure);
12296
12377
  };
12297
- }),
12378
+ }, true),
12298
12379
  "formula.call": compiled(({ value }) => {
12299
12380
  const record = partsOf$1(value);
12300
12381
  const fnPart = record["fn"];
@@ -13080,22 +13161,35 @@ function* together(env, list, options = {}) {
13080
13161
  * @returns The result.
13081
13162
  */
13082
13163
  function reference(machine, doc, context = makeContext(), options = {}) {
13083
- return evaluateRoot(machine, doc, context, options, void 0);
13164
+ return evaluateRoot(machine, doc, context, options, void 0, void 0);
13084
13165
  }
13085
13166
  /**
13086
- * This function evaluates a document from its root. An equation of a tree gives the record of its tree. Thus the
13087
- * reads of the equation go in the list of the outer evaluation (REF.READS).
13167
+ * This function evaluates a document from its root. An equation of a tree gives the record of its tree and the count
13168
+ * of its work. Thus its reads go in the list of the outer evaluation (REF.READS), and its work in the outer count
13169
+ * (WORK.EQUATION).
13088
13170
  */
13089
- function evaluateRoot(machine, doc, context, options, outer) {
13171
+ function evaluateRoot(machine, doc, context, options, outer, meter) {
13090
13172
  const at = rootAt(machine, doc, context, options);
13091
- const env = envOf(machine, options, false, at.ctx, outer);
13173
+ const env = envOf(machine, options, false, at.ctx, outer, meter);
13092
13174
  try {
13093
13175
  return within(env, () => evaluateAt(env, at));
13094
13176
  } catch (error) {
13095
13177
  return placed(thrown(error, "the reference"), []);
13178
+ } finally {
13179
+ if (!env.nested) env.meter.ended = true;
13096
13180
  }
13097
13181
  }
13098
13182
  /**
13183
+ * WORK.LIMIT: this function adds work to the count of an evaluation. After the end of the evaluation, each entry from
13184
+ * the host starts a new count (WORK.AFTER). A count over the limit throws `#WORK!`.
13185
+ */
13186
+ function spend(env, points) {
13187
+ const meter = env.meter;
13188
+ if (meter.ended && env.applying === 0) meter.spent = 0;
13189
+ meter.spent += points;
13190
+ if (meter.spent > env.maxWork) throw new Failure(workFailure(env.maxWork));
13191
+ }
13192
+ /**
13099
13193
  * This function starts a run of a document by the rules, without a compilation (REF.RUN). The host does each effect of a runner,
13100
13194
  * and a step waits when the host waits (RUN.SEQ). `all` settles the waits in the order of the host, or in the order
13101
13195
  * of the journal of a replay (RUN.REPLAY). An effect of an evaluator gives `#CALC!` (RUN.NEEDS-RUNNER). A signal that
@@ -13112,14 +13206,16 @@ function evaluateRoot(machine, doc, context, options, outer) {
13112
13206
  */
13113
13207
  function referenceRun(machine, doc, context = makeContext(), options = {}) {
13114
13208
  const at = rootAt(machine, doc, context, options);
13115
- const env = envOf(machine, options, true, at.ctx, void 0);
13116
- return driveRun(env, stepsAt(env, at), options.signal).catch((error) => placed(thrown(error, "the reference"), []));
13209
+ const env = envOf(machine, options, true, at.ctx, void 0, void 0);
13210
+ return driveRun(env, stepsAt(env, at), options.signal).catch((error) => placed(thrown(error, "the reference"), [])).finally(() => {
13211
+ env.meter.ended = true;
13212
+ });
13117
13213
  }
13118
13214
  /**
13119
13215
  * This function makes the state of the reference for one evaluation or one run. The record of the reads comes from
13120
13216
  * the evaluation around it, or from the list of the options.
13121
13217
  */
13122
- function envOf(machine, options, running, root, outer) {
13218
+ function envOf(machine, options, running, root, outer, meter) {
13123
13219
  const perform = options.perform;
13124
13220
  return {
13125
13221
  machine,
@@ -13137,6 +13233,12 @@ function envOf(machine, options, running, root, outer) {
13137
13233
  },
13138
13234
  held: 0,
13139
13235
  applying: 0,
13236
+ maxWork: machine.maxWork ?? 2e5,
13237
+ meter: meter ?? {
13238
+ spent: 0,
13239
+ ended: false
13240
+ },
13241
+ nested: meter !== void 0,
13140
13242
  reading: outer ?? (options.reads === void 0 ? void 0 : {
13141
13243
  list: options.reads,
13142
13244
  root
@@ -13230,7 +13332,7 @@ function equationOf(node, term, names) {
13230
13332
  return evaluateRoot(env.machine, term, ctx, {
13231
13333
  definitions: env.definitions,
13232
13334
  ...node.of === void 0 ? {} : { declaredType: node.of }
13233
- }, env.reading);
13335
+ }, env.reading, env.meter);
13234
13336
  }
13235
13337
  function termIn(table, name) {
13236
13338
  return table === void 0 || !Object.hasOwn(table, name) ? void 0 : table[name];
@@ -13580,42 +13682,55 @@ function instanceOf$1(node, attr, args) {
13580
13682
  return result;
13581
13683
  }
13582
13684
  /** TREE.RESULT: the JSON of a node. `open` holds the nodes and the containers whose JSON is in progress. */
13583
- function jsonOfNode(node, self, open) {
13584
- const record = {};
13585
- for (const part of node.parts) {
13586
- const result = attributeOf(node, part.key);
13587
- if (!result.ok) return result;
13588
- const value = plainValue(result.value, [...open, self]);
13589
- if (!value.ok) return value;
13590
- setField$2(record, part.key, value.value);
13685
+ function jsonOfNode(node, self, open, seen) {
13686
+ try {
13687
+ const record = {};
13688
+ for (const part of node.parts) {
13689
+ const result = attributeOf(node, part.key);
13690
+ if (!result.ok) return result;
13691
+ const value = plainValue(node, result.value, [...open, self], seen);
13692
+ if (!value.ok) return value;
13693
+ setField$2(record, part.key, value.value);
13694
+ }
13695
+ return ok(record);
13696
+ } finally {
13697
+ seen.add(self);
13591
13698
  }
13592
- return ok(record);
13593
13699
  }
13594
- /** This function gives a copy of a value with the JSON of each node in it. */
13595
- function plainValue(value, open) {
13700
+ /**
13701
+ * This function gives a copy of a value with the JSON of each node in it. The set `seen` holds each node, list and
13702
+ * record that the walk left. A second visit of one of them counts one point on the evaluation of `owner` (WORK.SHARED).
13703
+ */
13704
+ function plainValue(owner, value, open, seen) {
13596
13705
  const node = refNodeOf(value);
13597
13706
  if (node !== void 0) {
13598
13707
  if (open.includes(value)) return fail("#CYCLE!", `The JSON of the node ${node.kind} at [${node.place.join(", ")}] holds the node itself.`);
13599
- return jsonOfNode(node, value, open);
13708
+ if (seen.has(value) && owner.env !== void 0) spend(owner.env, 1);
13709
+ return jsonOfNode(node, value, open, seen);
13600
13710
  }
13601
13711
  if (typeof value !== "object" || value === null || isHostThing(value) || open.includes(value)) return ok(value);
13602
- if (Array.isArray(value)) {
13603
- const items = [];
13604
- for (const item of value) {
13605
- const plain = plainValue(item, [...open, value]);
13712
+ if (!Array.isArray(value) && !isRecord(value)) return ok(value);
13713
+ if (seen.has(value) && owner.env !== void 0) spend(owner.env, 1);
13714
+ try {
13715
+ if (Array.isArray(value)) {
13716
+ const items = [];
13717
+ for (const item of value) {
13718
+ const plain = plainValue(owner, item, [...open, value], seen);
13719
+ if (!plain.ok) return plain;
13720
+ items.push(plain.value);
13721
+ }
13722
+ return ok(items);
13723
+ }
13724
+ const copy = {};
13725
+ for (const key of Object.keys(value)) {
13726
+ const plain = plainValue(owner, value[key], [...open, value], seen);
13606
13727
  if (!plain.ok) return plain;
13607
- items.push(plain.value);
13728
+ setField$2(copy, key, plain.value);
13608
13729
  }
13609
- return ok(items);
13610
- }
13611
- if (!isRecord(value)) return ok(value);
13612
- const copy = {};
13613
- for (const key of Object.keys(value)) {
13614
- const plain = plainValue(value[key], [...open, value]);
13615
- if (!plain.ok) return plain;
13616
- setField$2(copy, key, plain.value);
13730
+ return ok(copy);
13731
+ } finally {
13732
+ seen.add(value);
13617
13733
  }
13618
- return ok(copy);
13619
13734
  }
13620
13735
  /**
13621
13736
  * TREE.LAZY, TREE.PARENT, TREE.SIBLING and TREE.ERROR: a node of an open tree gives its thing, and the root of a new
@@ -13623,6 +13738,8 @@ function plainValue(value, open) {
13623
13738
  * reads `self` only through `resolve` (C4, TREE.SELF).
13624
13739
  */
13625
13740
  const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolve: walk, doc }) => {
13741
+ const maker = activeEnvs[activeEnvs.length - 1];
13742
+ if (maker?.nested === true) spend(maker, 8);
13626
13743
  const reached = walk(["self"]);
13627
13744
  const parent = reached.ok ? reached.thing : void 0;
13628
13745
  const outer = refNodeOf(parent);
@@ -13658,7 +13775,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
13658
13775
  },
13659
13776
  has: (key) => key === "parent" || key === "type" || parts.some((part) => part.key === String(key)) || node.values.has(String(key)),
13660
13777
  toJson: () => {
13661
- const result = jsonOfNode(node, self, []);
13778
+ const result = jsonOfNode(node, self, [], /* @__PURE__ */ new Set());
13662
13779
  if (result.ok) return result.value;
13663
13780
  throw new Failure(result.error);
13664
13781
  }
@@ -13668,7 +13785,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
13668
13785
  AT_READERS.set(self, (attr, args) => instanceOf$1(node, attr, args));
13669
13786
  if (nested) return ok(self);
13670
13787
  try {
13671
- return jsonOfNode(node, self, []);
13788
+ return jsonOfNode(node, self, [], /* @__PURE__ */ new Set());
13672
13789
  } finally {
13673
13790
  node.tree.open = false;
13674
13791
  }
@@ -13807,11 +13924,17 @@ function formulaDefinitions(profile = {}) {
13807
13924
  const body = partNamed$1(parts, "body");
13808
13925
  const clock = activeEnvs[activeEnvs.length - 1] ?? {
13809
13926
  applying: 0,
13810
- maxDepth: 1e3
13927
+ maxDepth: 1e3,
13928
+ maxWork: 2e5,
13929
+ meter: {
13930
+ spent: 0,
13931
+ ended: false
13932
+ }
13811
13933
  };
13812
13934
  const limit = Math.ceil(clock.maxDepth / 4);
13813
13935
  const closure = (...args) => {
13814
13936
  if (clock.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
13937
+ spend(clock, 1);
13815
13938
  clock.applying += 1;
13816
13939
  try {
13817
13940
  const scope = {};
@@ -18631,20 +18754,14 @@ function checkSyntax(profile) {
18631
18754
  }
18632
18755
  // src/generate.ts
18633
18756
  /**
18634
- * This function makes a source of random numbers with a seed (the algorithm mulberry32). It needs no package.
18757
+ * This function makes a source of random numbers with a seed. The numbers come from `mulberry32` of
18758
+ * `@mark1russell7/rigor-generators` (K248, D191). The draws `int`, `chance` and `pick` keep the rules of the core.
18635
18759
  *
18636
18760
  * @param seed - The seed: a whole number.
18637
18761
  * @returns The source.
18638
18762
  */
18639
18763
  function random(seed) {
18640
- let state = seed >>> 0;
18641
- const next = () => {
18642
- state = state + 1831565813 >>> 0;
18643
- let t = state;
18644
- t = Math.imul(t ^ t >>> 15, t | 1);
18645
- t ^= t + Math.imul(t ^ t >>> 7, t | 61);
18646
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
18647
- };
18764
+ const next = mulberry32(seed);
18648
18765
  const int = (below) => Math.floor(next() * below);
18649
18766
  return {
18650
18767
  next,
@@ -22439,6 +22556,6 @@ function samplesAt(values, closed, depth) {
22439
22556
  function typeFromSamples(values, options = {}) {
22440
22557
  return samplesAt(values, options.closed === true, 0);
22441
22558
  }
22442
- 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, compose, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, defineLanguage, 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, stepper, stepperNext, stepperStart, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
22559
+ 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, WORK_LIMIT, 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, compose, conforms, context, cycles, dataEdges, decodeDomain, decodeLog, decodeValue, defineLanguage, 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, stepper, stepperNext, stepperStart, stored, syntaxFormat, tag, thrown, toJson, treeNodeEvaluator, typeCheck, typeFromSamples, typeFromSchema, typeIssues, typeName, typePath, typeText, typed, typesOf, valueOfThing, verifyReads, walk, worldThing };
22443
22560
 
22444
22561
  //# sourceMappingURL=index.js.map