@mark1russell7/coeval 0.0.0-bootstrap.0 → 0.1.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.
@@ -0,0 +1,553 @@
1
+ import { type Envelope, type Json, fromJson, typed, typeName } from "./doc.ts";
2
+ import { splitParts } from "./parts.ts";
3
+ import { ask, kindOf, type Answer } from "./ladder.ts";
4
+ import type { Side } from "./world.ts";
5
+ import {
6
+ type Context,
7
+ type Navigator,
8
+ type Resolution,
9
+ type Thing,
10
+ context as makeRootContext,
11
+ isHostThing,
12
+ resolve,
13
+ worldThing,
14
+ } from "./deref.ts";
15
+
16
+ export type { Context } from "./deref.ts";
17
+
18
+ /** The code of an error value. */
19
+ export type ErrorCode =
20
+ | "#KIND?"
21
+ | "#NOEVAL"
22
+ | "#PART?"
23
+ | "#NAME?"
24
+ | "#REF!"
25
+ | "#CYCLE!"
26
+ | "#STEP?"
27
+ | "#VALUE!"
28
+ | "#ARGS"
29
+ | "#CAP!"
30
+ | "#CALC!"
31
+ | "#DEPTH!";
32
+
33
+ /** An error value: a code and a reason. An evaluation gives an error value, and it does not throw. */
34
+ export interface EvalError {
35
+ readonly code: ErrorCode;
36
+ readonly reason: string;
37
+ }
38
+
39
+ /** The result of an evaluation: a value, or an error value. */
40
+ export type Result = { readonly ok: true; readonly value: Json } | { readonly ok: false; readonly error: EvalError };
41
+
42
+ /**
43
+ * This function makes a result with a value.
44
+ *
45
+ * @param value - The value.
46
+ * @returns The result.
47
+ */
48
+ export function ok(value: Json): Result {
49
+ return { ok: true, value };
50
+ }
51
+
52
+ /**
53
+ * This function makes a result with an error value.
54
+ *
55
+ * @param code - The code of the error.
56
+ * @param reason - One sentence that tells the cause.
57
+ * @returns The result.
58
+ */
59
+ export function fail(code: ErrorCode, reason: string): Result {
60
+ return { ok: false, error: { code, reason } };
61
+ }
62
+
63
+ /**
64
+ * This function makes a context with names and capabilities. The other roots are empty, and an evaluation sets
65
+ * the world.
66
+ *
67
+ * @param names - The names and their values.
68
+ * @param caps - The effects that the term can cause.
69
+ * @param self - The node of the term, if it has one.
70
+ * @returns The context.
71
+ */
72
+ export function makeContext(names: Readonly<Record<string, Json>> = {}, caps: readonly string[] = [], self: Thing = null): Context {
73
+ return makeRootContext({ names, caps, self });
74
+ }
75
+
76
+ /**
77
+ * A sealed part. An evaluator can read the binding name of a part and evaluate it. It cannot read the value of the
78
+ * part, thus two parts that give the same results can replace each other.
79
+ */
80
+ export interface Part {
81
+ /** The position of the part in its parent: an index of a list, or a field of a record. */
82
+ readonly key: string;
83
+ /** The binding name from the header of the part. */
84
+ readonly name?: string;
85
+ /**
86
+ * This function evaluates the part. Each call is a new evaluation.
87
+ *
88
+ * @param context - The context for the part. The default is the context of the parent.
89
+ * @returns The result of the part.
90
+ */
91
+ evaluate(context?: Context): Result;
92
+ }
93
+
94
+ /** The input of an evaluator. */
95
+ export interface EvalInput {
96
+ /** The text of the type of the document, for example `add` or `math.sum` after its alias. */
97
+ readonly kind: string;
98
+ /** The value of the document without its parts. */
99
+ readonly data: Json;
100
+ /** The parts, in the order of the value. */
101
+ readonly parts: readonly Part[];
102
+ /** The context of the document. */
103
+ readonly context: Context;
104
+ /**
105
+ * This function resolves a path from the context of the document.
106
+ *
107
+ * @param path - The steps. The first step is a root.
108
+ * @returns What the path reached, with each hop.
109
+ */
110
+ resolve(path: readonly Json[]): Resolution;
111
+ /**
112
+ * This function causes an effect. The context must have the capability for the kind of the effect. In a run, an
113
+ * evaluator cannot cause an effect: the host does each effect, thus only a runner can wait for it.
114
+ *
115
+ * @param kind - The kind of the effect, for example `log`.
116
+ * @param payload - The data of the effect.
117
+ * @returns The payload, or the error `#CAP!`.
118
+ */
119
+ effect(kind: string, payload: Json): Result;
120
+ }
121
+
122
+ /** An evaluator: a function from the input of a document to a result. */
123
+ export type Evaluator = (input: EvalInput) => Result;
124
+
125
+ /**
126
+ * The steps of an evaluation that can wait. It yields a promise only when the host makes it wait. A runner takes the
127
+ * result of a part with `yield*`, thus a run goes on at once until an effect waits.
128
+ */
129
+ export type Steps = Generator<Promise<Result>, Result, Result>;
130
+
131
+ /** A part for a runner. Its evaluation can wait for the effects in it. */
132
+ export interface RunPart {
133
+ /** The position of the part in its parent: an index of a list, or a field of a record. */
134
+ readonly key: string;
135
+ /** The binding name from the header of the part. */
136
+ readonly name?: string;
137
+ /**
138
+ * This function evaluates the part. Each call is a new evaluation. Take its result with `yield*`.
139
+ *
140
+ * @param context - The context for the part. The default is the context of the parent.
141
+ * @returns The steps of the evaluation of the part.
142
+ */
143
+ evaluate(context?: Context): Steps;
144
+ }
145
+
146
+ /** The input of a runner: the input of an evaluator, with parts and effects that can wait. */
147
+ export interface RunInput {
148
+ /** The text of the type of the document. */
149
+ readonly kind: string;
150
+ /** The value of the document without its parts. */
151
+ readonly data: Json;
152
+ /** The parts, in the order of the value. */
153
+ readonly parts: readonly RunPart[];
154
+ /** The context of the document. */
155
+ readonly context: Context;
156
+ /**
157
+ * This function resolves a path from the context of the document.
158
+ *
159
+ * @param path - The steps. The first step is a root.
160
+ * @returns What the path reached, with each hop.
161
+ */
162
+ resolve(path: readonly Json[]): Resolution;
163
+ /**
164
+ * This function causes an effect. The context must have the capability. In a run, the host does the effect,
165
+ * and the steps wait when the host waits. In an evaluation, the effect gives its payload. Take its result with
166
+ * `yield*`.
167
+ *
168
+ * @param kind - The kind of the effect, for example `log`.
169
+ * @param payload - The data of the effect.
170
+ * @returns The steps that give the result of the host, or an error value.
171
+ */
172
+ effect(kind: string, payload: Json): Steps;
173
+ }
174
+
175
+ /**
176
+ * A runner: the code of a kind whose parts or effects can wait, as a generator function. The same runner serves an
177
+ * evaluation, which does not wait at any time, and a run, in which the host does each effect.
178
+ */
179
+ export type Runner = (input: RunInput) => Steps;
180
+
181
+ /** A machine: a world of kinds, and the code of each evaluator name, of each `deref` and of each walker. */
182
+ export interface Machine extends Navigator {
183
+ readonly evaluators: Readonly<Record<string, Evaluator>>;
184
+ /** The runners, by evaluator name. A runner wins over an evaluator of the same name. */
185
+ readonly runners?: Readonly<Record<string, Runner>>;
186
+ /** The deepest nesting of evaluations. The default is 200. */
187
+ readonly maxDepth?: number;
188
+ }
189
+
190
+ /** An effect that an evaluation caused, in the order of the effects. */
191
+ export interface Effect {
192
+ readonly index: number;
193
+ readonly kind: string;
194
+ readonly payload: Json;
195
+ /** The ID of the trace node that caused the effect. */
196
+ readonly node: number;
197
+ /** The number of events before the effect. The effect comes before the end of its node. */
198
+ readonly at: number;
199
+ }
200
+
201
+ /** The host side of a run: it does one effect, and gives its result. A throw or a rejection is an error value. */
202
+ export type Perform = (effect: Effect) => Json | Promise<Json>;
203
+
204
+ /** The options of a run. */
205
+ export interface RunOptions {
206
+ /** The host code that does each effect. Without it, an effect gives its payload, as in an evaluation. */
207
+ readonly perform?: Perform;
208
+ /** The type of a bare root value. */
209
+ readonly declaredType?: string;
210
+ }
211
+
212
+ /**
213
+ * This function tells if the capabilities permit an effect. A capability permits the kind of its name, and each kind
214
+ * in its namespace: `store` permits `store.update`.
215
+ *
216
+ * @param caps - The capabilities of the context.
217
+ * @param kind - The kind of the effect.
218
+ * @returns `true` when one capability permits it.
219
+ */
220
+ export function permits(caps: readonly string[], kind: string): boolean {
221
+ return caps.some((cap) => cap === kind || kind.startsWith(`${cap}.`));
222
+ }
223
+
224
+ /** One evaluation in a trace. The children are the evaluations of its parts, in the order that they started. */
225
+ export interface TraceNode {
226
+ readonly id: number;
227
+ /** The keys from the root document to this document. */
228
+ readonly path: readonly string[];
229
+ /** The document. A bare value has the type that its position declares. */
230
+ readonly doc: Envelope;
231
+ /** `true` when the type came from the container and not from an envelope. */
232
+ readonly declared: boolean;
233
+ /** The answer of the ladder to the verb `eval`. */
234
+ readonly answer: Answer;
235
+ readonly side: Side;
236
+ /** The names that the document could read when its evaluation started. */
237
+ readonly names: readonly string[];
238
+ /** The names and their values when the evaluation started. */
239
+ readonly scope: Readonly<Record<string, Json>>;
240
+ /** The capabilities that the document had when its evaluation started. */
241
+ readonly caps: readonly string[];
242
+ /** A short text for the root `self` when the evaluation started. */
243
+ readonly self: string;
244
+ /** The time of the start. Each start and each end takes one tick. */
245
+ readonly enter: number;
246
+ /** The time of the end. */
247
+ readonly exit: number;
248
+ readonly result: Result;
249
+ readonly children: readonly TraceNode[];
250
+ /** The indices of the effects that this document caused itself. */
251
+ readonly effects: readonly number[];
252
+ }
253
+
254
+ /** The record of one evaluation of a document. */
255
+ export interface Run {
256
+ readonly result: Result;
257
+ readonly trace: TraceNode;
258
+ readonly effects: readonly Effect[];
259
+ /** The number of ticks. */
260
+ readonly time: number;
261
+ }
262
+
263
+ interface Building {
264
+ id: number;
265
+ path: readonly string[];
266
+ doc: Envelope;
267
+ declared: boolean;
268
+ answer: Answer;
269
+ side: Side;
270
+ names: readonly string[];
271
+ scope: Readonly<Record<string, Json>>;
272
+ caps: readonly string[];
273
+ self: string;
274
+ enter: number;
275
+ exit: number;
276
+ result: Result;
277
+ children: Building[];
278
+ effects: number[];
279
+ }
280
+
281
+ function selfLabel(self: Thing): string {
282
+ if (isHostThing(self)) return self.label;
283
+ return self === null ? "none" : JSON.stringify(self).slice(0, 40);
284
+ }
285
+
286
+ const NO_ANSWER: Answer = { verb: "eval", error: "no-answer", steps: [] };
287
+
288
+ /** The state of one evaluation or run: the machine, the effects and the clock. */
289
+ interface Session {
290
+ readonly machine: Machine;
291
+ /** `true` in a run: the runners take part, and the host does each effect. */
292
+ readonly running: boolean;
293
+ readonly perform: Perform | undefined;
294
+ readonly effects: Effect[];
295
+ tick: number;
296
+ nextId: number;
297
+ }
298
+
299
+ /** This function drives steps that cannot wait. */
300
+ function drive(steps: Steps): Result {
301
+ const step = steps.next();
302
+ if (step.done === true) return step.value;
303
+ void step.value.catch(() => undefined);
304
+ return fail("#CALC!", "A part waited, and its parent cannot wait.");
305
+ }
306
+
307
+ /** This function drives steps that can wait. The steps before the first wait happen at once, in the call. */
308
+ async function driveWaiting(steps: Steps): Promise<Result> {
309
+ let step = steps.next();
310
+ while (step.done !== true) {
311
+ let value: Result;
312
+ try {
313
+ value = await step.value;
314
+ } catch (error) {
315
+ step = steps.throw(error);
316
+ continue;
317
+ }
318
+ step = steps.next(value);
319
+ }
320
+ return step.value;
321
+ }
322
+
323
+ function* visit(
324
+ s: Session,
325
+ value: Json,
326
+ path: readonly string[],
327
+ declared: string | undefined,
328
+ ctx: Context,
329
+ parent: Building,
330
+ canWait: boolean,
331
+ ): Steps {
332
+ const envelope = fromJson(value);
333
+ const doc: Envelope = envelope ?? typed(declared ?? "?", value);
334
+ const node: Building = {
335
+ id: s.nextId,
336
+ path,
337
+ doc,
338
+ declared: envelope === undefined,
339
+ answer: NO_ANSWER,
340
+ side: "derive",
341
+ names: Object.keys(ctx.names),
342
+ scope: ctx.names,
343
+ caps: ctx.caps,
344
+ self: selfLabel(ctx.self),
345
+ enter: s.tick,
346
+ exit: s.tick,
347
+ result: fail("#NOEVAL", "The evaluation did not end."),
348
+ children: [],
349
+ effects: [],
350
+ };
351
+ s.nextId += 1;
352
+ s.tick += 1;
353
+ parent.children.push(node);
354
+ const finish = (result: Result): Result => {
355
+ node.result = result;
356
+ node.exit = s.tick;
357
+ s.tick += 1;
358
+ return result;
359
+ };
360
+
361
+ if (envelope === undefined && declared === undefined) {
362
+ return finish(fail("#PART?", "The value has no envelope, and its position declares no type."));
363
+ }
364
+ const maxDepth = s.machine.maxDepth ?? 200;
365
+ if (path.length > maxDepth) return finish(fail("#DEPTH!", `The nesting is deeper than ${maxDepth} documents.`));
366
+
367
+ const answer = ask(s.machine.world, envelope ?? {}, "eval", declared === undefined ? {} : { declaredType: declared });
368
+ node.answer = answer;
369
+ const kind = kindOf(s.machine.world, doc.type);
370
+ node.side = kind?.side ?? "derive";
371
+ if (answer.error === "unknown-kind") return finish(fail("#KIND?", `The world has no kind ${typeName(doc.type)}.`));
372
+ const name = answer.evaluator;
373
+ const runners = s.machine.runners ?? {};
374
+ const hasRunner = name !== undefined && Object.hasOwn(runners, name);
375
+ const runner = hasRunner ? runners[name] : undefined;
376
+ const code = name !== undefined && Object.hasOwn(s.machine.evaluators, name) ? s.machine.evaluators[name] : undefined;
377
+ if (name === undefined || (runner === undefined && code === undefined)) {
378
+ return finish(fail("#NOEVAL", `No rung gives an evaluator for ${typeName(doc.type)}.`));
379
+ }
380
+ if (runner !== undefined && s.running && !canWait) {
381
+ return finish(fail("#CALC!", `${typeName(doc.type)} waits for effects, and its parent cannot wait. Give the parent a runner.`));
382
+ }
383
+
384
+ const split = splitParts(kind?.parts, doc.value);
385
+ if (!split.ok) return finish(fail("#VALUE!", `${split.reason} The kind is ${typeName(doc.type)}.`));
386
+ const slots = split.parts.map((slot) => ({ slot, header: fromJson(slot.item) }));
387
+ const record = (effectKind: string, payload: Json): Result | Effect => {
388
+ if (!permits(ctx.caps, effectKind)) return fail("#CAP!", `The context has no capability for the effect ${effectKind}.`);
389
+ const effect: Effect = { index: s.effects.length, kind: effectKind, payload, node: node.id, at: s.tick };
390
+ s.effects.push(effect);
391
+ node.effects.push(effect.index);
392
+ return effect;
393
+ };
394
+ const kindText = typeName(doc.type);
395
+ const resolveHere = (steps: readonly Json[]): Resolution => resolve(s.machine, ctx, steps);
396
+
397
+ if (runner !== undefined) {
398
+ const parts: RunPart[] = slots.map(({ slot, header }) => ({
399
+ key: slot.key,
400
+ ...(header?.name === undefined ? {} : { name: header.name }),
401
+ evaluate: (override?: Context) => visit(s, slot.item, [...path, slot.key], slot.of, override ?? ctx, node, true),
402
+ }));
403
+ const input: RunInput = {
404
+ kind: kindText,
405
+ data: split.data,
406
+ parts,
407
+ context: ctx,
408
+ resolve: resolveHere,
409
+ effect: function* (effectKind: string, payload: Json): Steps {
410
+ const made = record(effectKind, payload);
411
+ if ("ok" in made) return made;
412
+ if (!s.running || s.perform === undefined) return ok(payload);
413
+ const failed = (error: unknown): Result => fail("#CALC!", `The host failed the effect ${effectKind}: ${String(error)}`);
414
+ let done: Json | Promise<Json>;
415
+ try {
416
+ done = s.perform(made);
417
+ } catch (error) {
418
+ return failed(error);
419
+ }
420
+ if (!(done instanceof Promise)) return ok(done ?? null);
421
+ return yield done.then((result) => ok(result ?? null), failed);
422
+ },
423
+ };
424
+ try {
425
+ return finish(yield* runner(input));
426
+ } catch (error) {
427
+ return finish(fail("#CALC!", `The runner ${name} threw: ${String(error)}`));
428
+ }
429
+ }
430
+
431
+ const parts: Part[] = slots.map(({ slot, header }) => ({
432
+ key: slot.key,
433
+ ...(header?.name === undefined ? {} : { name: header.name }),
434
+ evaluate: (override?: Context) => drive(visit(s, slot.item, [...path, slot.key], slot.of, override ?? ctx, node, false)),
435
+ }));
436
+ const input: EvalInput = {
437
+ kind: kindText,
438
+ data: split.data,
439
+ parts,
440
+ context: ctx,
441
+ resolve: resolveHere,
442
+ effect: (effectKind: string, payload: Json) => {
443
+ if (s.running) return fail("#CALC!", `The effect ${effectKind} needs a runner: in a run, the host does each effect.`);
444
+ const made = record(effectKind, payload);
445
+ return "ok" in made ? made : ok(payload);
446
+ },
447
+ };
448
+ try {
449
+ return finish((code as Evaluator)(input));
450
+ } catch (error) {
451
+ return finish(fail("#CALC!", `The evaluator ${name} threw: ${String(error)}`));
452
+ }
453
+ }
454
+
455
+ function holderNode(): Building {
456
+ return {
457
+ id: -1,
458
+ path: [],
459
+ doc: typed("?", null),
460
+ declared: false,
461
+ answer: NO_ANSWER,
462
+ side: "derive",
463
+ names: [],
464
+ scope: {},
465
+ caps: [],
466
+ self: "none",
467
+ enter: 0,
468
+ exit: 0,
469
+ result: ok(null),
470
+ children: [],
471
+ effects: [],
472
+ };
473
+ }
474
+
475
+ function rootContext(machine: Machine, context: Context): Context {
476
+ return context.world === null ? { ...context, world: worldThing(machine.world) } : context;
477
+ }
478
+
479
+ function record(s: Session, holder: Building, result: Result): Run {
480
+ const root = holder.children[0];
481
+ if (root === undefined) throw new Error("The evaluation made no trace.");
482
+ return { result, trace: root, effects: s.effects, time: s.tick };
483
+ }
484
+
485
+ /**
486
+ * This function evaluates a document, and records each evaluation in a trace.
487
+ *
488
+ * The verb `eval` goes up the ladder for each document. The kind of the document tells where its parts are. The
489
+ * evaluator gets each part sealed: it can evaluate the part, and it cannot read its value. A failure gives an error
490
+ * value, and the function does not throw. An effect is recorded in its order, and nothing does it.
491
+ *
492
+ * @param machine - The world and the code of the evaluators.
493
+ * @param doc - The document, as JSON.
494
+ * @param context - The names and the capabilities at the root.
495
+ * @param declaredType - The type of a bare root value.
496
+ * @returns The result, the trace and the effects in their order.
497
+ */
498
+ export function evaluate(machine: Machine, doc: Json, context: Context = makeContext(), declaredType?: string): Run {
499
+ const s: Session = { machine, running: false, perform: undefined, effects: [], tick: 0, nextId: 0 };
500
+ const holder = holderNode();
501
+ const result = drive(visit(s, doc, [], declaredType, rootContext(machine, context), holder, false));
502
+ return record(s, holder, result);
503
+ }
504
+
505
+ /**
506
+ * This function runs a document: an evaluation in which the host does each effect. A runner waits for its
507
+ * parts and for its effects, thus a step can read the result of the step before. The part of the run before the
508
+ * first wait happens at once, in the call.
509
+ *
510
+ * @param machine - The world, the evaluators and the runners.
511
+ * @param doc - The document, as JSON.
512
+ * @param context - The names and the capabilities at the root.
513
+ * @param options - The host code that does the effects, and the type of a bare root value.
514
+ * @returns The result, the trace and the effects in their order, when the run ends.
515
+ */
516
+ export async function run(machine: Machine, doc: Json, context: Context = makeContext(), options: RunOptions = {}): Promise<Run> {
517
+ const s: Session = { machine, running: true, perform: options.perform, effects: [], tick: 0, nextId: 0 };
518
+ const holder = holderNode();
519
+ const result = await driveWaiting(visit(s, doc, [], options.declaredType, rootContext(machine, context), holder, true));
520
+ return record(s, holder, result);
521
+ }
522
+
523
+ /**
524
+ * This function finds a node of a trace by its path.
525
+ *
526
+ * @param trace - The root of the trace.
527
+ * @param path - The keys from the root.
528
+ * @returns The first evaluation at that path, or `undefined` when the document did not evaluate.
529
+ */
530
+ export function nodeAt(trace: TraceNode, path: readonly string[]): TraceNode | undefined {
531
+ let node: TraceNode | undefined = trace;
532
+ for (const key of path) {
533
+ node = node?.children.find((child) => child.path[child.path.length - 1] === key);
534
+ if (node === undefined) return undefined;
535
+ }
536
+ return node;
537
+ }
538
+
539
+ /**
540
+ * This function lists the nodes of a trace in the order of their start.
541
+ *
542
+ * @param trace - The root of the trace.
543
+ * @returns Each node, the root first.
544
+ */
545
+ export function flatten(trace: TraceNode): readonly TraceNode[] {
546
+ const out: TraceNode[] = [];
547
+ const walk = (node: TraceNode): void => {
548
+ out.push(node);
549
+ node.children.forEach(walk);
550
+ };
551
+ walk(trace);
552
+ return out.sort((a, b) => a.enter - b.enter);
553
+ }
package/src/index.ts ADDED
@@ -0,0 +1,118 @@
1
+ export {
2
+ type Envelope,
3
+ type Json,
4
+ type JsonRecord,
5
+ type Key,
6
+ type TypeRef,
7
+ ENVELOPE_KEYS,
8
+ field,
9
+ fromJson,
10
+ isEnvelope,
11
+ isKey,
12
+ isRecord,
13
+ isTypeRef,
14
+ ref,
15
+ toJson,
16
+ typeName,
17
+ typePath,
18
+ typed,
19
+ } from "./doc.ts";
20
+ export {
21
+ type Alias,
22
+ type Kind,
23
+ type Lookup,
24
+ type Namespace,
25
+ type PartsSpec,
26
+ type Side,
27
+ type World,
28
+ type WorldEntry,
29
+ entriesAsJson,
30
+ isAlias,
31
+ isKind,
32
+ kindDocument,
33
+ lookupKind,
34
+ } from "./world.ts";
35
+ export {
36
+ type Answer,
37
+ type AskOptions,
38
+ type Header,
39
+ type KindSource,
40
+ type Outcome,
41
+ type Rung,
42
+ type Step,
43
+ RUNGS,
44
+ ask,
45
+ kindNamed,
46
+ kindOf,
47
+ } from "./ladder.ts";
48
+ export {
49
+ type Context,
50
+ type DerefCode,
51
+ type Hop,
52
+ type HopBy,
53
+ type HostThing,
54
+ type Navigator,
55
+ type Resolution,
56
+ type Root,
57
+ type Thing,
58
+ type WalkInput,
59
+ type WalkResult,
60
+ type Walker,
61
+ ROOTS,
62
+ THING,
63
+ context,
64
+ derefStep,
65
+ isHostThing,
66
+ isRef,
67
+ resolve,
68
+ valueOfThing,
69
+ worldThing,
70
+ } from "./deref.ts";
71
+ export { type Classification, type Shape, classify, tag } from "./classify.ts";
72
+ export { type PartSlot, type Split, splitParts } from "./parts.ts";
73
+ export {
74
+ type Effect,
75
+ type ErrorCode,
76
+ type EvalError,
77
+ type EvalInput,
78
+ type Evaluator,
79
+ type Machine,
80
+ type Part,
81
+ type Perform,
82
+ type Result,
83
+ type Run,
84
+ type RunInput,
85
+ type RunOptions,
86
+ type RunPart,
87
+ type Runner,
88
+ type TraceNode,
89
+ evaluate,
90
+ fail,
91
+ flatten,
92
+ makeContext,
93
+ nodeAt,
94
+ ok,
95
+ permits,
96
+ run,
97
+ } from "./evaluate.ts";
98
+ export { STD_CAPS, STD_EVALUATORS, STD_MACHINE, STD_RUNNERS, STD_WALKERS, STD_WORLD } from "./stdlib.ts";
99
+ export {
100
+ type Edge,
101
+ type OrderProblem,
102
+ type StepSpec,
103
+ checkSteps,
104
+ dataEdges,
105
+ effectEdges,
106
+ isAllowedOrder,
107
+ layers,
108
+ } from "./order.ts";
109
+ export {
110
+ type Construct,
111
+ type Give,
112
+ type Part as ContextPart,
113
+ type PartInfo,
114
+ type Use,
115
+ CONSTRUCTS,
116
+ PARTS,
117
+ PART_INFO,
118
+ } from "./context.ts";