solve-engine 2.38.21 → 2.38.23

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.
Files changed (94) hide show
  1. package/dist/{PackageCompatibility-ZCZVGHws.d.ts → PackageCompatibility-C7ILySsH.d.ts} +1 -1
  2. package/dist/{PackageCompatibility-Bv42nEm2.d.cts → PackageCompatibility-CzDzOIg9.d.cts} +1 -1
  3. package/dist/{PackageRegistry-7dFbaAZp.d.cts → PackageRegistry-Bd8ErpwZ.d.cts} +78 -1
  4. package/dist/{PackageRegistry-B6s8LGCu.d.ts → PackageRegistry-D7_B0mxv.d.ts} +78 -1
  5. package/dist/{VMBuiltins-0C4z3yDS.d.cts → VMBuiltins-Baa90D2v.d.cts} +232 -1
  6. package/dist/{VMBuiltins-Bu6qaKi0.d.ts → VMBuiltins-BqkoJtHt.d.ts} +232 -1
  7. package/dist/chunk-54QMY2VL.cjs +2 -0
  8. package/dist/chunk-54QMY2VL.cjs.map +1 -0
  9. package/dist/{chunk-7PUNL5CJ.cjs → chunk-6FBXJYWO.cjs} +3 -3
  10. package/dist/{chunk-H4G3UXJV.js.map → chunk-6FBXJYWO.cjs.map} +1 -1
  11. package/dist/chunk-AEGR3GFA.js +3 -0
  12. package/dist/chunk-AEGR3GFA.js.map +1 -0
  13. package/dist/chunk-CR7IHPA2.cjs +2 -0
  14. package/dist/chunk-CR7IHPA2.cjs.map +1 -0
  15. package/dist/{chunk-NFASELLK.js → chunk-FBXQUQCY.js} +2 -2
  16. package/dist/{chunk-NFASELLK.js.map → chunk-FBXQUQCY.js.map} +1 -1
  17. package/dist/chunk-GITRBCSD.cjs +5 -0
  18. package/dist/chunk-GITRBCSD.cjs.map +1 -0
  19. package/dist/chunk-JVHRND2N.js +5 -0
  20. package/dist/chunk-JVHRND2N.js.map +1 -0
  21. package/dist/{chunk-H4G3UXJV.js → chunk-KSOB5FCI.js} +3 -3
  22. package/dist/chunk-KSOB5FCI.js.map +1 -0
  23. package/dist/chunk-OBQC7KDY.cjs +2 -0
  24. package/dist/chunk-OBQC7KDY.cjs.map +1 -0
  25. package/dist/{chunk-VLFP6IAY.cjs → chunk-OGBLSNQE.cjs} +2 -2
  26. package/dist/{chunk-VLFP6IAY.cjs.map → chunk-OGBLSNQE.cjs.map} +1 -1
  27. package/dist/chunk-QP4VIEXZ.js +2 -0
  28. package/dist/chunk-QP4VIEXZ.js.map +1 -0
  29. package/dist/chunk-RMBUP4XA.js +2 -0
  30. package/dist/chunk-RMBUP4XA.js.map +1 -0
  31. package/dist/chunk-UITBYTCD.cjs +3 -0
  32. package/dist/chunk-UITBYTCD.cjs.map +1 -0
  33. package/dist/chunk-X2QJE3SV.js +2 -0
  34. package/dist/chunk-X2QJE3SV.js.map +1 -0
  35. package/dist/chunk-Y5ZY6DPX.cjs +2 -0
  36. package/dist/chunk-Y5ZY6DPX.cjs.map +1 -0
  37. package/dist/chunk-ZISAN7NW.js +2 -0
  38. package/dist/chunk-ZISAN7NW.js.map +1 -0
  39. package/dist/constants.cjs +1 -1
  40. package/dist/constants.js +1 -1
  41. package/dist/engine.cjs +1 -1
  42. package/dist/engine.d.cts +128 -5
  43. package/dist/engine.d.ts +128 -5
  44. package/dist/engine.js +1 -1
  45. package/dist/engine.worker.cjs +1 -1
  46. package/dist/engine.worker.js +1 -1
  47. package/dist/index.cjs +1 -1
  48. package/dist/index.d.cts +4 -4
  49. package/dist/index.d.ts +4 -4
  50. package/dist/index.js +1 -1
  51. package/dist/language.d.cts +3 -3
  52. package/dist/language.d.ts +3 -3
  53. package/dist/packages.cjs +1 -1
  54. package/dist/packages.d.cts +2 -2
  55. package/dist/packages.d.ts +2 -2
  56. package/dist/packages.js +1 -1
  57. package/dist/testing.cjs +2 -2
  58. package/dist/testing.d.cts +3 -3
  59. package/dist/testing.d.ts +3 -3
  60. package/dist/testing.js +1 -1
  61. package/dist/vm.cjs +1 -1
  62. package/dist/vm.d.cts +1 -1
  63. package/dist/vm.d.ts +1 -1
  64. package/dist/vm.js +1 -1
  65. package/dist/worker.cjs +2 -2
  66. package/dist/worker.d.cts +2 -2
  67. package/dist/worker.d.ts +2 -2
  68. package/dist/worker.js +1 -1
  69. package/package.json +1 -1
  70. package/dist/chunk-2YHOWQ43.js +0 -2
  71. package/dist/chunk-2YHOWQ43.js.map +0 -1
  72. package/dist/chunk-3JSXJSMT.js +0 -2
  73. package/dist/chunk-3JSXJSMT.js.map +0 -1
  74. package/dist/chunk-432HHLSB.cjs +0 -5
  75. package/dist/chunk-432HHLSB.cjs.map +0 -1
  76. package/dist/chunk-5QA3BI4V.js +0 -3
  77. package/dist/chunk-5QA3BI4V.js.map +0 -1
  78. package/dist/chunk-6W3JFXPQ.cjs +0 -2
  79. package/dist/chunk-6W3JFXPQ.cjs.map +0 -1
  80. package/dist/chunk-7PUNL5CJ.cjs.map +0 -1
  81. package/dist/chunk-EPLOL7WC.cjs +0 -2
  82. package/dist/chunk-EPLOL7WC.cjs.map +0 -1
  83. package/dist/chunk-HNXV35Q2.cjs +0 -2
  84. package/dist/chunk-HNXV35Q2.cjs.map +0 -1
  85. package/dist/chunk-JM7BIFF4.js +0 -5
  86. package/dist/chunk-JM7BIFF4.js.map +0 -1
  87. package/dist/chunk-JZQRUOO6.js +0 -2
  88. package/dist/chunk-JZQRUOO6.js.map +0 -1
  89. package/dist/chunk-K2OUNZZG.cjs +0 -2
  90. package/dist/chunk-K2OUNZZG.cjs.map +0 -1
  91. package/dist/chunk-LJIR7MLG.cjs +0 -3
  92. package/dist/chunk-LJIR7MLG.cjs.map +0 -1
  93. package/dist/chunk-SIUHB77U.js +0 -2
  94. package/dist/chunk-SIUHB77U.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { I as IEnginePackage } from './PackageRegistry-B6s8LGCu.js';
