@mark1russell7/coeval 0.27.2 → 0.28.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 +25 -9
- package/build/index.js.map +1 -1
- package/package.json +1 -1
- package/src/schedule.ts +33 -12
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.
|
|
4
|
+
"version": "0.28.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/schedule.ts
CHANGED
|
@@ -362,8 +362,14 @@ export function schedule(machine: Machine, options: ScheduleOptions = {}): Sched
|
|
|
362
362
|
*/
|
|
363
363
|
const hostDemand = (id: string): Result => {
|
|
364
364
|
const before = overflowCount();
|
|
365
|
+
const size = current().values.size;
|
|
365
366
|
const result = visit(id);
|
|
366
|
-
|
|
367
|
+
if (overflowCount() === before) return current().walk === undefined ? result : settle(id, result, []);
|
|
368
|
+
// A map keeps the order of its new keys. Thus the entries after the first `size` are the nodes of this demand (S2b).
|
|
369
|
+
const touched: string[] = [];
|
|
370
|
+
let index = 0;
|
|
371
|
+
for (const node of current().values.keys()) if (index++ >= size) touched.push(node);
|
|
372
|
+
return settle(id, result, touched);
|
|
367
373
|
};
|
|
368
374
|
|
|
369
375
|
/** This function demands one node, with the algorithm of Tarjan over the demands for the cycles of D31. */
|
|
@@ -490,20 +496,26 @@ export function schedule(machine: Machine, options: ScheduleOptions = {}): Sched
|
|
|
490
496
|
* Each evaluation enters a new node or finishes a node. Thus the walks of a data epoch do at most `2V` evaluations
|
|
491
497
|
* for `V` entered nodes. They keep one result and one entry in each list for each such node.
|
|
492
498
|
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
* the walk.
|
|
499
|
+
* After a cycle, each entered node keeps only its error. A result of the overflowed demand depends on the depth of
|
|
500
|
+
* the stack, thus each such node loses its result too (S2b). A node with a value does not take the value of the walk,
|
|
501
|
+
* because a value can hold the root of the walk. The schedule demands these nodes again, in the order in which the
|
|
502
|
+
* walk finished them. Thus each read of such a demand finds a result, and a long chain through lazy reads gives its
|
|
503
|
+
* value.
|
|
496
504
|
*
|
|
497
505
|
* @param id - The node of the demand.
|
|
498
506
|
* @param given - The result of the demand.
|
|
507
|
+
* @param touched - The nodes that the overflowed demand gave a result. A demand with no overflow gives none.
|
|
499
508
|
* @returns The final result of the demand.
|
|
500
509
|
*/
|
|
501
|
-
const settle = (id: string, given: Result): Result => {
|
|
510
|
+
const settle = (id: string, given: Result, touched: readonly string[]): Result => {
|
|
502
511
|
const epoch = current();
|
|
503
512
|
const walk = (epoch.walk ??= startWalk());
|
|
504
513
|
const { results } = walk;
|
|
505
|
-
if (
|
|
514
|
+
if (cache.facts(docs.get(id)).side === "run") return given;
|
|
515
|
+
if (results.has(id) && touched.length === 0) return given;
|
|
506
516
|
const entered: string[] = [];
|
|
517
|
+
// The entered nodes in the order in which the walk finished them. Each node finishes after the nodes that it reads.
|
|
518
|
+
const finished: string[] = [];
|
|
507
519
|
const starts: number[] = [];
|
|
508
520
|
const enter = (node: string): void => {
|
|
509
521
|
const mine = count++;
|
|
@@ -537,6 +549,7 @@ export function schedule(machine: Machine, options: ScheduleOptions = {}): Sched
|
|
|
537
549
|
const self = looped.delete(node);
|
|
538
550
|
const onCycle = reached < (order.get(node) as number) || close(from) > 1 || self;
|
|
539
551
|
results.set(node, onCycle ? cycleOf(node) : result);
|
|
552
|
+
finished.push(node);
|
|
540
553
|
// A node behind a cycle of an earlier walk finds that cycle too.
|
|
541
554
|
found ||= onCycle || (!result.ok && result.error.code === "#CYCLE!");
|
|
542
555
|
const reader = stack[stack.length - 1];
|
|
@@ -549,14 +562,22 @@ export function schedule(machine: Machine, options: ScheduleOptions = {}): Sched
|
|
|
549
562
|
looped.clear();
|
|
550
563
|
close(0);
|
|
551
564
|
}
|
|
552
|
-
if (!found) return given;
|
|
553
|
-
for (const node of
|
|
554
|
-
const result = results.get(node) as Result;
|
|
565
|
+
if (!found && touched.length === 0) return given;
|
|
566
|
+
for (const node of touched) {
|
|
555
567
|
cache.forget(node);
|
|
556
|
-
|
|
557
|
-
else epoch.values.set(node, result);
|
|
568
|
+
epoch.values.delete(node);
|
|
558
569
|
}
|
|
559
|
-
|
|
570
|
+
if (found) {
|
|
571
|
+
for (const node of entered) {
|
|
572
|
+
const result = results.get(node) as Result;
|
|
573
|
+
cache.forget(node);
|
|
574
|
+
if (result.ok) epoch.values.delete(node);
|
|
575
|
+
else epoch.values.set(node, result);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// Each demand starts with no node in evaluation, and the nodes that it reads already have their results.
|
|
579
|
+
for (const node of finished) if (!epoch.values.has(node)) visit(node);
|
|
580
|
+
return epoch.values.get(id) ?? visit(id);
|
|
560
581
|
};
|
|
561
582
|
|
|
562
583
|
/** This function gives the record of the derive nodes, for a path that ends at the root `world`. */
|