openalgo-script 0.5.0 → 0.6.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/CHANGELOG.md +121 -0
- package/README.md +53 -22
- package/dist/adapters/charts/run.d.ts.map +1 -1
- package/dist/adapters/charts/run.js +6 -0
- package/dist/adapters/charts/run.js.map +1 -1
- package/dist/adapters/charts/tables.d.ts +6 -19
- package/dist/adapters/charts/tables.d.ts.map +1 -1
- package/dist/adapters/charts/tables.js.map +1 -1
- package/dist/adapters/charts/undrawable.d.ts +4 -0
- package/dist/adapters/charts/undrawable.d.ts.map +1 -0
- package/dist/adapters/charts/undrawable.js +47 -0
- package/dist/adapters/charts/undrawable.js.map +1 -0
- package/dist/core/backtest/drive.d.ts +36 -1
- package/dist/core/backtest/drive.d.ts.map +1 -1
- package/dist/core/backtest/drive.js +13 -107
- package/dist/core/backtest/drive.js.map +1 -1
- package/dist/core/backtest/index.d.ts +2 -0
- package/dist/core/backtest/index.d.ts.map +1 -1
- package/dist/core/backtest/index.js.map +1 -1
- package/dist/core/backtest/walk.d.ts +39 -0
- package/dist/core/backtest/walk.d.ts.map +1 -0
- package/dist/core/backtest/walk.js +125 -0
- package/dist/core/backtest/walk.js.map +1 -0
- package/dist/core/catalogue/catalogue.generated.d.ts +178 -1
- package/dist/core/catalogue/catalogue.generated.d.ts.map +1 -1
- package/dist/core/catalogue/catalogue.generated.js +18 -1
- package/dist/core/catalogue/catalogue.generated.js.map +1 -1
- package/dist/core/catalogue/types.d.ts +8 -2
- package/dist/core/catalogue/types.d.ts.map +1 -1
- package/dist/core/catalogue/values.generated.d.ts +51 -0
- package/dist/core/catalogue/values.generated.d.ts.map +1 -1
- package/dist/core/check/assigned.d.ts +19 -0
- package/dist/core/check/assigned.d.ts.map +1 -0
- package/dist/core/check/assigned.js +14 -0
- package/dist/core/check/assigned.js.map +1 -0
- package/dist/core/check/call-sites.d.ts.map +1 -1
- package/dist/core/check/call-sites.js +9 -4
- package/dist/core/check/call-sites.js.map +1 -1
- package/dist/core/check/calls.d.ts.map +1 -1
- package/dist/core/check/calls.js +12 -4
- package/dist/core/check/calls.js.map +1 -1
- package/dist/core/check/check.d.ts.map +1 -1
- package/dist/core/check/check.js +15 -2
- package/dist/core/check/check.js.map +1 -1
- package/dist/core/check/checker.d.ts +26 -0
- package/dist/core/check/checker.d.ts.map +1 -1
- package/dist/core/check/checker.js +38 -2
- package/dist/core/check/checker.js.map +1 -1
- package/dist/core/check/constant.d.ts +16 -0
- package/dist/core/check/constant.d.ts.map +1 -1
- package/dist/core/check/constant.js +52 -0
- package/dist/core/check/constant.js.map +1 -1
- package/dist/core/check/deleted.d.ts +3 -0
- package/dist/core/check/deleted.d.ts.map +1 -0
- package/dist/core/check/deleted.js +109 -0
- package/dist/core/check/deleted.js.map +1 -0
- package/dist/core/check/expressions.js +1 -1
- package/dist/core/check/expressions.js.map +1 -1
- package/dist/core/check/library-output.d.ts.map +1 -1
- package/dist/core/check/library-output.js +1 -0
- package/dist/core/check/library-output.js.map +1 -1
- package/dist/core/check/library-prose.generated.js +10 -10
- package/dist/core/check/library-prose.generated.js.map +1 -1
- package/dist/core/check/library.d.ts +7 -0
- package/dist/core/check/library.d.ts.map +1 -1
- package/dist/core/check/library.js +1 -0
- package/dist/core/check/library.js.map +1 -1
- package/dist/core/check/surface.d.ts +9 -0
- package/dist/core/check/surface.d.ts.map +1 -1
- package/dist/core/check/surface.js +13 -0
- package/dist/core/check/surface.js.map +1 -1
- package/dist/core/engine/bar-source.d.ts +65 -0
- package/dist/core/engine/bar-source.d.ts.map +1 -0
- package/dist/core/engine/bar-source.js +58 -0
- package/dist/core/engine/bar-source.js.map +1 -0
- package/dist/core/engine/engine.d.ts +9 -11
- package/dist/core/engine/engine.d.ts.map +1 -1
- package/dist/core/engine/engine.js +24 -24
- package/dist/core/engine/engine.js.map +1 -1
- package/dist/core/engine/guard.d.ts.map +1 -1
- package/dist/core/engine/guard.js +10 -0
- package/dist/core/engine/guard.js.map +1 -1
- package/dist/core/engine/host.d.ts +4 -2
- package/dist/core/engine/host.d.ts.map +1 -1
- package/dist/core/engine/host.js.map +1 -1
- package/dist/core/engine/index.d.ts +1 -0
- package/dist/core/engine/index.d.ts.map +1 -1
- package/dist/core/engine/index.js.map +1 -1
- package/dist/core/engine/library/binding.d.ts +2 -0
- package/dist/core/engine/library/binding.d.ts.map +1 -1
- package/dist/core/engine/library/binding.js.map +1 -1
- package/dist/core/engine/library/index.d.ts +8 -0
- package/dist/core/engine/library/index.d.ts.map +1 -1
- package/dist/core/engine/library/index.js +10 -0
- package/dist/core/engine/library/index.js.map +1 -1
- package/dist/core/engine/library/objects.d.ts.map +1 -1
- package/dist/core/engine/library/objects.js +1 -1
- package/dist/core/engine/library/objects.js.map +1 -1
- package/dist/core/engine/request-body.d.ts +3 -1
- package/dist/core/engine/request-body.d.ts.map +1 -1
- package/dist/core/engine/request-body.js +3 -1
- package/dist/core/engine/request-body.js.map +1 -1
- package/dist/core/engine/request-plan.d.ts +3 -3
- package/dist/core/engine/request-plan.js +3 -3
- package/dist/core/engine/requests.d.ts +2 -2
- package/dist/core/engine/requests.d.ts.map +1 -1
- package/dist/core/engine/requests.js +5 -4
- package/dist/core/engine/requests.js.map +1 -1
- package/dist/core/engine/series.d.ts +18 -6
- package/dist/core/engine/series.d.ts.map +1 -1
- package/dist/core/engine/series.js +24 -5
- package/dist/core/engine/series.js.map +1 -1
- package/dist/core/engine/session/record.d.ts +4 -4
- package/dist/core/engine/session/record.js +4 -4
- package/dist/core/importer/calls.d.ts +29 -0
- package/dist/core/importer/calls.d.ts.map +1 -0
- package/dist/core/importer/calls.js +267 -0
- package/dist/core/importer/calls.js.map +1 -0
- package/dist/core/importer/context.d.ts +118 -0
- package/dist/core/importer/context.d.ts.map +1 -0
- package/dist/core/importer/context.js +120 -0
- package/dist/core/importer/context.js.map +1 -0
- package/dist/core/importer/expressions.d.ts +44 -0
- package/dist/core/importer/expressions.d.ts.map +1 -0
- package/dist/core/importer/expressions.js +223 -0
- package/dist/core/importer/expressions.js.map +1 -0
- package/dist/core/importer/importer.d.ts +13 -0
- package/dist/core/importer/importer.d.ts.map +1 -0
- package/dist/core/importer/importer.js +220 -0
- package/dist/core/importer/importer.js.map +1 -0
- package/dist/core/importer/index.d.ts +20 -0
- package/dist/core/importer/index.d.ts.map +1 -0
- package/dist/core/importer/index.js +18 -0
- package/dist/core/importer/index.js.map +1 -0
- package/dist/core/importer/lexer.d.ts +68 -0
- package/dist/core/importer/lexer.d.ts.map +1 -0
- package/dist/core/importer/lexer.js +207 -0
- package/dist/core/importer/lexer.js.map +1 -0
- package/dist/core/importer/names.d.ts +41 -0
- package/dist/core/importer/names.d.ts.map +1 -0
- package/dist/core/importer/names.js +78 -0
- package/dist/core/importer/names.js.map +1 -0
- package/dist/core/importer/orders.d.ts +8 -0
- package/dist/core/importer/orders.d.ts.map +1 -0
- package/dist/core/importer/orders.js +332 -0
- package/dist/core/importer/orders.js.map +1 -0
- package/dist/core/importer/outputs.d.ts +19 -0
- package/dist/core/importer/outputs.d.ts.map +1 -0
- package/dist/core/importer/outputs.js +266 -0
- package/dist/core/importer/outputs.js.map +1 -0
- package/dist/core/importer/parser.d.ts +5 -0
- package/dist/core/importer/parser.d.ts.map +1 -0
- package/dist/core/importer/parser.js +439 -0
- package/dist/core/importer/parser.js.map +1 -0
- package/dist/core/importer/presence.d.ts +32 -0
- package/dist/core/importer/presence.d.ts.map +1 -0
- package/dist/core/importer/presence.js +146 -0
- package/dist/core/importer/presence.js.map +1 -0
- package/dist/core/importer/settle.d.ts +23 -0
- package/dist/core/importer/settle.d.ts.map +1 -0
- package/dist/core/importer/settle.js +135 -0
- package/dist/core/importer/settle.js.map +1 -0
- package/dist/core/importer/statements.d.ts +4 -0
- package/dist/core/importer/statements.d.ts.map +1 -0
- package/dist/core/importer/statements.js +339 -0
- package/dist/core/importer/statements.js.map +1 -0
- package/dist/core/importer/syntax.d.ts +182 -0
- package/dist/core/importer/syntax.d.ts.map +1 -0
- package/dist/core/importer/syntax.js +14 -0
- package/dist/core/importer/syntax.js.map +1 -0
- package/dist/core/importer/table.d.ts +52 -0
- package/dist/core/importer/table.d.ts.map +1 -0
- package/dist/core/importer/table.js +156 -0
- package/dist/core/importer/table.js.map +1 -0
- package/dist/core/importer/values.d.ts +27 -0
- package/dist/core/importer/values.d.ts.map +1 -0
- package/dist/core/importer/values.js +236 -0
- package/dist/core/importer/values.js.map +1 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/stdlib/calendar/civil.d.ts.map +1 -1
- package/dist/core/stdlib/calendar/civil.js +5 -2
- package/dist/core/stdlib/calendar/civil.js.map +1 -1
- package/dist/core/version/version.generated.d.ts +1 -1
- package/dist/core/version/version.generated.js +1 -1
- package/package.json +5 -2
- package/spec/errors.json +380 -20
- package/src/adapters/charts/run.ts +6 -0
- package/src/adapters/charts/tables.ts +6 -19
- package/src/adapters/charts/undrawable.ts +51 -0
- package/src/core/backtest/drive.ts +66 -154
- package/src/core/backtest/index.ts +2 -0
- package/src/core/backtest/walk.ts +182 -0
- package/src/core/catalogue/catalogue.generated.ts +18 -1
- package/src/core/catalogue/types.ts +8 -2
- package/src/core/catalogue/values.generated.ts +16 -0
- package/src/core/check/assigned.ts +31 -0
- package/src/core/check/call-sites.ts +11 -4
- package/src/core/check/calls.ts +13 -4
- package/src/core/check/check.ts +14 -2
- package/src/core/check/checker.ts +39 -2
- package/src/core/check/constant.ts +57 -0
- package/src/core/check/deleted.ts +135 -0
- package/src/core/check/expressions.ts +1 -1
- package/src/core/check/library-output.ts +1 -0
- package/src/core/check/library-prose.generated.ts +10 -10
- package/src/core/check/library.ts +8 -0
- package/src/core/check/surface.ts +16 -0
- package/src/core/engine/bar-source.ts +113 -0
- package/src/core/engine/engine.ts +26 -25
- package/src/core/engine/guard.ts +12 -1
- package/src/core/engine/host.ts +4 -2
- package/src/core/engine/index.ts +1 -0
- package/src/core/engine/library/binding.ts +2 -0
- package/src/core/engine/library/index.ts +11 -0
- package/src/core/engine/library/objects.ts +1 -6
- package/src/core/engine/request-body.ts +5 -7
- package/src/core/engine/request-plan.ts +3 -3
- package/src/core/engine/requests.ts +11 -8
- package/src/core/engine/series.ts +30 -6
- package/src/core/engine/session/record.ts +4 -4
- package/src/core/importer/calls.ts +274 -0
- package/src/core/importer/context.ts +197 -0
- package/src/core/importer/expressions.ts +247 -0
- package/src/core/importer/importer.ts +226 -0
- package/src/core/importer/index.ts +19 -0
- package/src/core/importer/lexer.ts +285 -0
- package/src/core/importer/names.ts +104 -0
- package/src/core/importer/orders.ts +307 -0
- package/src/core/importer/outputs.ts +245 -0
- package/src/core/importer/parser.ts +436 -0
- package/src/core/importer/presence.ts +164 -0
- package/src/core/importer/settle.ts +141 -0
- package/src/core/importer/statements.ts +331 -0
- package/src/core/importer/syntax.ts +144 -0
- package/src/core/importer/table.ts +191 -0
- package/src/core/importer/values.ts +241 -0
- package/src/core/index.ts +13 -0
- package/src/core/stdlib/calendar/civil.ts +5 -2
- package/src/core/version/version.generated.ts +1 -1
|
@@ -49,7 +49,9 @@ import type { CompiledProgram, Position } from './types.js';
|
|
|
49
49
|
import type { RequestPlan } from './request-plan.js';
|
|
50
50
|
import { NO_SESSION, sessionReader } from './session/index.js';
|
|
51
51
|
import type { SessionReader } from './session/index.js';
|
|
52
|
-
import {
|
|
52
|
+
import { handOver, noBars } from './series.js';
|
|
53
|
+
import { KnownBars, sourceOf } from './bar-source.js';
|
|
54
|
+
import type { BarColumns } from './bar-source.js';
|
|
53
55
|
import { barMinutesOf } from './timeframe.js';
|
|
54
56
|
import { RequestSet } from './requests.js';
|
|
55
57
|
import type { Value } from './values/index.js';
|
|
@@ -96,7 +98,7 @@ export class Engine {
|
|
|
96
98
|
* chart bar is inside, and on a live feed there is nothing there yet. That is
|
|
97
99
|
* the mode repainting on history, permanently and by design.
|
|
98
100
|
*/
|
|
99
|
-
private known
|
|
101
|
+
private readonly known = new KnownBars();
|
|
100
102
|
|
|
101
103
|
private supplied = 0;
|
|
102
104
|
private index = -1;
|
|
@@ -230,7 +232,7 @@ export class Engine {
|
|
|
230
232
|
// that has already failed keeps the failure it has, which is the one that
|
|
231
233
|
// explains what went wrong first.
|
|
232
234
|
if (this.failure === undefined) {
|
|
233
|
-
const problem =
|
|
235
|
+
const problem = handOver(bar, this.known.at(this.index), this.index + 1);
|
|
234
236
|
if (problem !== undefined) return this.refuse(problem);
|
|
235
237
|
}
|
|
236
238
|
if (this.started) this.checkpoint();
|
|
@@ -239,7 +241,7 @@ export class Engine {
|
|
|
239
241
|
this.updates = 1;
|
|
240
242
|
this.started = true;
|
|
241
243
|
this.previousClose = this.lastClose;
|
|
242
|
-
if (this.known.length <= this.index) this.known
|
|
244
|
+
if (this.known.length <= this.index) this.known.set(this.index, bar);
|
|
243
245
|
return this.execute(bar, state, true);
|
|
244
246
|
}
|
|
245
247
|
|
|
@@ -257,14 +259,14 @@ export class Engine {
|
|
|
257
259
|
// update whose time has moved back onto the bar before it is a series the
|
|
258
260
|
// engine cannot run on, whatever it is called.
|
|
259
261
|
if (this.failure === undefined) {
|
|
260
|
-
const problem =
|
|
262
|
+
const problem = handOver(bar, this.known.at(this.index - 1), this.index);
|
|
261
263
|
if (problem !== undefined) return this.refuse(problem);
|
|
262
264
|
}
|
|
263
265
|
this.rollback();
|
|
264
266
|
this.updates += 1;
|
|
265
267
|
// A revision replaces the bar the fold already read, so the bucket it is
|
|
266
268
|
// inside is rebuilt from this reading rather than from the one it replaced.
|
|
267
|
-
this.known
|
|
269
|
+
this.known.set(this.index, bar);
|
|
268
270
|
return this.execute(bar, state, false);
|
|
269
271
|
}
|
|
270
272
|
|
|
@@ -282,27 +284,34 @@ export class Engine {
|
|
|
282
284
|
* pane with nothing drawn on it is what a study that computed nothing also
|
|
283
285
|
* produces and only the engine can tell the two apart.
|
|
284
286
|
*/
|
|
285
|
-
run(bars: readonly HostBar[], states: readonly BarState[] = []): RunResult {
|
|
287
|
+
run(bars: readonly HostBar[] | BarColumns, states: readonly BarState[] = []): RunResult {
|
|
288
|
+
const source = sourceOf(bars);
|
|
286
289
|
const out: BarResult[] = [];
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
// which would run no iterations and return a clean, empty, wordless result.
|
|
290
|
-
if (bars.length === 0 && !this.started) {
|
|
290
|
+
// No bars at all is answered here: the loop below would return an empty, wordless result.
|
|
291
|
+
if (source.length === 0 && !this.started) {
|
|
291
292
|
const diagnostic = this.failure ?? noBars(this.options.host?.instrument);
|
|
292
293
|
this.failure = diagnostic;
|
|
293
294
|
return { bars: [], diagnostic };
|
|
294
295
|
}
|
|
295
|
-
this.known
|
|
296
|
-
for (let i = 0; i <
|
|
297
|
-
const bar =
|
|
296
|
+
this.known.reset(source);
|
|
297
|
+
for (let i = 0; i < source.length; i += 1) {
|
|
298
|
+
const bar = source.at(i);
|
|
298
299
|
if (bar === undefined) continue;
|
|
299
|
-
const result = this.append(bar, states[i] ?? {},
|
|
300
|
+
const result = this.append(bar, states[i] ?? {}, source.length);
|
|
300
301
|
out.push(result);
|
|
301
302
|
if (result.diagnostic !== undefined) return { bars: out, diagnostic: result.diagnostic };
|
|
302
303
|
}
|
|
303
304
|
return { bars: out, diagnostic: undefined };
|
|
304
305
|
}
|
|
305
306
|
|
|
307
|
+
/**
|
|
308
|
+
* The dataset a driver appends one bar at a time, handed to the fold before
|
|
309
|
+
* bar 0 as `run` hands it, so a `"lookahead"` read reads it as history.
|
|
310
|
+
*/
|
|
311
|
+
history(bars: readonly HostBar[] | BarColumns): void {
|
|
312
|
+
if (!this.started) this.known.reset(sourceOf(bars));
|
|
313
|
+
}
|
|
314
|
+
|
|
306
315
|
/**
|
|
307
316
|
* A frame from the destination, `host-interface.md` 7.2. Held until the next
|
|
308
317
|
* bar begins rather than folded where it lands: nothing reaches a running
|
|
@@ -339,7 +348,7 @@ export class Engine {
|
|
|
339
348
|
// session or is inside the one that bar was already in. Read from the bars
|
|
340
349
|
// themselves rather than carried, so a re-executed bar compares against the
|
|
341
350
|
// same neighbour it compared against the first time.
|
|
342
|
-
const previous = this.known
|
|
351
|
+
const previous = this.known.at(index - 1)?.time ?? null;
|
|
343
352
|
this.facts = factsFor(
|
|
344
353
|
index,
|
|
345
354
|
this.supplied,
|
|
@@ -418,15 +427,6 @@ export class Engine {
|
|
|
418
427
|
};
|
|
419
428
|
}
|
|
420
429
|
|
|
421
|
-
/**
|
|
422
|
-
* A bar that failed.
|
|
423
|
-
*
|
|
424
|
-
* Steps 7 to 11 do not run, the bar's output columns keep whatever the
|
|
425
|
-
* previous execution published or stay absent, and the engine reports the
|
|
426
|
-
* error with its code and source position. It does not continue to the next
|
|
427
|
-
* bar with a half executed state, so the journal is rolled back and the
|
|
428
|
-
* script is marked stopped.
|
|
429
|
-
*/
|
|
430
430
|
/**
|
|
431
431
|
* A hand-over the engine refuses, before any of it has been executed.
|
|
432
432
|
*
|
|
@@ -449,6 +449,7 @@ export class Engine {
|
|
|
449
449
|
};
|
|
450
450
|
}
|
|
451
451
|
|
|
452
|
+
/** A bar that failed: steps 7 to 11 do not run, the journal rolls back, the script stops. */
|
|
452
453
|
private stopped(thrown: unknown): BarResult {
|
|
453
454
|
const diagnostic =
|
|
454
455
|
thrown instanceof ScriptError ? thrown.diagnostic : unexpected('the bar', thrown);
|
package/src/core/engine/guard.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* catalogue has: an array past its element ceiling is OS5002, a string past its
|
|
11
11
|
* character ceiling is OS5008, one more drawing object than the host will hold
|
|
12
12
|
* is OS5010, an argument outside its contract is OS4003, an index outside an
|
|
13
|
-
* array is OS4004, a change to an object a script already deleted is OS4005,
|
|
13
|
+
* array is OS4004, a cell outside a table's declared shape is OS4008, a change to an object a script already deleted is OS4005,
|
|
14
14
|
* and a timezone name the host's table does not hold is OS6005.
|
|
15
15
|
*/
|
|
16
16
|
import type { Span } from '../span/index.js';
|
|
@@ -52,6 +52,17 @@ export function guardFor(budget: Budget): Guard {
|
|
|
52
52
|
raise('OS4004', span, { index, name, size });
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* A cell outside the grid its table declared, OS4008.
|
|
57
|
+
*
|
|
58
|
+
* Not OS4004, which is about an array and would name an index and a
|
|
59
|
+
* flattened element count: a table's shape is two numbers the declaration
|
|
60
|
+
* fixed, and the fix is to declare the shape the script writes.
|
|
61
|
+
*/
|
|
62
|
+
badCell(span: Span, row: number, column: number, rows: number, columns: number): never {
|
|
63
|
+
raise('OS4008', span, { row, column, rows, columns });
|
|
64
|
+
},
|
|
65
|
+
|
|
55
66
|
deleted(span: Span, kind: string, bar: number): never {
|
|
56
67
|
raise('OS4005', span, { kind, bar });
|
|
57
68
|
},
|
package/src/core/engine/host.ts
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* stop rather than what a script computes.
|
|
26
26
|
*/
|
|
27
27
|
import type { HostBar } from './bars.js';
|
|
28
|
+
import type { BarColumns } from './bar-source.js';
|
|
28
29
|
import type { PendingEffect } from './channels.js';
|
|
29
30
|
import type { OrderIntent } from './ledger/index.js';
|
|
30
31
|
import type { HostFacts } from './library/index.js';
|
|
@@ -154,10 +155,11 @@ export interface RequestRefusal {
|
|
|
154
155
|
* answer between bars and then recalculates the study over its whole history,
|
|
155
156
|
* which is a fresh load rather than an answer spliced into a run already past
|
|
156
157
|
* the bars it would have changed. A host that wants the engine to fold the
|
|
157
|
-
* chart's own bars instead returns nothing at all.
|
|
158
|
+
* chart's own bars instead returns nothing at all. The bars may be records or
|
|
159
|
+
* columns, as a run's may (`bar-source.ts`).
|
|
158
160
|
*/
|
|
159
161
|
export type RequestAnswer =
|
|
160
|
-
| { readonly bars: readonly HostBar[] }
|
|
162
|
+
| { readonly bars: readonly HostBar[] | BarColumns }
|
|
161
163
|
| { readonly pending: true }
|
|
162
164
|
| { readonly refused: RequestRefusal };
|
|
163
165
|
|
package/src/core/engine/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ export type { AlertFiring } from './alerts.js';
|
|
|
32
32
|
export type { Grid } from './grids.js';
|
|
33
33
|
|
|
34
34
|
export type { BarFacts, BarState, HostBar } from './bars.js';
|
|
35
|
+
export type { BarColumn, BarColumns } from './bar-source.js';
|
|
35
36
|
export { BAR_FIELDS, barField, isBarField } from './bars.js';
|
|
36
37
|
|
|
37
38
|
export type { Clock, EngineLimits } from './budget.js';
|
|
@@ -160,6 +160,8 @@ export interface Guard {
|
|
|
160
160
|
badArgument(span: Span, name: string, argument: string, found: string): never;
|
|
161
161
|
/** Raise a run-time diagnostic against an index outside an array. */
|
|
162
162
|
badIndex(span: Span, name: string, index: string, size: number): never;
|
|
163
|
+
/** Raise a run-time diagnostic against a cell outside a table's declared shape. */
|
|
164
|
+
badCell(span: Span, row: number, column: number, rows: number, columns: number): never;
|
|
163
165
|
/** Raise a run-time diagnostic against an object a script already deleted. */
|
|
164
166
|
deleted(span: Span, kind: string, bar: number): never;
|
|
165
167
|
/** Raise a run-time diagnostic against a zone name the host does not know. */
|
|
@@ -74,6 +74,17 @@ for (const one of ENTRIES) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/** The entry for one name and argument count, or nothing when there is none. */
|
|
77
|
+
/**
|
|
78
|
+
* Every name and argument count this engine holds, as `name/arity`, sorted.
|
|
79
|
+
*
|
|
80
|
+
* `scripts/check-manifests.mjs` compares it with the second engine's, so a call
|
|
81
|
+
* one engine holds and the other does not is found by a build rather than by the
|
|
82
|
+
* first case that reaches it.
|
|
83
|
+
*/
|
|
84
|
+
export function manifestKeys(): readonly string[] {
|
|
85
|
+
return [...INDEX.keys()].sort();
|
|
86
|
+
}
|
|
87
|
+
|
|
77
88
|
export function manifestEntry(name: string, arity: number): ManifestEntry | undefined {
|
|
78
89
|
return INDEX.get(keyOf(name, arity));
|
|
79
90
|
}
|
|
@@ -234,12 +234,7 @@ export const OBJECT_ENTRIES: readonly ManifestEntry[] = [
|
|
|
234
234
|
const col = wholeAt(ctx, 'cell', 'col', args, 2);
|
|
235
235
|
if (row === null || col === null) return null;
|
|
236
236
|
if (row >= object.rows || col >= object.cols) {
|
|
237
|
-
ctx.guard.
|
|
238
|
-
ctx.span,
|
|
239
|
-
ctx.nameOf(valueAt(args, 0)),
|
|
240
|
-
`${row}, ${col}`,
|
|
241
|
-
object.rows * object.cols,
|
|
242
|
-
);
|
|
237
|
+
ctx.guard.badCell(ctx.span, row, col, object.rows, object.cols);
|
|
243
238
|
}
|
|
244
239
|
const written: GridCell = {
|
|
245
240
|
row,
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
import type { Span } from '../span/index.js';
|
|
29
29
|
import { barField, factsFor } from './bars.js';
|
|
30
30
|
import type { HostBar } from './bars.js';
|
|
31
|
+
import { recordSource } from './bar-source.js';
|
|
32
|
+
import type { BarSource } from './bar-source.js';
|
|
31
33
|
import { Budget, stepBound } from './budget.js';
|
|
32
34
|
import type { Clock, EngineLimits } from './budget.js';
|
|
33
35
|
import { Channels } from './channels.js';
|
|
@@ -59,12 +61,7 @@ export interface BodyInput {
|
|
|
59
61
|
*/
|
|
60
62
|
export interface NestedRequests {
|
|
61
63
|
readonly empty: boolean;
|
|
62
|
-
fill(
|
|
63
|
-
registers: Registers,
|
|
64
|
-
bars: readonly HostBar[],
|
|
65
|
-
index: number,
|
|
66
|
-
fresh: boolean,
|
|
67
|
-
): void;
|
|
64
|
+
fill(registers: Registers, bars: BarSource, index: number, fresh: boolean): void;
|
|
68
65
|
}
|
|
69
66
|
|
|
70
67
|
export interface BodyParts {
|
|
@@ -120,6 +117,7 @@ export class RequestBody {
|
|
|
120
117
|
private lastClose: number | null = null;
|
|
121
118
|
/** The requested bars themselves, kept only when a read inside folds them. */
|
|
122
119
|
private readonly history: HostBar[] = [];
|
|
120
|
+
private readonly historySource = recordSource(this.history);
|
|
123
121
|
/**
|
|
124
122
|
* The value the last closed requested bar handed back.
|
|
125
123
|
*
|
|
@@ -251,7 +249,7 @@ export class RequestBody {
|
|
|
251
249
|
const nested = this.parts.nested;
|
|
252
250
|
if (nested !== undefined && !nested.empty) {
|
|
253
251
|
this.history[index] = bar;
|
|
254
|
-
nested.fill(this.registers, this.
|
|
252
|
+
nested.fill(this.registers, this.historySource, index, this.touches === 0);
|
|
255
253
|
}
|
|
256
254
|
|
|
257
255
|
this.machine.run();
|
|
@@ -218,9 +218,9 @@ export function undatable(plan: RequestPlan): boolean {
|
|
|
218
218
|
*
|
|
219
219
|
* OS6012's own message, because the zone is an instrument fact the host did not
|
|
220
220
|
* supply and that is exactly what this read needs and cannot default. Nothing
|
|
221
|
-
* is raised: a fact the host did not state leaves the read absent,
|
|
222
|
-
*
|
|
223
|
-
*
|
|
221
|
+
* is raised: a fact the host did not state leaves the read absent, as
|
|
222
|
+
* `host-interface.md` 4.5 settles it, and this is the sentence that explains
|
|
223
|
+
* the absence rather than a second answer to it.
|
|
224
224
|
*/
|
|
225
225
|
export function undatableReason(query: RequestQuery): string {
|
|
226
226
|
return diagnosticFor('OS6012', NO_POSITION, { fact: 'a timezone', symbol: named(query) }).message;
|
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
*/
|
|
49
49
|
import type { Span } from '../span/index.js';
|
|
50
50
|
import type { HostBar } from './bars.js';
|
|
51
|
+
import { sourceOf } from './bar-source.js';
|
|
52
|
+
import type { BarSource } from './bar-source.js';
|
|
51
53
|
import type { Clock, EngineLimits } from './budget.js';
|
|
52
54
|
import type { EngineHost } from './host.js';
|
|
53
55
|
import type { ResolvedInput } from './inputs.js';
|
|
@@ -97,7 +99,7 @@ interface Read {
|
|
|
97
99
|
readonly register: number;
|
|
98
100
|
readonly body: RequestBody;
|
|
99
101
|
/** The host's bars for a `symbol` read, or nothing when the fold is the chart's. */
|
|
100
|
-
readonly source:
|
|
102
|
+
readonly source: BarSource | undefined;
|
|
101
103
|
readonly ready: boolean;
|
|
102
104
|
readonly reason: string;
|
|
103
105
|
/** How far into the source the fold has read. */
|
|
@@ -146,7 +148,7 @@ export class RequestSet {
|
|
|
146
148
|
* have been revised since the last execution, and the bucket it is inside has
|
|
147
149
|
* to be rebuilt from the revision rather than from the reading it replaced.
|
|
148
150
|
*/
|
|
149
|
-
fill(registers: Registers, bars:
|
|
151
|
+
fill(registers: Registers, bars: BarSource, index: number, fresh: boolean): void {
|
|
150
152
|
const heap = this.parts.heapOf();
|
|
151
153
|
for (const read of this.reads) {
|
|
152
154
|
if (fresh) {
|
|
@@ -227,7 +229,7 @@ function build(parts: RequestParts, request: Request, plan: RequestPlan): Read {
|
|
|
227
229
|
plan,
|
|
228
230
|
register: request.series,
|
|
229
231
|
body,
|
|
230
|
-
source: answer !== undefined && 'bars' in answer ? answer.bars : undefined,
|
|
232
|
+
source: answer !== undefined && 'bars' in answer ? sourceOf(answer.bars) : undefined,
|
|
231
233
|
// A fold of the chart's own bars needs nothing from the host, so it is
|
|
232
234
|
// answered the moment it is planned. A read the host is still fetching is
|
|
233
235
|
// not: the read is absent, `req.isReady` is false, and the study keeps
|
|
@@ -247,9 +249,9 @@ function build(parts: RequestParts, request: Request, plan: RequestPlan): Read {
|
|
|
247
249
|
}
|
|
248
250
|
|
|
249
251
|
/** The read's value for the chart bar at `index`, and the fold that gets there. */
|
|
250
|
-
function valueOf(read: Read, bars:
|
|
252
|
+
function valueOf(read: Read, bars: BarSource, index: number): Value {
|
|
251
253
|
if (!read.ready) return ABSENT;
|
|
252
|
-
const bar = bars
|
|
254
|
+
const bar = bars.at(index);
|
|
253
255
|
const at = bar?.time ?? null;
|
|
254
256
|
if (at === null) return ABSENT;
|
|
255
257
|
const key = keyOf(read, at);
|
|
@@ -258,7 +260,7 @@ function valueOf(read: Read, bars: readonly HostBar[], index: number): Value {
|
|
|
258
260
|
const source = read.source ?? bars;
|
|
259
261
|
const lookahead = read.plan.request.mode === 'lookahead';
|
|
260
262
|
for (;;) {
|
|
261
|
-
const next = source
|
|
263
|
+
const next = source.at(read.cursor);
|
|
262
264
|
if (next === undefined) break;
|
|
263
265
|
const found = next.time === null ? undefined : keyOf(read, next.time);
|
|
264
266
|
if (found === undefined) {
|
|
@@ -310,7 +312,7 @@ function feed(read: Read, bar: HostBar, key: number): void {
|
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
/** A re-executed bar: the fold as it stood when the bar began. */
|
|
313
|
-
function restore(read: Read, bars:
|
|
315
|
+
function restore(read: Read, bars: BarSource): void {
|
|
314
316
|
read.cursor = read.mark.cursor;
|
|
315
317
|
read.openKey = read.mark.openKey;
|
|
316
318
|
read.openFrom = read.mark.openFrom;
|
|
@@ -318,7 +320,7 @@ function restore(read: Read, bars: readonly HostBar[]): void {
|
|
|
318
320
|
if (read.openKey === undefined) return;
|
|
319
321
|
const source = read.source ?? bars;
|
|
320
322
|
for (let at = read.openFrom; at < read.cursor; at += 1) {
|
|
321
|
-
const bar = source
|
|
323
|
+
const bar = source.at(at);
|
|
322
324
|
if (bar === undefined || bar.time === null) continue;
|
|
323
325
|
if (keyOf(read, bar.time) !== read.openKey) continue;
|
|
324
326
|
read.open = read.open === undefined ? start(bar) : extend(read.open, bar);
|
|
@@ -380,3 +382,4 @@ function lower(a: number | null, b: number | null | undefined): number | null {
|
|
|
380
382
|
function both(a: number | null, b: number | null): number | null {
|
|
381
383
|
return a === null || b === null ? null : a + b;
|
|
382
384
|
}
|
|
385
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The three things the engine checks about the bars it is handed,
|
|
3
3
|
* `host-interface.md` 3.5 and conformance item 1.
|
|
4
4
|
*
|
|
5
5
|
* Everything else about a series the engine takes exactly as stated: it does
|
|
@@ -55,6 +55,23 @@ export function noBars(instrument: Instrument | undefined): Diagnostic {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* A bar handed over with no time, OS6025.
|
|
60
|
+
*
|
|
61
|
+
* `host-interface.md` 3.1 states `time` for every bar with no absent case, and
|
|
62
|
+
* the order rule is built on it. Reading a missing one as the absent value, as
|
|
63
|
+
* `barField` would, steps the bar over every calendar fold and makes every
|
|
64
|
+
* session fact absent on a bar that is on the chart: a study draws a gap where
|
|
65
|
+
* the host has data, and nothing says why. It is a bar of the wrong shape, not
|
|
66
|
+
* one out of order, so it has a code and a fix of its own. A time that is not a
|
|
67
|
+
* finite number is no time either.
|
|
68
|
+
*/
|
|
69
|
+
export function undated(bar: HostBar, index: number): Diagnostic | undefined {
|
|
70
|
+
const time: unknown = bar.time;
|
|
71
|
+
if (typeof time === 'number' && Number.isFinite(time)) return undefined;
|
|
72
|
+
return failure('OS6025', NO_POSITION, { index });
|
|
73
|
+
}
|
|
74
|
+
|
|
58
75
|
/**
|
|
59
76
|
* A bar whose time does not follow the one before it, OS6011.
|
|
60
77
|
*
|
|
@@ -63,11 +80,9 @@ export function noBars(instrument: Instrument | undefined): Diagnostic {
|
|
|
63
80
|
* only one whose position tells the host where its own ordering went wrong.
|
|
64
81
|
*
|
|
65
82
|
* `previous` is the bar already handed over, or nothing for the first bar of a
|
|
66
|
-
* run, which follows nothing and is therefore always in order. A
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* so inventing this one for it would be a refusal the specification does not
|
|
70
|
-
* describe.
|
|
83
|
+
* run, which follows nothing and is therefore always in order. A bar with no
|
|
84
|
+
* time never reaches this comparison: `undated` refuses it first, because a
|
|
85
|
+
* bar dated nothing is not two instants in the wrong order.
|
|
71
86
|
*/
|
|
72
87
|
export function outOfOrder(
|
|
73
88
|
bar: HostBar,
|
|
@@ -80,3 +95,12 @@ export function outOfOrder(
|
|
|
80
95
|
if (time > before) return undefined;
|
|
81
96
|
return failure('OS6011', NO_POSITION, { index, time, previous: index - 1 });
|
|
82
97
|
}
|
|
98
|
+
|
|
99
|
+
/** Both checks of a bar handed over, in the order they are made: its shape, then its order. */
|
|
100
|
+
export function handOver(
|
|
101
|
+
bar: HostBar,
|
|
102
|
+
previous: HostBar | undefined,
|
|
103
|
+
index: number,
|
|
104
|
+
): Diagnostic | undefined {
|
|
105
|
+
return undated(bar, index) ?? outOfOrder(bar, previous, index);
|
|
106
|
+
}
|
|
@@ -106,10 +106,10 @@ function hoursOf(stated: SessionHours | undefined): Hours | null {
|
|
|
106
106
|
*
|
|
107
107
|
* Each of the three is reported at load rather than answered with absence,
|
|
108
108
|
* because absence there is indistinguishable from the honest case and the honest
|
|
109
|
-
* case is the one a reader will assume.
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
109
|
+
* case is the one a reader will assume. A bare read of an instrument fact the
|
|
110
|
+
* host did not state is a different question with the opposite answer: it is
|
|
111
|
+
* absent and never refused (`host-interface.md` 4.5, decision 66), because a
|
|
112
|
+
* record the host contradicts itself in is not a fact it left out.
|
|
113
113
|
*/
|
|
114
114
|
export function recordProblem(
|
|
115
115
|
stated: SessionHours | undefined,
|