1
+ import { I as IEnginePackage } from './PackageRegistry-D7_B0mxv.js';
2
2
 
3
3
  /**
4
4
  * Package load-time compatibility checking, the "detect overlapping
@@ -1,4 +1,4 @@
1
- import { I as IEnginePackage } from './PackageRegistry-7dFbaAZp.cjs';
1
+ import { I as IEnginePackage } from './PackageRegistry-Bd8ErpwZ.cjs';
2
2
 
3
3
  /**
4
4
  * Package load-time compatibility checking, the "detect overlapping
@@ -2,7 +2,7 @@ import { a as PrecedenceParser, b as PrefixParselet, I as InfixParselet } from '
2
2
  import { M as MarkdownLineType, L as Lexer, e as TokenCategory, c as LexerVocabulary } from './Lexer-DaWkCu84.cjs';
3
3
  import { IAsyncResolver } from './resolvers.cjs';
4
4
  import { T as TokenFusion, c as TokenNormalizer, a as NormalizerRule } from './TokenNormalizer-D382VSYh.cjs';
5
- import { b as VMCheckpointer, D as DependencyGraph, V as VM, h as DagSnapshot, i as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-0C4z3yDS.cjs';
5
+ import { b as VMCheckpointer, D as DependencyGraph, V as VM, h as DagSnapshot, i as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-Baa90D2v.cjs';
6
6
  import { V as Value, b as ValueType, D as DatetimeGrain } from './Value-B55Hvn3e.cjs';
7
7
  import { a as BytecodeProgram } from './BytecodeBuilder-DSWKZi4f.cjs';
8
8
  import { C as CalendarBackend } from './CalendarBackend-MdS3Bb4P.cjs';
@@ -2410,6 +2410,8 @@ declare class ExpressionEngine {
2410
2410
  private builderPool;
2411
2411
  private builderPoolIndex;
2412
2412
  private lastTelemetry;
2413
+ /** Whether the line being evaluated sits on a cycle; see {@link setLineOnCycle}. */
2414
+ private lineOnCycle;
2413
2415
  constructor(options?: EngineOptions);
