@mark1russell7/coeval 0.26.1 → 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
@@ -2410,7 +2410,7 @@ function checkHidden(m, draft) {
2410
2410
  * - A runner hides the evaluator of its name. Thus one part must give both, or the merge gives a conflict.
2411
2411
  * - The hooks `known` compose in the order of the parts. A hook does not answer for a name that a later part replaces.
2412
2412
  * The hooks `facts` compose the same way, and the first answer that is not `undefined` wins.
2413
- * - 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
2414
2414
  * values are a conflict. An absent field has no value.
2415
2415
  *
2416
2416
  * A conflict stops the merge, unless the later part names its path in `replaces`. A part can be a function of the
@@ -4325,6 +4325,20 @@ function placeText(place) {
4325
4325
  }
4326
4326
  return text;
4327
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
+ }
4328
4342
  function selfLabel(self) {
4329
4343
  try {
4330
4344
  if (isHostThing(self)) return self.label;
@@ -4458,7 +4472,12 @@ var Session = class {
4458
4472
  running;
4459
4473
  traced;
4460
4474
  perform;
4461
- 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;
4462
4481
  /**
4463
4482
  * The record of the reads. Without it, a resolution records nothing. A nested evaluation of an equation of a tree
4464
4483
  * shares the record of the evaluation around it (READS.EQUATION).
@@ -4480,18 +4499,38 @@ var Session = class {
4480
4499
  * root scope is made at the first effect or `all`, thus an evaluation without effects makes no scope.
4481
4500
  */
4482
4501
  scope;
4483
- constructor(machine, epoch, running, traced, perform, signal, effects, reading = void 0) {
4502
+ constructor(machine, epoch, running, traced, perform, top, effects, reading = void 0) {
4484
4503
  this.machine = machine;
4485
4504
  this.epoch = epoch;
4486
4505
  this.running = running;
4487
4506
  this.traced = traced;
4488
4507
  this.perform = perform;
4489
- this.signal = signal;
4508
+ this.top = top;
4490
4509
  this.reading = reading;
4491
4510
  this.list = effects;
4492
4511
  this.holder = traced ? holderNode() : void 0;
4493
4512
  this.current = this.holder;
4494
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
+ }
4495
4534
  /** The effects of the evaluation, in their order. */
4496
4535
  get effects() {
4497
4536
  return this.list ??= [];
@@ -5104,6 +5143,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
5104
5143
  ...address ? { address: true } : {}
5105
5144
  };
5106
5145
  if (runner !== void 0) {
5146
+ c.keeps = true;
5107
5147
  let inner;
5108
5148
  try {
5109
5149
  inner = isCompiledRunner(runner) ? runner.compileRun(input) : interpretRun(runner, input, split.fill, kind?.caps?.some((rule) => rule.rule === "grant") === true);
@@ -5114,6 +5154,7 @@ function compileNode(c, value, place, declared, depth, address = false) {
5114
5154
  const run = placedRun(guard === void 0 ? inner : guardRun(inner, guard, c.machine.domains), place, name);
5115
5155
  return finish$2(c, meta, runnerCode(run, place, kindText), run);
5116
5156
  }
5157
+ if (!isCompiledEvaluator(evaluator) || evaluator.keeps === true) c.keeps = true;
5117
5158
  let inner;
5118
5159
  try {
5119
5160
  inner = isCompiledEvaluator(evaluator) ? evaluator.compile(input) : interpret(evaluator, input, split.fill);
@@ -5187,6 +5228,8 @@ var Probe = class {
5187
5228
  running = false;
5188
5229
  /** `true` after the part asked for something that a fold cannot give. */
5189
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;
5190
5233
  /** The count of the names that the part read. */
5191
5234
  reads = 0;
5192
5235
  /**
@@ -5254,6 +5297,11 @@ var Probe = class {
5254
5297
  keepsContext() {
5255
5298
  this.refused = true;
5256
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
+ }
5257
5305
  };
5258
5306
  /**
5259
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
@@ -5585,8 +5633,8 @@ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
5585
5633
  /**
5586
5634
  * This function evaluates a plan inside the evaluation of another runtime, for example an equation of a tree inside
5587
5635
  * the evaluation of its tree (READS.EQUATION). The plan gets its own runtime, as in `plan.evaluate`. The reads of the
5588
- * plan go in the record of the reads of `outer`. The context at the root of `outer` tells which reads are free
5589
- * (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)`.
5590
5638
  *
5591
5639
  * @param plan - The plan.
5592
5640
  * @param context - The context of the plan.
@@ -5594,11 +5642,10 @@ const RUNTIME = /* @__PURE__ */ Symbol("coeval.runtime");
5594
5642
  * @returns The result.
5595
5643
  */
5596
5644
  function evaluateWithin(plan, context, outer) {
5597
- const reading = outer instanceof Session ? outer.reading : void 0;
5598
- if (reading === void 0 || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
5645
+ if (!(outer instanceof Session) || !(plan instanceof CompiledPlan)) return plan.evaluate(context);
5599
5646
  const machine = plan.machine;
5600
5647
  const ctx = rootContext(machine, context);
5601
- 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));
5602
5649
  }
5603
5650
  function interpret(fn, input, fill) {
5604
5651
  const { kind, typePath, doc, data, place, machine } = input;
@@ -5761,7 +5808,22 @@ function prepare(machine, doc, options = {}) {
5761
5808
  run: void 0
5762
5809
  };
5763
5810
  }
5764
- 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
+ };
5765
5827
  }
5766
5828
  /**
5767
5829
  * The object of a plan (PLAN.LEAN). The code of `evaluate` and `run` is on the class, thus a plan keeps only its
@@ -5796,8 +5858,10 @@ var CompiledPlan = class {
5796
5858
  run(context = makeContext(), runOptions = {}) {
5797
5859
  const machine = this.machine;
5798
5860
  const ctx = rootContext(machine, context);
5799
- const s = new Session(machine, ctx.caps, true, this.traced, runOptions.perform, runOptions.signal, void 0, readingOf(runOptions.reads, ctx));
5800
- 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
+ });
5801
5865
  }
5802
5866
  };
5803
5867
  /**
@@ -5888,8 +5952,10 @@ async function run(machine, doc, context = makeContext(), options = {}) {
5888
5952
  ...options.verb === void 0 ? {} : { verb: options.verb }
5889
5953
  });
5890
5954
  const ctx = rootContext(machine, context);
5891
- const s = new Session(machine, ctx.caps, true, true, options.perform, options.signal, void 0, readingOf(options.reads, ctx));
5892
- 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);
5893
5959
  }
5894
5960
  /**
5895
5961
  * This function finds a node of a trace by its path.
@@ -6437,9 +6503,13 @@ function allValues(results) {
6437
6503
  const errors = results.filter((result) => !result.ok);
6438
6504
  const first = errors[0];
6439
6505
  if (first !== void 0 && errors.length === 1) return { error: first };
6440
- if (errors.length > 1) return { error: fail("#ARGS", `${errors.length} parts failed.`) };
6506
+ if (errors.length > 1) return { error: partsFailed(errors) };
6441
6507
  return { values: results.map((result) => result.ok ? result.value : null) };
6442
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
+ }
6443
6513
  function numbers(values, kind) {
6444
6514
  const bad = values.findIndex((value) => !isNumber(value));
6445
6515
  if (bad !== -1) return fail("#VALUE!", `Part ${bad} of ${kind} is not a number.`);
@@ -6919,20 +6989,24 @@ function putField(target, key, value) {
6919
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
6920
6990
  * it holds a node. A container that holds itself stays as it is.
6921
6991
  */
6922
- function plainOf(value, path) {
6992
+ function plainOf(value, path, runtime) {
6993
+ if (typeof value !== "object" || value === null) return ok(value);
6923
6994
  const state = stateOf(value);
6995
+ const open = path.get(value);
6924
6996
  if (state !== void 0) {
6925
- 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);
6926
6999
  return state.json(path);
6927
7000
  }
6928
- if (typeof value !== "object" || value === null || path.has(value) || isHostThing(value)) return ok(value);
7001
+ if (open === true || isHostThing(value)) return ok(value);
6929
7002
  if (!Array.isArray(value) && !isRecord(value)) return ok(value);
6930
- path.add(value);
7003
+ if (open === false) runtime?.spend?.(1);
7004
+ path.set(value, true);
6931
7005
  try {
6932
7006
  if (Array.isArray(value)) {
6933
7007
  let list;
6934
7008
  for (let index = 0; index < value.length; index += 1) {
6935
- const item = plainOf(value[index], path);
7009
+ const item = plainOf(value[index], path, runtime);
6936
7010
  if (!item.ok) return item;
6937
7011
  if (item.value !== value[index]) (list ??= [...value])[index] = item.value;
6938
7012
  }
@@ -6941,7 +7015,7 @@ function plainOf(value, path) {
6941
7015
  const record = value;
6942
7016
  let out;
6943
7017
  for (const key of Object.keys(record)) {
6944
- const item = plainOf(record[key], path);
7018
+ const item = plainOf(record[key], path, runtime);
6945
7019
  if (!item.ok) return item;
6946
7020
  if (item.value === record[key]) continue;
6947
7021
  if (out === void 0) {
@@ -6952,7 +7026,7 @@ function plainOf(value, path) {
6952
7026
  }
6953
7027
  return ok(out ?? value);
6954
7028
  } finally {
6955
- path.delete(value);
7029
+ path.set(value, false);
6956
7030
  }
6957
7031
  }
6958
7032
  /**
@@ -7404,19 +7478,19 @@ function treeThing(input, place, build, outer, host) {
7404
7478
  };
7405
7479
  },
7406
7480
  json(path) {
7407
- path.add(node);
7481
+ path.set(node, true);
7408
7482
  try {
7409
7483
  const out = {};
7410
7484
  for (const part of parts) {
7411
7485
  const result = read(part.key);
7412
7486
  if (!result.ok) return result;
7413
- const value = plainOf(result.value, path);
7487
+ const value = plainOf(result.value, path, runtime);
7414
7488
  if (!value.ok) return value;
7415
7489
  putField(out, part.key, value.value);
7416
7490
  }
7417
7491
  return ok(out);
7418
7492
  } finally {
7419
- path.delete(node);
7493
+ path.set(node, false);
7420
7494
  }
7421
7495
  }
7422
7496
  };
@@ -7439,7 +7513,7 @@ function treeThing(input, place, build, outer, host) {
7439
7513
  return cell !== void 0 && !cell.busy && cell.result !== void 0;
7440
7514
  },
7441
7515
  toJson() {
7442
- const result = state.json(/* @__PURE__ */ new Set());
7516
+ const result = state.json(/* @__PURE__ */ new Map());
7443
7517
  if (!result.ok) throw new Failure(result.error);
7444
7518
  return result.value;
7445
7519
  }
@@ -7479,6 +7553,8 @@ const NO_HOPS = /* @__PURE__ */ Object.freeze({ hops: false });
7479
7553
  * The argument `host` gives the memo cells of the host (TREE.CELL), or `undefined` for the plain memo of each node.
7480
7554
  */
7481
7555
  function treeNode(input, host) {
7556
+ const runtime = input[RUNTIME];
7557
+ if (runtime?.nested === true) runtime.spend?.(8);
7482
7558
  const found = input.resolve(SELF_PATH, NO_HOPS);
7483
7559
  const outer = found.ok ? found.thing : void 0;
7484
7560
  const above = stateOf(outer);
@@ -7488,7 +7564,7 @@ function treeNode(input, host) {
7488
7564
  build.open = true;
7489
7565
  const root = treeThing(input, place, build, outer, host);
7490
7566
  try {
7491
- return stateOf(root).json(/* @__PURE__ */ new Set());
7567
+ return stateOf(root).json(/* @__PURE__ */ new Map());
7492
7568
  } finally {
7493
7569
  build.open = false;
7494
7570
  }
@@ -11280,8 +11356,11 @@ function setOwn$2(target, key, value) {
11280
11356
  });
11281
11357
  else target[key] = value;
11282
11358
  }
11283
- function compiled(compile) {
11284
- return { compile };
11359
+ function compiled(compile, keeps) {
11360
+ return keeps === void 0 ? { compile } : {
11361
+ compile,
11362
+ keeps
11363
+ };
11285
11364
  }
11286
11365
  /** This function evaluates parts in order. It gives the value of each part, or the first error. */
11287
11366
  function valuesOf(parts, ctx, rt) {
@@ -12009,7 +12088,7 @@ function makeEvaluators(profile) {
12009
12088
  const evaluator = evaluators[name];
12010
12089
  const type = Object.hasOwn(types, name) ? types[name] : void 0;
12011
12090
  const made = Object.freeze(type === void 0 ? evaluator : {
12012
- compile: evaluator.compile,
12091
+ ...evaluator,
12013
12092
  type
12014
12093
  });
12015
12094
  if (truth !== void 0 && TRUTH_READERS.includes(name)) truthByCode.set(made, truth);
@@ -12278,6 +12357,7 @@ function formulaCode(profile) {
12278
12357
  const closure = (...args) => {
12279
12358
  const level = (clock.applying ?? 0) + 1;
12280
12359
  if (level > limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
12360
+ rt.spend?.(1);
12281
12361
  clock.applying = level;
12282
12362
  try {
12283
12363
  const scope = { ...ctx.names };
@@ -12295,7 +12375,7 @@ function formulaCode(profile) {
12295
12375
  Object.defineProperty(closure, CLOSURE$3, { value: { params: names } });
12296
12376
  return ok(closure);
12297
12377
  };
12298
- }),
12378
+ }, true),
12299
12379
  "formula.call": compiled(({ value }) => {
12300
12380
  const record = partsOf$1(value);
12301
12381
  const fnPart = record["fn"];
@@ -13081,22 +13161,35 @@ function* together(env, list, options = {}) {
13081
13161
  * @returns The result.
13082
13162
  */
13083
13163
  function reference(machine, doc, context = makeContext(), options = {}) {
13084
- return evaluateRoot(machine, doc, context, options, void 0);
13164
+ return evaluateRoot(machine, doc, context, options, void 0, void 0);
13085
13165
  }
13086
13166
  /**
13087
- * This function evaluates a document from its root. An equation of a tree gives the record of its tree. Thus the
13088
- * 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).
13089
13170
  */
13090
- function evaluateRoot(machine, doc, context, options, outer) {
13171
+ function evaluateRoot(machine, doc, context, options, outer, meter) {
13091
13172
  const at = rootAt(machine, doc, context, options);
13092
- const env = envOf(machine, options, false, at.ctx, outer);
13173
+ const env = envOf(machine, options, false, at.ctx, outer, meter);
13093
13174
  try {
13094
13175
  return within(env, () => evaluateAt(env, at));
13095
13176
  } catch (error) {
13096
13177
  return placed(thrown(error, "the reference"), []);
13178
+ } finally {
13179
+ if (!env.nested) env.meter.ended = true;
13097
13180
  }
13098
13181
  }
13099
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
+ /**
13100
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,
13101
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
13102
13195
  * of the journal of a replay (RUN.REPLAY). An effect of an evaluator gives `#CALC!` (RUN.NEEDS-RUNNER). A signal that
@@ -13113,14 +13206,16 @@ function evaluateRoot(machine, doc, context, options, outer) {
13113
13206
  */
13114
13207
  function referenceRun(machine, doc, context = makeContext(), options = {}) {
13115
13208
  const at = rootAt(machine, doc, context, options);
13116
- const env = envOf(machine, options, true, at.ctx, void 0);
13117
- 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
+ });
13118
13213
  }
13119
13214
  /**
13120
13215
  * This function makes the state of the reference for one evaluation or one run. The record of the reads comes from
13121
13216
  * the evaluation around it, or from the list of the options.
13122
13217
  */
13123
- function envOf(machine, options, running, root, outer) {
13218
+ function envOf(machine, options, running, root, outer, meter) {
13124
13219
  const perform = options.perform;
13125
13220
  return {
13126
13221
  machine,
@@ -13138,6 +13233,12 @@ function envOf(machine, options, running, root, outer) {
13138
13233
  },
13139
13234
  held: 0,
13140
13235
  applying: 0,
13236
+ maxWork: machine.maxWork ?? 2e5,
13237
+ meter: meter ?? {
13238
+ spent: 0,
13239
+ ended: false
13240
+ },
13241
+ nested: meter !== void 0,
13141
13242
  reading: outer ?? (options.reads === void 0 ? void 0 : {
13142
13243
  list: options.reads,
13143
13244
  root
@@ -13231,7 +13332,7 @@ function equationOf(node, term, names) {
13231
13332
  return evaluateRoot(env.machine, term, ctx, {
13232
13333
  definitions: env.definitions,
13233
13334
  ...node.of === void 0 ? {} : { declaredType: node.of }
13234
- }, env.reading);
13335
+ }, env.reading, env.meter);
13235
13336
  }
13236
13337
  function termIn(table, name) {
13237
13338
  return table === void 0 || !Object.hasOwn(table, name) ? void 0 : table[name];
@@ -13581,42 +13682,55 @@ function instanceOf$1(node, attr, args) {
13581
13682
  return result;
13582
13683
  }
13583
13684
  /** TREE.RESULT: the JSON of a node. `open` holds the nodes and the containers whose JSON is in progress. */
13584
- function jsonOfNode(node, self, open) {
13585
- const record = {};
13586
- for (const part of node.parts) {
13587
- const result = attributeOf(node, part.key);
13588
- if (!result.ok) return result;
13589
- const value = plainValue(result.value, [...open, self]);
13590
- if (!value.ok) return value;
13591
- 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);
13592
13698
  }
13593
- return ok(record);
13594
13699
  }
13595
- /** This function gives a copy of a value with the JSON of each node in it. */
13596
- 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) {
13597
13705
  const node = refNodeOf(value);
13598
13706
  if (node !== void 0) {
13599
13707
  if (open.includes(value)) return fail("#CYCLE!", `The JSON of the node ${node.kind} at [${node.place.join(", ")}] holds the node itself.`);
13600
- 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);
13601
13710
  }
13602
13711
  if (typeof value !== "object" || value === null || isHostThing(value) || open.includes(value)) return ok(value);
13603
- if (Array.isArray(value)) {
13604
- const items = [];
13605
- for (const item of value) {
13606
- 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);
13607
13727
  if (!plain.ok) return plain;
13608
- items.push(plain.value);
13728
+ setField$2(copy, key, plain.value);
13609
13729
  }
13610
- return ok(items);
13611
- }
13612
- if (!isRecord(value)) return ok(value);
13613
- const copy = {};
13614
- for (const key of Object.keys(value)) {
13615
- const plain = plainValue(value[key], [...open, value]);
13616
- if (!plain.ok) return plain;
13617
- setField$2(copy, key, plain.value);
13730
+ return ok(copy);
13731
+ } finally {
13732
+ seen.add(value);
13618
13733
  }
13619
- return ok(copy);
13620
13734
  }
13621
13735
  /**
13622
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
@@ -13624,6 +13738,8 @@ function plainValue(value, open) {
13624
13738
  * reads `self` only through `resolve` (C4, TREE.SELF).
13625
13739
  */
13626
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);
13627
13743
  const reached = walk(["self"]);
13628
13744
  const parent = reached.ok ? reached.thing : void 0;
13629
13745
  const outer = refNodeOf(parent);
@@ -13659,7 +13775,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
13659
13775
  },
13660
13776
  has: (key) => key === "parent" || key === "type" || parts.some((part) => part.key === String(key)) || node.values.has(String(key)),
13661
13777
  toJson: () => {
13662
- const result = jsonOfNode(node, self, []);
13778
+ const result = jsonOfNode(node, self, [], /* @__PURE__ */ new Set());
13663
13779
  if (result.ok) return result.value;
13664
13780
  throw new Failure(result.error);
13665
13781
  }
@@ -13669,7 +13785,7 @@ const treeDefinition = ({ parts, context, kind, place, machine, typePath, resolv
13669
13785
  AT_READERS.set(self, (attr, args) => instanceOf$1(node, attr, args));
13670
13786
  if (nested) return ok(self);
13671
13787
  try {
13672
- return jsonOfNode(node, self, []);
13788
+ return jsonOfNode(node, self, [], /* @__PURE__ */ new Set());
13673
13789
  } finally {
13674
13790
  node.tree.open = false;
13675
13791
  }
@@ -13808,11 +13924,17 @@ function formulaDefinitions(profile = {}) {
13808
13924
  const body = partNamed$1(parts, "body");
13809
13925
  const clock = activeEnvs[activeEnvs.length - 1] ?? {
13810
13926
  applying: 0,
13811
- maxDepth: 1e3
13927
+ maxDepth: 1e3,
13928
+ maxWork: 2e5,
13929
+ meter: {
13930
+ spent: 0,
13931
+ ended: false
13932
+ }
13812
13933
  };
13813
13934
  const limit = Math.ceil(clock.maxDepth / 4);
13814
13935
  const closure = (...args) => {
13815
13936
  if (clock.applying >= limit) throw new Failure(fail("#DEPTH!", `The applications of functions nest deeper than ${limit} levels.`).error);
13937
+ spend(clock, 1);
13816
13938
  clock.applying += 1;
13817
13939
  try {
13818
13940
  const scope = {};
@@ -22434,6 +22556,6 @@ function samplesAt(values, closed, depth) {
22434
22556
  function typeFromSamples(values, options = {}) {
22435
22557
  return samplesAt(values, options.closed === true, 0);
22436
22558
  }
22437
- 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 };
22438
22560
 
22439
22561
  //# sourceMappingURL=index.js.map