This site describes solve-engine 2.44.0, the version npm installs.
LineExecutionContext
Defined in: packages/engine/src/vm/VM.ts:329
Per-line execution context, threaded optionally through
executeBytecode down to CALL_PLUGIN’s plugin-function handlers
(see vm/VMBuiltins.ts’s pluginFunctionRegistry).
Exists so a package can implement cross-line features (prev, line<N>,
range/above aggregation. See packages/lines/) without every other
plugin function having to care: it’s optional, and every existing
handler ignores it unchanged. Before this, a plugin function’s only
input was its own call-site arguments, no line number, no access to
any other line’s cached result. getLineResult/isLineBoundary are
both undefined when there’s no real document (e.g.
ExpressionEngine.evaluateExpression()’s single-expression path, which
uses lineIndex = -1 as its existing “no document” sentinel), a
plugin function needing document access must check for that itself
and return a clear error, never silently treat it as line 0.
Properties
Section titled “Properties”calendar?
Section titled “calendar?”calendar?: CalendarBackend;Defined in: packages/engine/src/vm/VM.ts:369
The calendar backend this engine computes dates with (EngineContext.calendar).
A plugin function that reads or steps a date computes through it, so the
date it answers agrees with the one the VM’s own opcodes would produce.
Absent means the Date backend; calendarOf() in
calendar/DateCalendar.ts resolves either case.
evaluateLineWithBinding?
Section titled “evaluateLineWithBinding?”evaluateLineWithBinding?: (lineNumber, variable, bound, symbolicTolerant) => Value;Defined in: packages/engine/src/vm/VM.ts:519
Re-evaluate another line’s already-compiled expression with variable
bound to bound for that one evaluation, without disturbing the
document’s own value for it. This is the primitive goal seek
(packages/goalseek/) drives: binding a numeric candidate probes the
relationship, binding a symbolic placeholder (with symbolicTolerant)
reads it back in closed form. Returns an error Value when there is no
document, the line is not a plain expression ready to run, or its
re-evaluation itself faults. The binding is a call frame, so it shadows
the document’s value exactly the way a function parameter does and is
gone the moment the probe returns.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
variable | string |
bound | Value |
symbolicTolerant | boolean |
Returns
Section titled “Returns”getLineCount?
Section titled “getLineCount?”getLineCount?: () => number;Defined in: packages/engine/src/vm/VM.ts:346
How many lines the document has now; absent when there is no document.
A form that declares a span before reading it (see noteLineRead) needs
to know where the document ends: a range written as line 1 : line 3000000 has no line to read past the last one, and declaring three
million positions that exist nowhere cost the heap for nothing. The
walk that reads the span already stops at the first line it cannot use.
Asked for rather than copied, because one context serves a document for as long as it is open: a count taken when the context was built was the count before the last insert, and a range declared under it stopped a line short.
Returns
Section titled “Returns”number
getLineReads?
Section titled “getLineReads?”getLineReads?: (lineNumber) => string[] | undefined;Defined in: packages/engine/src/vm/VM.ts:497
The variables another line’s expression reads, by 1-based line number, or
undefined when the line has no evaluated expression (forward reference,
out of range, or markdown). Goal seek (packages/goalseek/) uses it to
refuse up front when the variable it was asked to vary is one the target
line never reads, rather than searching a relationship that cannot move.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”string[] | undefined
getLineResult?
Section titled “getLineResult?”getLineResult?: (lineNumber, declared?) => Value | undefined;Defined in: packages/engine/src/vm/VM.ts:419
Look up another line’s cached result by 1-based line number. undefined
means not evaluated yet, out of range, or below this line: a note is
read from the top, so a line further down is never read, on any pass.
No Value is undefined-like, so the two cannot be confused.
On the incremental path a read records that this line depends on that
position. Pass declared as true for a read an edge the form already
took covers (a member of a tag asked for through
getTaggedLines, a line inside a span given to
noteFigureSpanRead), so the graph records nothing more; a form
that reads a thousand members then costs one edge, not a thousand.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
declared? | boolean |
Returns
Section titled “Returns”Value | undefined
getLineText?
Section titled “getLineText?”getLineText?: (lineNumber) => string | undefined;Defined in: packages/engine/src/vm/VM.ts:585
The RAW markdown text of line lineNumber (1-based), or undefined
when there is no real document or the line is out of range. Distinct
from getLineResult, which returns a line’s evaluated Value: a
markdown table’s rows are skipped by the evaluator and hold no result,
so reading a column as data has to go back to the source text. Backs
the tables package (packages/tables/), which walks upward from the
current line to find the nearest table and read one of its columns.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”string | undefined
getTaggedLines?
Section titled “getTaggedLines?”getTaggedLines?: (tag) => readonly number[] | undefined;Defined in: packages/engine/src/vm/VM.ts:462
The 1-based positions of the lines carrying #tag, ascending, or
undefined when this path keeps no index and the caller should walk the
document itself.
total of #tag used to look at every line of the document, so a notepad
of tagged amounts and totals cost aggregates x lines per pass. Both
document paths maintain an index instead, and answer from it here.
Asking is also what tells the dependency graph that this line reads
every line carrying the tag, as one edge on the tag rather than one per
member (#733), so a form that asks here needs no noteLineRead for the
members. A line joining or leaving the group later is covered by the
same edge.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
tag | string |
Returns
Section titled “Returns”readonly number[] | undefined
getTagGroups?
Section titled “getTagGroups?”getTagGroups?: () => ReadonlyMap<string, readonly number[]> | undefined;Defined in: packages/engine/src/vm/VM.ts:474
Every category tag the document’s lines carry, lower-cased, each with the
1-based positions of its lines ascending, or undefined when this path
keeps no index and the caller should walk the document itself.
What total by tag reads its groups from (#734). The answer is the same
object for as long as the document’s text is unchanged, within a pass
and across passes, so a form may key work of its own on it. Asking tells
the dependency graph that this line reads every tagged line, as one
edge, the way getTaggedLines does for one tag.
Returns
Section titled “Returns”ReadonlyMap<string, readonly number[]> | undefined
getVariable?
Section titled “getVariable?”getVariable?: (name) => Value | undefined;Defined in: packages/engine/src/vm/VM.ts:506
The value the document gives a name as it stands, or undefined when no
line has set it. Goal seek reads it to learn the unit its unknown is in,
so solve line 3 for price = £1,500 answers in pounds when price is an
amount of pounds (#835), and a line that is only sum or total reads it
before it totals the block above (#742). Present on every path the engine
builds a context for, a single expression included.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
Returns
Section titled “Returns”Value | undefined
goalSeekMaxIterations?
Section titled “goalSeekMaxIterations?”goalSeekMaxIterations?: number;Defined in: packages/engine/src/vm/VM.ts:531
The hard ceiling on goal seek’s bisection steps, from
config.vm.maxGoalSeekIterations. Carried on the context so the search,
which runs as a plugin function with no other view of engine config, is
bounded by the host’s configured limit rather than a hardcoded one.
inWhatIf?
Section titled “inWhatIf?”inWhatIf?: boolean;Defined in: packages/engine/src/vm/VM.ts:354
Set when this pass runs a what-if’s scenario (line 4 with deposit = 150000), which works each line out once in a scratch engine. A form that
re-runs another line (goal seek) names that as the reason it cannot
answer here, rather than the batch pass or a single expression, which the
reader did not write.
isBlockEnd?
Section titled “isBlockEnd?”isBlockEnd?: (lineNumber) => boolean;Defined in: packages/engine/src/vm/VM.ts:489
Whether line lineNumber ends the block of figures total above and
average above read: a blank line, a heading, a rule, a fence or a table
(see lexer/BlockBoundary). A line with no figure that does not end the
block, a comment or a blockquote, is passed over (#652). When absent the
aggregates stop at isLineBoundary, as they did before.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”boolean
isLineBoundary?
Section titled “isLineBoundary?”isLineBoundary?: (lineNumber) => boolean;Defined in: packages/engine/src/vm/VM.ts:481
Whether line lineNumber has no figure to read: a blank line, a #
heading, or a line the classifier skips (a comment, a blockquote, table
markup). A line range passes over such a line; the section and tag
forms read it the same way.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”boolean
lineIndex
Section titled “lineIndex”lineIndex: number;Defined in: packages/engine/src/vm/VM.ts:331
1-based current line number, or -1 when there is no real document (see class doc above).
networkEnabled?
Section titled “networkEnabled?”networkEnabled?: boolean;Defined in: packages/engine/src/vm/VM.ts:361
Whether this engine may fetch live data (network.enabled). A plugin
function that reads a resolver’s cache uses it to say “live data is
switched off” when the cache is empty, rather than the “not preflighted”
message that describes a different fault. Absent means enabled.
noteFigureSpanRead?
Section titled “noteFigureSpanRead?”noteFigureSpanRead?: (first, last) => void;Defined in: packages/engine/src/vm/VM.ts:446
Say that this line reads the figures on lines first to last, before
reading any of them: every line in the span except a summary line (a
total above, a section or tag total), which a span of figures passes
over, as a section total does.
One edge however long the span, where noteLineRead per member is one per line (#733). The graph asks the document which lines in the span are summaries when it follows the edge back, so two totals of one section are not taken to read each other. Absent where there is no document; a form falls back to noteLineRead then, or skips the declaration where that is absent too.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
first | number |
last | number |
Returns
Section titled “Returns”void
noteLineRead?
Section titled “noteLineRead?”noteLineRead?: (lineNumber) => void;Defined in: packages/engine/src/vm/VM.ts:432
Say that this line is about to read lineNumber, before reading it.
A form that reads several lines stops at the first it cannot use, so the lines after that one are never read and, if reading were the only way the dependency graph learned of a read, never recorded. A cycle that closes through one of those lines was then invisible from scratch and visible from a history that had once read the whole span, and the two paths disagreed about whether the line was on a cycle at all. A form declares its whole span through this first, so what the graph knows does not depend on how far the form got. Absent where there is no document.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”void
observeCall?
Section titled “observeCall?”observeCall?: (call) => void;Defined in: packages/engine/src/vm/VM.ts:597
Receives every call the VM makes while this line runs: a built-in
function, a package’s plugin function, an as converter, or a unit or
currency conversion, each with its arguments and the value it pushed.
Set only by ExpressionEngine.explainLine(), which runs the line once
more with this attached so a derivation can name each step with the
engine’s own numbers. Absent on every ordinary evaluation, where the VM
reads it once per program and never calls anything, so evaluation costs
the same with or without explaining.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
call | ObservedCall |
Returns
Section titled “Returns”void
queryClient?
Section titled “queryClient?”queryClient?: QueryClient;Defined in: packages/engine/src/vm/VM.ts:386
The query cache of the engine running this line, where its asynchronous
resolvers keep what they fetched. A plugin function that reads a
resolved value back (createQueryResolver’s, the historical currency
conversion’s) reads it from here, so it reads its own engine’s cache
however many engines share the process (#710). Absent on a context no
engine built; such a handler falls back to the deprecated
getActiveQueryClient().
random?
Section titled “random?”random?: () => number;Defined in: packages/engine/src/vm/VM.ts:397
The random source this line draws from, a number in [0, 1) per call, the
way calendar is the clock. roll, random(), pick, shuffle,
coin and uuid all read it. Unseeded it is Math.random; with a seed
(createEngine({ random: { seed } }) or a random seed line) it is a
stream keyed on the seed and this line’s own compiled program, so a draw
is the same on every run and changes only when its line is edited.
Absent means Math.random. A function rather than a value because the
context object is reused across a pass (see lineIndex).
Returns
Section titled “Returns”number
readScenario?
Section titled “readScenario?”readScenario?: (name, lineNumber) => Value;Defined in: packages/engine/src/vm/VM.ts:575
What line lineNumber says with the inputs of the scenario named name
in force (line 5 under bull, #744), or the error that stops it.
The scenario is the scenario <name> with ... line above the asking
line; none, or two with the same name, is refused by name. It is read as
the what-if it stands for (line 5 with ..., with the declaration’s
inputs), evaluated where the asking line stands, so every what-if
refusal is a scenario’s too. Every line above the asking line is read,
so an edit to any of them re-runs it. Absent where there is no document.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
lineNumber | number |
Returns
Section titled “Returns”rerunLines?
Section titled “rerunLines?”rerunLines?: (lineNumber) => | Value | LineRerun;Defined in: packages/engine/src/vm/VM.ts:563
Open a re-run of the document up to and including lineNumber, for
asking what that line would say if some inputs were different. This is
the primitive the what-if and sweep forms (packages/whatif/) drive.
Unlike evaluateLineWithBinding, which re-runs one line with one
name bound in a call frame, this re-runs every line from the top of the
document to the target, from their text, in a scratch engine of its own.
So an input the target reads through another line (payment on line 3
reading deposit, line 4 reading payment) reaches it, and nothing the
document holds (its variables, its cached results, its dependency graph)
is touched: the scratch engine is thrown away when the session closes.
Returns the session, or an error Value when there is nothing to re-run:
the line is out of range, the re-run would be nested inside another one,
or a line in the span writes a global :name, which other documents read.
Absent where there is no document (the single-expression path). The caller
must LineRerun.close the session, in a finally.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”scope?
Section titled “scope?”scope?: ScopeId;Defined in: packages/engine/src/vm/VM.ts:405
The scope this line executes under: the owner of a global :name cell it
writes. Absent on a path with no engine context of its own (a warm-up run,
the worker, a lone evaluateExpression); the cell opcodes fall back to the
engine’s own EngineContext.scope there. See vm/CellScope.ts and
docs-internal/plans/CROSS_SCOPE_CELLS.md.
spendWork?
Section titled “spendWork?”spendWork?: (lineRuns, form) => Value | null;Defined in: packages/engine/src/vm/VM.ts:543
Charge work that reaches across lines to the current pass, in line runs:
a what-if or sweep re-running lines, a span aggregate reading them (goal
seek’s probes are charged by evaluateLineWithBinding itself).
Returns the refusal when the charge would take the pass past
config.vm.maxLineRunsPerPass, and null, having counted it, when it fits
(#711). A function rather than a count, since this context serves a whole
pass. Absent where there is no document: the single-expression path,
whose cross-line forms refuse before they would spend anything. See
vm/PassWork.ts.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineRuns | number |
form | string |
Returns
Section titled “Returns”Value | null
traceLine?
Section titled “traceLine?”traceLine?: (lineNumber) => LineTrace;Defined in: packages/engine/src/vm/VM.ts:605
The lines that fed line lineNumber’s answer, followed upwards, for the
inputs of line N form. A forward reference (a line reading a line below
it) is reported in the trace and not followed, since from inside a pass
the line below has not been worked out. Absent when there is no document
to trace in. See ExpressionEngine.traceLine().
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
lineNumber | number |
Returns
Section titled “Returns”week?: WeekShape;Defined in: packages/engine/src/vm/VM.ts:376
The shape of the week this engine keeps (EngineContext.week): its
weekend days and the day a week starts on. Absent means Saturday and
Sunday off, starting on Monday; weekOf() in calendar/WeekShape.ts
resolves either case.