2414
2416
  /**
2415
2417
  * Get the native event stream from the batcher for stream-based consumers.
@@ -2434,6 +2436,81 @@ declare class ExpressionEngine {
2434
2436
  * Tests use this to access `batcher._testCaptures` for synchronous
2435
2437
  * event observation without async stream reader timing issues.
2436
2438
  */
2439
+ /**
2440
+ * Put a name back to what the lines above `lineNumber` left it holding.
2441
+ *
2442
+ * The invariant a pass from scratch keeps without trying: when it reaches a
2443
+ * line, every name holds what the lines above defined, because those lines
2444
+ * have just run in order and stored. The incremental path keeps the VM
2445
+ * between passes, so a line that writes a name can find the name holding
2446
+ * its own previous answer instead. That is invisible for `:x = 5`, which
2447
+ * stores over it, and wrong twice over for a definition that reads what it
2448
+ * writes or fails to store:
2449
+ *
2450
+ * - `:v3 = 44` above `:v3 = v3 + 3` is 47 on every pass from scratch, since
2451
+ * line 1 puts 44 back each time. Edit line 1 away and nothing puts
2452
+ * anything back, so line 2 reads its own 47 and climbs by three a pass,
2453
+ * where a pass from scratch says `v3` is undefined.
2454
+ * - `:x = 5` edited to `:x = zz + 1` skips the store, on both paths, and
2455
+ * the incremental one is left holding the 5 the same line stored before
2456
+ * the edit, where a pass from scratch has nothing.
2457
+ *
2458
+ * The checkpoint chain records what each line wrote in document order, so
2459
+ * the value the prefix holds is the one it holds just before this line,
2460
+ * and this puts the VM there: the value if there is one, absent if not.
2461
+ * The evaluator calls it before a definition runs and again if it fails,
2462
+ * both times before the line's own checkpoint is taken, so the checkpoint
2463
+ * records the corrected state.
2464
+ *
2465
+ * A function is a definition too, and was the one kind nothing could
2466
+ * undo: `f(x) = x + 4` edited into a blank left `f(9)` answering 13 for
2467
+ * the rest of the session. The prefix is consulted for a function binding
2468
+ * as well as a variable one, and each is put back on its own, since a
2469
+ * name can be bound in both bags at once (`f(x) = x + 1` above `:f = 4`).
2470
+ * A name bound to neither above is unbound from both.
2471
+ *
2472
+ * An accumulator is left alone. Every pass resets each running total to
2473
+ * its seed and re-runs every line that steps it, in order, so by the time
2474
+ * any step runs the VM already holds what the steps above built, seed
2475
+ * included, and putting the prefix back would only undo a step.
2476
+ *
2477
+ * @param name - The name the line writes.
2478
+ * @param lineNumber - The 1-based line it sits on.
2479
+ */
2480
+ restoreToPrefix(name: string, lineNumber: number): void;
2481
+ /**
2482
+ * Whether `name` is a running total, stepped by `+=` or `-=` somewhere.
2483
+ *
2484
+ * The evaluator's cycle walk asks, because a total's steppers depend on one
2485
+ * another through the total in a way the graph deliberately does not
2486
+ * record: a line is kept out of the consumers of a name it writes, which
2487
+ * is right for `:x = 5` and hides the fold for `spent += 5`.
2488
+ *
2489
+ * @param name - A variable name.
2490
+ * @returns True when a line has stepped it.
2491
+ */
2492
+ /**
2493
+ * Tell the engine whether the line about to run sits on a cycle.
2494
+ *
2495
+ * A line that depends on itself, through positions or names or both, has
2496
+ * no answer of its own: each value it could hold is computed from that same
2497
+ * value a pass earlier. A single fresh pass reports that, because some
2498
+ * member reads a line below it that has not run, and the error travels all
2499
+ * the way round. The incremental path carries the VM between passes, so a
2500
+ * member could find a number to start from, and the pair then chased it.
2501
+ *
2502
+ * While this is set, a positional read of a line below the one running
2503
+ * answers as an unevaluated line does, which is what makes a member report
2504
+ * the cycle rather than the number it read last pass. The evaluator sets it
2505
+ * per line from the cycle membership it keeps, and puts the names such a
2506
+ * line reads back to the prefix before it runs, for the same reason. A line
2507
+ * not on a cycle keeps the incremental path's tolerance of a plain forward
2508
+ * reference, which resolves by running the document again.
2509
+ *
2510
+ * @param onCycle - Whether the line about to run is on a cycle.
2511
+ */
2512
+ setLineOnCycle(onCycle: boolean): void;
2513
+ isAccumulatorName(name: string): boolean;
2437
2514
  /** The names of every user-defined unit in scope, for detecting a removal. */
2438
2515
  userUnitNames(): string[];
2439
2516
  /**
@@ -2,7 +2,7 @@ import { a as PrecedenceParser, b as PrefixParselet, I as InfixParselet } from '
2
2
  import { M as MarkdownLineType, L as Lexer, e as TokenCategory, c as LexerVocabulary } from './Lexer-DPn5dfCH.js';
3
3
  import { IAsyncResolver } from './resolvers.js';
4
4
  import { T as TokenFusion, c as TokenNormalizer, a as NormalizerRule } from './TokenNormalizer-DAzPp-j1.js';
5
- import { b as VMCheckpointer, D as DependencyGraph, V as VM, h as DagSnapshot, i as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-Bu6qaKi0.js';
5
+ import { b as VMCheckpointer, D as DependencyGraph, V as VM, h as DagSnapshot, i as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-BqkoJtHt.js';
6
6
  import { V as Value, b as ValueType, D as DatetimeGrain } from './Value-B55Hvn3e.js';
7
7
  import { a as BytecodeProgram } from './BytecodeBuilder-DSWKZi4f.js';
8
8
  import { C as CalendarBackend } from './CalendarBackend-MdS3Bb4P.js';
@@ -2410,6 +2410,8 @@ declare class ExpressionEngine {
2410
2410
  private builderPool;
2411
2411
  private builderPoolIndex;
2412
2412
  private lastTelemetry;
2413
+ /** Whether the line being evaluated sits on a cycle; see {@link setLineOnCycle}. */
2414
+ private lineOnCycle;
2413
2415
  constructor(options?: EngineOptions);
2414
2416
  /**
2415
2417
  * Get the native event stream from the batcher for stream-based consumers.
@@ -2434,6 +2436,81 @@ declare class ExpressionEngine {
2434
2436
  * Tests use this to access `batcher._testCaptures` for synchronous
2435
2437
  * event observation without async stream reader timing issues.
2436
2438
  */
2439
+ /**
2440
+ * Put a name back to what the lines above `lineNumber` left it holding.
2441
+ *
2442
+ * The invariant a pass from scratch keeps without trying: when it reaches a
2443
+ * line, every name holds what the lines above defined, because those lines
2444
+ * have just run in order and stored. The incremental path keeps the VM
2445
+ * between passes, so a line that writes a name can find the name holding
2446
+ * its own previous answer instead. That is invisible for `:x = 5`, which
2447
+ * stores over it, and wrong twice over for a definition that reads what it
2448
+ * writes or fails to store:
2449
+ *
2450
+ * - `:v3 = 44` above `:v3 = v3 + 3` is 47 on every pass from scratch, since
2451
+ * line 1 puts 44 back each time. Edit line 1 away and nothing puts
2452
+ * anything back, so line 2 reads its own 47 and climbs by three a pass,
2453
+ * where a pass from scratch says `v3` is undefined.
2454
+ * - `:x = 5` edited to `:x = zz + 1` skips the store, on both paths, and
2455
+ * the incremental one is left holding the 5 the same line stored before
2456
+ * the edit, where a pass from scratch has nothing.
2457
+ *
2458
+ * The checkpoint chain records what each line wrote in document order, so
2459
+ * the value the prefix holds is the one it holds just before this line,
2460
+ * and this puts the VM there: the value if there is one, absent if not.
2461
+ * The evaluator calls it before a definition runs and again if it fails,
2462
+ * both times before the line's own checkpoint is taken, so the checkpoint
2463
+ * records the corrected state.
2464
+ *
2465
+ * A function is a definition too, and was the one kind nothing could
2466
+ * undo: `f(x) = x + 4` edited into a blank left `f(9)` answering 13 for
2467
+ * the rest of the session. The prefix is consulted for a function binding
2468
+ * as well as a variable one, and each is put back on its own, since a
2469
+ * name can be bound in both bags at once (`f(x) = x + 1` above `:f = 4`).
2470
+ * A name bound to neither above is unbound from both.
2471
+ *
2472
+ * An accumulator is left alone. Every pass resets each running total to
2473
+ * its seed and re-runs every line that steps it, in order, so by the time
2474
+ * any step runs the VM already holds what the steps above built, seed
2475
+ * included, and putting the prefix back would only undo a step.
2476
+ *
2477
+ * @param name - The name the line writes.
2478
+ * @param lineNumber - The 1-based line it sits on.
2479
+ */
2480
+ restoreToPrefix(name: string, lineNumber: number): void;
2481
+ /**
2482
+ * Whether `name` is a running total, stepped by `+=` or `-=` somewhere.
2483
+ *
2484
+ * The evaluator's cycle walk asks, because a total's steppers depend on one
2485
+ * another through the total in a way the graph deliberately does not
2486
+ * record: a line is kept out of the consumers of a name it writes, which
2487
+ * is right for `:x = 5` and hides the fold for `spent += 5`.
2488
+ *
2489
+ * @param name - A variable name.
2490
+ * @returns True when a line has stepped it.
2491
+ */
2492
+ /**
2493
+ * Tell the engine whether the line about to run sits on a cycle.
2494
+ *
2495
+ * A line that depends on itself, through positions or names or both, has
2496
+ * no answer of its own: each value it could hold is computed from that same
2497
+ * value a pass earlier. A single fresh pass reports that, because some
2498
+ * member reads a line below it that has not run, and the error travels all
2499
+ * the way round. The incremental path carries the VM between passes, so a
2500
+ * member could find a number to start from, and the pair then chased it.
2501
+ *
2502
+ * While this is set, a positional read of a line below the one running
2503
+ * answers as an unevaluated line does, which is what makes a member report
2504
+ * the cycle rather than the number it read last pass. The evaluator sets it
2505
+ * per line from the cycle membership it keeps, and puts the names such a
2506
+ * line reads back to the prefix before it runs, for the same reason. A line
2507
+ * not on a cycle keeps the incremental path's tolerance of a plain forward
2508
+ * reference, which resolves by running the document again.
2509
+ *
2510
+ * @param onCycle - Whether the line about to run is on a cycle.
2511
+ */
2512
+ setLineOnCycle(onCycle: boolean): void;
2513
+ isAccumulatorName(name: string): boolean;
2437
2514
  /** The names of every user-defined unit in scope, for detecting a removal. */
2438
2515
  userUnitNames(): string[];
2439
2516
  /**
@@ -81,6 +81,21 @@ interface Bytecode {
81
81
  interface LineExecutionContext {
82
82
  /** 1-based current line number, or -1 when there is no real document (see class doc above). */
83
83
  lineIndex: number;
84
+ /**
85
+ * How many lines the document has now; absent when there is no document.
86
+ *
87
+ * A form that declares a span before reading it (see `noteLineRead`) needs
88
+ * to know where the document ends: a range written as `line 1 : line
89
+ * 3000000` has no line to read past the last one, and declaring three
90
+ * million positions that exist nowhere cost the heap for nothing. The
91
+ * walk that reads the span already stops at the first line it cannot use.
92
+ *
93
+ * Asked for rather than copied, because one context serves a document for
94
+ * as long as it is open: a count taken when the context was built was the
95
+ * count before the last insert, and a range declared under it stopped a
96
+ * line short.
97
+ */
98
+ getLineCount?: () => number;
84
99
  /**
85
100
  * Whether this engine may fetch live data (`network.enabled`). A plugin
86
101
  * function that reads a resolver's cache uses it to say "live data is
@@ -98,6 +113,19 @@ interface LineExecutionContext {
98
113
  calendar?: CalendarBackend;
99
114
  /** Look up another line's cached result by 1-based line number. `undefined` = not evaluated yet (or out of range), distinct from a line that evaluated to an actual `undefined`-like Value, which can't happen (every Value type has a concrete representation). */
100
115
  getLineResult?: (lineNumber: number) => Value | undefined;
116
+ /**
117
+ * Say that this line is about to read `lineNumber`, before reading it.
118
+ *
119
+ * A form that reads several lines stops at the first it cannot use, so the
120
+ * lines after that one are never read and, if reading were the only way
121
+ * the dependency graph learned of a read, never recorded. A cycle that
122
+ * closes through one of those lines was then invisible from scratch and
123
+ * visible from a history that had once read the whole span, and the two
124
+ * paths disagreed about whether the line was on a cycle at all. A form
125
+ * declares its whole span through this first, so what the graph knows does
126
+ * not depend on how far the form got. Absent where there is no document.
127
+ */
128
+ noteLineRead?: (lineNumber: number) => void;
101
129
  /**
102
130
  * The 1-based positions of the lines carrying `#tag`, ascending, or
103
131
  * `undefined` when this path keeps no index and the caller should walk the
@@ -519,6 +547,8 @@ interface VM {
519
547
  defineUserFunction(name: string, params: string[], program: BytecodeProgram): void;
520
548
  getUserFunction(name: string): UserFunctionDef | undefined;
521
549
  hasUserFunction(name: string): boolean;
550
+ /** Unbind a user function, for a definition edited away, deleted, or failed. */
551
+ deleteUserFunction(name: string): void;
522
552
  /**
523
553
  * Every session-scoped variable currently defined, as `[name, value]` pairs,
524
554
  * for snapshotting the VM's state (see `engine/EngineSnapshot.ts`). The
@@ -662,6 +692,46 @@ declare class DependencyGraph {
662
692
  */
663
693
  private lastPositionReader;
664
694
  private lastPositionReads;
695
+ /**
696
+ * Readers that recorded a position they had not been recorded reading,
697
+ * since the evaluator last took the list.
698
+ *
699
+ * A positional edge can close a cycle, and the moment it is recorded is the
700
+ * one moment that is knowable: the reader has just run its current text,
701
+ * so the edge is real, and every other edge in the graph describes the
702
+ * last run of the line that holds it. The evaluator takes the list at the
703
+ * end of each pass and looks for a cycle through each reader on it; see
704
+ * `ThreeTierEvaluator.settleCycles`. A line that only
705
+ * re-recorded edges it already had is not on it, which is every line of
706
+ * every pass once a document has settled.
707
+ */
708
+ private readersThatGainedAPosition;
709
+ /**
710
+ * How many recorded positional edges point downwards, from a reader to a
711
+ * line below it.
712
+ *
713
+ * A cycle needs one. Every edge in a document of `prev` and `above` points
714
+ * upwards, positions fall strictly along any path, and no path can come
715
+ * back to where it started. So the evaluator asks this before walking
716
+ * anything, and a document with no forward reference never pays for the
717
+ * walk at all, which is nearly every document and every pass after the one
718
+ * that closed a cycle.
719
+ */
720
+ private downwardPositionReads;
721
+ /**
722
+ * Lines that registered a different edge set since the evaluator last
723
+ * asked, and the keys whose producer set changed.
724
+ *
725
+ * The roots of the end-of-pass cycle walk. A cycle is closed, or a name that
726
+ * pinned one is withdrawn, by a change in the graph; nothing else creates
727
+ * one. A line that re-registers the edges it had is not on the list, which
728
+ * is every line of a settled pass, and it is also a line that is dirty
729
+ * because it threw, which stays dirty and re-runs every pass: rooting the
730
+ * walk on "ran" rather than "changed" made such a line reset its cycle on
731
+ * alternate passes for ever. Taken and cleared by {@link takeEdgeChanges}.
732
+ */
733
+ private edgesChangedThisPass;
734
+ private producersChangedThisPass;
665
735
  /**
666
736
  * Whether this line already carries exactly these edges.
667
737
  *
@@ -729,6 +799,90 @@ declare class DependencyGraph {
729
799
  * @param dependsOnLine - 1-based line whose result it read
730
800
  */
731
801
  registerLinePositionDependency(lineNumber: number, dependsOnLine: number): void;
802
+ /**
803
+ * Cut a line's recorded positions back to the ones its last run read.
804
+ *
805
+ * For the evaluator to call once a line has executed. A positional read is
806
+ * discovered while the line runs, and a position the line has stopped
807
+ * reading cannot be discovered that way, so without this the recorded set
808
+ * only ever grew: `prev + 1` edited to `7` went on reading line 1 in the
809
+ * graph for the rest of the session, and `total above` kept its edges to
810
+ * the lines above a heading that had cut its block short. Anything asking
811
+ * the graph what a line reads was told what it used to read, and a cycle
812
+ * that the heading had broken was still a cycle to the graph, while a cycle
813
+ * that its removal re-closed was not new to it and so was never noticed.
814
+ *
815
+ * A run that read no position at all leaves the line with none. A line
816
+ * that did not execute (compiled only, or skipped) must not be reconciled,
817
+ * since it read nothing for a reason that says nothing about its text.
818
+ *
819
+ * @param lineNumber - 1-based line that has just executed
820
+ */
821
+ reconcilePositionReads(lineNumber: number): void;
822
+ /**
823
+ * Forget every position this line was recorded reading.
824
+ *
825
+ * For a line whose text has just changed, before it runs: whatever the old
826
+ * text read is not evidence about the new one, and a rule consulting the
827
+ * graph between the edit and the run would otherwise be told the old
828
+ * edges. The next run records what the new text reads. Only the `line:`
829
+ * keys go; a data-source pin is discovered the same way but is not about
830
+ * the text, and stays until the line is removed.
831
+ *
832
+ * @param lineNumber - 1-based line whose positions are to go
833
+ */
834
+ forgetPositionReads(lineNumber: number): void;
835
+ /**
836
+ * The positions a line has been recorded reading, as line numbers.
837
+ *
838
+ * The forward direction of {@link getAffectedLinesByPosition}: that answers
839
+ * "who reads this position", this answers "which positions does this line
840
+ * read". Both directions are what finding a cycle takes.
841
+ *
842
+ * @param lineNumber - 1-based line doing the reading
843
+ * @returns The positions it has read, in no particular order; empty if none
844
+ */
845
+ positionsReadBy(lineNumber: number): number[];
846
+ /**
847
+ * The readers that recorded a new position since this was last called, and
848
+ * an empty list until one does.
849
+ *
850
+ * Taking the list clears it. See {@link readersThatGainedAPosition}.
851
+ *
852
+ * @returns The 1-based readers, in the order they recorded
853
+ */
854
+ /**
855
+ * What changed in the graph since this was last called: the lines whose
856
+ * edge set changed, and the keys whose producer set changed. Taking it
857
+ * clears it. See {@link edgesChangedThisPass}.
858
+ *
859
+ * @returns The changed lines and keys, each possibly empty.
860
+ */
861
+ takeEdgeChanges(): {
862
+ lines: readonly number[];
863
+ keys: readonly string[];
864
+ };
865
+ takeReadersThatGainedAPosition(): readonly number[];
866
+ /**
867
+ * Whether any recorded positional edge points from a reader to a line
868
+ * below it.
869
+ *
870
+ * The precondition for a positional cycle, and so for the walk that looks
871
+ * for one; see {@link downwardPositionReads}.
872
+ *
873
+ * @returns True while at least one such edge is recorded
874
+ */
875
+ hasDownwardPositionRead(): boolean;
876
+ /** The positions an entry records, in the recorded half; the same walk {@link positionsReadBy} makes. */
877
+ private positionsReadFrom;
878
+ /**
879
+ * Drop one positional edge from every index that holds it.
880
+ *
881
+ * The consumer index is what says whether the edge exists, so a position the
882
+ * entry lists twice (in the set, and later inside the span that grew over
883
+ * it) is dropped once and counted once.
884
+ */
885
+ private dropPositionRead;
732
886
  /**
733
887
  * Every line that read some position's result, whichever position it was.
734
888
  *
@@ -796,6 +950,20 @@ declare class DependencyGraph {
796
950
  * @param key - The key, from {@link edgeKey}
797
951
  * @returns Set of line numbers that write this key, or empty set if none
798
952
  */
953
+ /**
954
+ * The lines that read `key`, one edge away.
955
+ *
956
+ * The consumer index, which {@link registerLine} keeps clear of the line
957
+ * that writes the key: a definition's read of its own name is a convention
958
+ * for the graph's benefit, not a dependency, and `x += 1` reads its total
959
+ * to step it, not to depend on another line. That is what makes this index
960
+ * the right one for finding a cycle, where the raw reads would make every
961
+ * definition a self-loop and every twice-defined name a two-cycle.
962
+ *
963
+ * @param key - An edge key.
964
+ * @returns The 1-based readers, or an empty set.
965
+ */
966
+ directConsumersOf(key: string): ReadonlySet<number>;
799
967
  getProducers(key: string): ReadonlySet<number>;
800
968
  /**
801
969
  * The keys a line that WRITES something reads.
@@ -1010,9 +1178,13 @@ declare class VMCheckpointer {
1010
1178
  * @param lineNumber 1-based line position.
1011
1179
  * @param lineId Persistent line ID from DocumentModel.
1012
1180
  * @param variableNames Names of variables that were written at this line.
1181
+ * @param functionNames Which of those names the line defined as functions,
1182
+ * from the bytecode it ran. Without it the VM is asked, which cannot tell
1183
+ * a line that defined `f` from one that set the variable `f` under a
1184
+ * function of that name defined above.
1013
1185
  * @returns The new checkpoint, or null if no variable names provided.
1014
1186
  */
1015
- snapshot(lineNumber: number, lineId: number, variableNames: string[]): VMCheckpoint | null;
1187
+ snapshot(lineNumber: number, lineId: number, variableNames: string[], functionNames?: ReadonlySet<string>): VMCheckpoint | null;
1016
1188
  /**
1017
1189
  * Restore the VM to the state at or just after the given line number.
1018
1190
  *
@@ -1087,6 +1259,33 @@ declare class VMCheckpointer {
1087
1259
  *
1088
1260
  * @param names - The names no line defines any more.
1089
1261
  */
1262
+ /**
1263
+ * Drop the entry a line holds, because the line no longer writes anything.
1264
+ *
1265
+ * A line's entry is replaced when the line writes again and left alone
1266
+ * otherwise, so a definition edited into an expression with no definition in
1267
+ * it (`:v3 = 44` edited to `7 + 7`) kept saying `v3 = 44` in the chain. The
1268
+ * lines below it that asked what the prefix holds were told 44, where a pass
1269
+ * from scratch has nothing there. The entry after it is re-parented to the
1270
+ * one before, the same way {@link snapshot} keeps the links straight.
1271
+ *
1272
+ * @param lineNumber - 1-based line whose entry, if any, goes.
1273
+ */
1274
+ dropCheckpointAt(lineNumber: number): void;
1275
+ /**
1276
+ * Follow every line to its new position after a structural edit.
1277
+ *
1278
+ * An insert or a delete moves every line below it, and the chain is read
1279
+ * by position. It used to be cleared instead and rebuilt as lines ran, but
1280
+ * a clean line above the viewport never runs, so its entry was gone for
1281
+ * good and a line below asking what the prefix held was told nothing:
1282
+ * `:a = 5` above the viewport was reported as undefined by `:b = a + c`
1283
+ * under it. Each entry follows its line by id, the entry of a deleted
1284
+ * line goes, and the parents are linked again in the new order.
1285
+ *
1286
+ * @param positionOf - The 1-based position a line id has now, or -1 for a line that is gone.
1287
+ */
1288
+ renumber(positionOf: (lineId: number) => number): void;
1090
1289
  forget(names: readonly string[]): void;
1091
1290
  /**
1092
1291
  * Find the nearest checkpoint at or before the given line number.
@@ -1122,6 +1321,38 @@ declare class VMCheckpointer {
1122
1321
  *
1123
1322
  * @returns The Value, or undefined if the variable was never set.
1124
1323
  */
1324
+ /**
1325
+ * The value a name held at the end of the line before `lineNumber`, or
1326
+ * undefined if no line above it had set one.
1327
+ *
1328
+ * What a definition that failed leaves behind. A pass from scratch skips
1329
+ * the store when the right-hand side errors, so the name keeps whatever the
1330
+ * lines above it had put there: `:x = 1` then `:x = zz` leaves `x` at 1,
1331
+ * and `:x = zz` on its own leaves it undefined. The incremental path holds
1332
+ * the value from the previous pass instead, which for the line that failed
1333
+ * is its own old answer, so the evaluator asks here what the prefix holds
1334
+ * and puts that back. The chain records what each line wrote, in document
1335
+ * order, so the entry nearest before the line, followed through its
1336
+ * parents, is exactly the prefix.
1337
+ *
1338
+ * @param name - The variable.
1339
+ * @param lineNumber - The 1-based line whose own entry is to be excluded.
1340
+ * @returns The value the lines above set, or undefined.
1341
+ */
1342
+ /**
1343
+ * The function a name was bound to at the end of the line before
1344
+ * `lineNumber`, or undefined if no line above it had defined one.
1345
+ *
1346
+ * {@link lookupVariableBefore}, for the functions bag: a function
1347
+ * definition is a definition, and one edited away or failed leaves the name
1348
+ * as the lines above left it just as a variable does.
1349
+ *
1350
+ * @param name - The function name.
1351
+ * @param lineNumber - The 1-based line whose own entry is to be excluded.
1352
+ * @returns The definition the lines above made, or undefined.
1353
+ */
1354
+ lookupFunctionBefore(name: string, lineNumber: number): UserFunctionDef | undefined;
1355
+ lookupVariableBefore(name: string, lineNumber: number): Value | undefined;
1125
1356
  lookupVariable(name: string): Value | undefined;
1126
1357
  /**
1127
1358
  * Clear all checkpoints. The underlying VM is NOT reset, call