@cotal-ai/lang 0.0.0 → 0.18.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/LICENSE +202 -0
- package/dist/dryrun.d.ts +106 -0
- package/dist/dryrun.d.ts.map +1 -0
- package/dist/dryrun.js +172 -0
- package/dist/dryrun.js.map +1 -0
- package/dist/duration.d.ts +12 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +34 -0
- package/dist/duration.js.map +1 -0
- package/dist/effects.d.ts +231 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +64 -0
- package/dist/effects.js.map +1 -0
- package/dist/errors.d.ts +141 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +163 -0
- package/dist/errors.js.map +1 -0
- package/dist/grammar.d.ts +28 -0
- package/dist/grammar.d.ts.map +1 -0
- package/dist/grammar.js +793 -0
- package/dist/grammar.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/interpret.d.ts +89 -0
- package/dist/interpret.d.ts.map +1 -0
- package/dist/interpret.js +1117 -0
- package/dist/interpret.js.map +1 -0
- package/dist/journal.d.ts +177 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +198 -0
- package/dist/journal.js.map +1 -0
- package/dist/keys.d.ts +87 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +105 -0
- package/dist/keys.js.map +1 -0
- package/dist/primitives.d.ts +84 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +265 -0
- package/dist/primitives.js.map +1 -0
- package/dist/sim.d.ts +101 -0
- package/dist/sim.d.ts.map +1 -0
- package/dist/sim.js +192 -0
- package/dist/sim.js.map +1 -0
- package/dist/values.d.ts +35 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +0 -0
- package/dist/values.js.map +1 -0
- package/package.json +27 -7
- package/README.md +0 -10
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The effect interface: one seam, two implementations.
|
|
3
|
+
*
|
|
4
|
+
* A handler is told to do a thing and reports what happened. It never touches the journal. That
|
|
5
|
+
* split is what makes the simulator a real test harness rather than a second implementation to
|
|
6
|
+
* keep in sync: every durability rule holds identically under simulation and production, because
|
|
7
|
+
* the interpreter, not the handler, is what enforces them.
|
|
8
|
+
*
|
|
9
|
+
* The simulation handler lives in this package. The production handler binds these calls onto the
|
|
10
|
+
* mesh (goals, checkpoints, work leases) and lives outside it, so this package stays pure.
|
|
11
|
+
*/
|
|
12
|
+
import type { StepKey } from "./keys.js";
|
|
13
|
+
/**
|
|
14
|
+
* A handle's journalled form is a stable, site-independent reference: an agent's persistent
|
|
15
|
+
* identity, a channel's name, a run id. Never a session id, a file descriptor, or a host path.
|
|
16
|
+
* A run that resumes on another machine has to mean the same thing by every binding it holds,
|
|
17
|
+
* and a host-local pointer in journalled state is exactly how that stops being true.
|
|
18
|
+
*/
|
|
19
|
+
export interface AgentHandleValue {
|
|
20
|
+
readonly agent: string;
|
|
21
|
+
readonly persona: string;
|
|
22
|
+
readonly worktree?: string;
|
|
23
|
+
readonly role?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ChannelHandleValue {
|
|
26
|
+
readonly channel: string;
|
|
27
|
+
}
|
|
28
|
+
export type TurnStatus = "done" | "blocked" | "handoff";
|
|
29
|
+
export interface TurnResultValue {
|
|
30
|
+
readonly status: TurnStatus;
|
|
31
|
+
readonly to?: AgentHandleValue;
|
|
32
|
+
readonly note?: string;
|
|
33
|
+
readonly at: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* WHAT HAPPENED, which is all a handler is allowed to decide.
|
|
37
|
+
*
|
|
38
|
+
* A handler never chooses whether an expiry is returned or thrown. It reports the raw outcome, the
|
|
39
|
+
* interpreter journals THAT, and the disposition is computed from today's source afterwards, on
|
|
40
|
+
* the live path and the replay path alike (see applyCheckpointPolicy).
|
|
41
|
+
*
|
|
42
|
+
* Written the other way round the reapply rule cannot work at all, and this package shipped it
|
|
43
|
+
* that way for a day: a handler that throws L4007 makes the journal record `failed`, and a replay
|
|
44
|
+
* under an edited `proceed` then has nothing but an error to reinterpret. A policy applied before
|
|
45
|
+
* the journal is a policy baked into the record.
|
|
46
|
+
*/
|
|
47
|
+
export type CheckpointRaw = {
|
|
48
|
+
readonly outcome: "resolved";
|
|
49
|
+
readonly value?: unknown;
|
|
50
|
+
readonly artifact?: string;
|
|
51
|
+
readonly by?: string;
|
|
52
|
+
readonly at: number;
|
|
53
|
+
/**
|
|
54
|
+
* Which answer the settle accepted. Every resolver presents as the run driver, so the
|
|
55
|
+
* arbiter has to NAME its choice: a principal cannot discriminate between two answers.
|
|
56
|
+
*
|
|
57
|
+
* NOTHING IN THIS PACKAGE SETS IT. The binding between an answer id and a settle fact lives
|
|
58
|
+
* in the substrate the mesh handler talks to, which is a v0.4 delta this package does not
|
|
59
|
+
* carry; the field is here so the journal preserves what a production handler reports rather
|
|
60
|
+
* than dropping it, and the simulator deliberately never invents one. Read an absent
|
|
61
|
+
* `answerId` as "this handler does not name its answers", never as "the answer was anonymous".
|
|
62
|
+
*/
|
|
63
|
+
readonly answerId?: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly outcome: "expired";
|
|
66
|
+
readonly at: number;
|
|
67
|
+
};
|
|
68
|
+
export interface CheckpointResultValue {
|
|
69
|
+
readonly status: "resolved" | "expired";
|
|
70
|
+
readonly value?: unknown;
|
|
71
|
+
readonly by?: string;
|
|
72
|
+
readonly at: number;
|
|
73
|
+
readonly artifact?: string;
|
|
74
|
+
}
|
|
75
|
+
/** An event descriptor. Pure: building one performs no effect. */
|
|
76
|
+
export type EventDescriptor = {
|
|
77
|
+
readonly event: "replied";
|
|
78
|
+
readonly agent: string;
|
|
79
|
+
} | {
|
|
80
|
+
readonly event: "message";
|
|
81
|
+
readonly channel: string;
|
|
82
|
+
readonly from?: string;
|
|
83
|
+
readonly matches?: string;
|
|
84
|
+
} | {
|
|
85
|
+
readonly event: "idle";
|
|
86
|
+
readonly channel: string;
|
|
87
|
+
readonly duration: string;
|
|
88
|
+
} | {
|
|
89
|
+
readonly event: "down";
|
|
90
|
+
readonly agent: string;
|
|
91
|
+
};
|
|
92
|
+
/** A notify fact: a bounded decision record, never a message. See NOTIFY_BOUND. */
|
|
93
|
+
export interface NotifyFact {
|
|
94
|
+
readonly decision: string;
|
|
95
|
+
readonly outcome: string;
|
|
96
|
+
readonly detail?: Readonly<Record<string, string | number | boolean>>;
|
|
97
|
+
}
|
|
98
|
+
export interface SpawnRequest {
|
|
99
|
+
readonly persona: string;
|
|
100
|
+
readonly model?: string;
|
|
101
|
+
readonly variant?: string;
|
|
102
|
+
readonly worktree?: string;
|
|
103
|
+
readonly join?: readonly ChannelHandleValue[];
|
|
104
|
+
readonly role?: string;
|
|
105
|
+
readonly permits?: Readonly<Record<string, unknown>>;
|
|
106
|
+
readonly supervise?: Readonly<Record<string, unknown>>;
|
|
107
|
+
/** What a fork does with this agent: spawn a fresh one, or reuse the original. Default respawn. */
|
|
108
|
+
readonly onFork?: "respawn" | "adopt";
|
|
109
|
+
}
|
|
110
|
+
export interface TurnRequest {
|
|
111
|
+
readonly agent: AgentHandleValue;
|
|
112
|
+
readonly deadline?: string;
|
|
113
|
+
}
|
|
114
|
+
export interface AskRequest {
|
|
115
|
+
readonly agent: AgentHandleValue;
|
|
116
|
+
readonly schema: unknown;
|
|
117
|
+
readonly deadline?: string;
|
|
118
|
+
readonly attempts?: number;
|
|
119
|
+
}
|
|
120
|
+
export interface CheckpointRequest {
|
|
121
|
+
readonly prompt: string;
|
|
122
|
+
readonly schema?: unknown;
|
|
123
|
+
readonly timeout?: string;
|
|
124
|
+
readonly onExpiry?: "fail" | "proceed" | "escalate";
|
|
125
|
+
readonly to?: string;
|
|
126
|
+
}
|
|
127
|
+
export interface SleepRequest {
|
|
128
|
+
readonly duration: string;
|
|
129
|
+
}
|
|
130
|
+
export interface WaitRequest {
|
|
131
|
+
readonly event: EventDescriptor;
|
|
132
|
+
readonly timeout?: string;
|
|
133
|
+
}
|
|
134
|
+
export interface NotifyRequest {
|
|
135
|
+
readonly agents: readonly AgentHandleValue[];
|
|
136
|
+
readonly fact: NotifyFact;
|
|
137
|
+
}
|
|
138
|
+
export interface MonitorRequest {
|
|
139
|
+
readonly agent: AgentHandleValue;
|
|
140
|
+
}
|
|
141
|
+
export interface ConclaveRequest {
|
|
142
|
+
readonly members: readonly AgentHandleValue[];
|
|
143
|
+
readonly channel?: string;
|
|
144
|
+
}
|
|
145
|
+
/** Raised by a handler when an effect fails in a way the program can catch. */
|
|
146
|
+
export declare class EffectError extends Error {
|
|
147
|
+
readonly code: string;
|
|
148
|
+
readonly kind: string;
|
|
149
|
+
readonly detail?: Readonly<Record<string, unknown>> | undefined;
|
|
150
|
+
constructor(code: string, kind: string, message: string, detail?: Readonly<Record<string, unknown>> | undefined);
|
|
151
|
+
}
|
|
152
|
+
/** Raised into a branch that a `race` loser or a run cancellation has cut short. */
|
|
153
|
+
export declare class Cancelled extends Error {
|
|
154
|
+
readonly reason: string;
|
|
155
|
+
constructor(reason: string);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Raw outcome to what the program sees, computed from TODAY's source.
|
|
159
|
+
*
|
|
160
|
+
* The same call runs on the live path and after a journal hit, which is the whole point: a resumed
|
|
161
|
+
* run must reach this with the recorded fact and the current `onExpiry`, so editing `proceed` to
|
|
162
|
+
* `fail` makes the resume throw even though nothing about the recorded expiry changed.
|
|
163
|
+
*
|
|
164
|
+
* `escalate` never arrives here. It mints an effect rather than choosing a disposition, so it is
|
|
165
|
+
* hashed (design 5.12) and an edit to it diverges before any of this runs.
|
|
166
|
+
*/
|
|
167
|
+
export declare function applyCheckpointPolicy(raw: CheckpointRaw, onExpiry: "fail" | "proceed" | "escalate" | undefined): CheckpointResultValue;
|
|
168
|
+
export interface CancelSignal {
|
|
169
|
+
readonly cancelled: boolean;
|
|
170
|
+
readonly reason?: string;
|
|
171
|
+
onCancel(fn: (reason: string) => void): void;
|
|
172
|
+
}
|
|
173
|
+
export interface EffectContext {
|
|
174
|
+
/** The key of the step being performed. Handlers use it for tracing, never for lookup. */
|
|
175
|
+
readonly key: StepKey;
|
|
176
|
+
readonly signal: CancelSignal;
|
|
177
|
+
/**
|
|
178
|
+
* `base64url(sha256(runId, stepKey, inputHash, attempt))`, on the pending entry BEFORE this
|
|
179
|
+
* handler was called. SUBMIT UNDER IT, idempotently: a resumed run reissues the same id and the
|
|
180
|
+
* far side recognises it rather than creating a second goal. This is the identity that makes an
|
|
181
|
+
* effect recoverable; {@link EffectContext.bind} carries facts the handler LEARNS and is never
|
|
182
|
+
* what recovery keys on, because a crash before the handler learned them leaves none.
|
|
183
|
+
*/
|
|
184
|
+
readonly requestId: string;
|
|
185
|
+
/**
|
|
186
|
+
* Which attempt of this step {@link EffectContext.requestId} names, counted from 0.
|
|
187
|
+
*
|
|
188
|
+
* Only an escalating checkpoint ever exceeds 0, and it is the interpreter, not the handler, that
|
|
189
|
+
* decides whether to hop. A handler reads this for tracing and for the far side's own idempotency
|
|
190
|
+
* bookkeeping; it must not treat a non-zero attempt as licence to retry, because the attempt that
|
|
191
|
+
* is open is the only one it has been asked to complete.
|
|
192
|
+
*/
|
|
193
|
+
readonly attempt: number;
|
|
194
|
+
/**
|
|
195
|
+
* Present when a previous attempt at this step started but never settled, carrying whatever it
|
|
196
|
+
* passed to {@link EffectContext.bind}. The handler must RE-BIND to that resource and await its
|
|
197
|
+
* terminal, not issue a fresh action: the goal already exists, the checkpoint token is already
|
|
198
|
+
* minted, and issuing a second one is how a crash turns into a duplicate side effect.
|
|
199
|
+
*/
|
|
200
|
+
readonly resume?: Readonly<Record<string, unknown>>;
|
|
201
|
+
/**
|
|
202
|
+
* Declare the external resource this effect just created, BEFORE awaiting its terminal.
|
|
203
|
+
*
|
|
204
|
+
* This is what makes a crash mid-effect recoverable: the pending journal entry points at a
|
|
205
|
+
* real thing, so a resumed run re-binds to it and awaits its outcome instead of issuing a
|
|
206
|
+
* second action. Idempotency then comes from the layer underneath (a goal's bind fingerprint,
|
|
207
|
+
* a checkpoint's one-use settle fact, a work item's lease).
|
|
208
|
+
*/
|
|
209
|
+
bind(external: Readonly<Record<string, unknown>>): Promise<void>;
|
|
210
|
+
}
|
|
211
|
+
export interface EffectHandler {
|
|
212
|
+
/**
|
|
213
|
+
* The host clock, which the interpreter uses to stamp `startedAt` and `endedAt` on journal
|
|
214
|
+
* entries. Production reads the wall clock; simulation reads a virtual one, which is how a
|
|
215
|
+
* program that waits four hours is tested in microseconds without pretending the wait did not
|
|
216
|
+
* happen. The program's own `now()` never reads this: it reads the run clock derived from
|
|
217
|
+
* those journalled stamps, which is what makes time advance only at effect boundaries.
|
|
218
|
+
*/
|
|
219
|
+
now(): number;
|
|
220
|
+
spawn(req: SpawnRequest, ctx: EffectContext): Promise<AgentHandleValue>;
|
|
221
|
+
turn(req: TurnRequest, ctx: EffectContext): Promise<TurnResultValue>;
|
|
222
|
+
ask(req: AskRequest, ctx: EffectContext): Promise<unknown>;
|
|
223
|
+
checkpoint(req: CheckpointRequest, ctx: EffectContext): Promise<CheckpointRaw>;
|
|
224
|
+
sleep(req: SleepRequest, ctx: EffectContext): Promise<null>;
|
|
225
|
+
wait(req: WaitRequest, ctx: EffectContext): Promise<unknown | null>;
|
|
226
|
+
notify(req: NotifyRequest, ctx: EffectContext): Promise<null>;
|
|
227
|
+
monitor(req: MonitorRequest, ctx: EffectContext): Promise<null>;
|
|
228
|
+
openConclave(req: ConclaveRequest, ctx: EffectContext): Promise<ChannelHandleValue>;
|
|
229
|
+
closeConclave(req: ConclaveRequest, ctx: EffectContext): Promise<null>;
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=effects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"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"}
|
package/dist/effects.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The effect interface: one seam, two implementations.
|
|
3
|
+
*
|
|
4
|
+
* A handler is told to do a thing and reports what happened. It never touches the journal. That
|
|
5
|
+
* split is what makes the simulator a real test harness rather than a second implementation to
|
|
6
|
+
* keep in sync: every durability rule holds identically under simulation and production, because
|
|
7
|
+
* the interpreter, not the handler, is what enforces them.
|
|
8
|
+
*
|
|
9
|
+
* The simulation handler lives in this package. The production handler binds these calls onto the
|
|
10
|
+
* mesh (goals, checkpoints, work leases) and lives outside it, so this package stays pure.
|
|
11
|
+
*/
|
|
12
|
+
// ---- the handler contract ---------------------------------------------------------------------
|
|
13
|
+
/** Raised by a handler when an effect fails in a way the program can catch. */
|
|
14
|
+
export class EffectError extends Error {
|
|
15
|
+
code;
|
|
16
|
+
kind;
|
|
17
|
+
detail;
|
|
18
|
+
constructor(code, kind, message, detail) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.kind = kind;
|
|
22
|
+
this.detail = detail;
|
|
23
|
+
this.name = "EffectError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Raised into a branch that a `race` loser or a run cancellation has cut short. */
|
|
27
|
+
export class Cancelled extends Error {
|
|
28
|
+
reason;
|
|
29
|
+
constructor(reason) {
|
|
30
|
+
super(`cancelled: ${reason}`);
|
|
31
|
+
this.reason = reason;
|
|
32
|
+
this.name = "Cancelled";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Raw outcome to what the program sees, computed from TODAY's source.
|
|
37
|
+
*
|
|
38
|
+
* The same call runs on the live path and after a journal hit, which is the whole point: a resumed
|
|
39
|
+
* run must reach this with the recorded fact and the current `onExpiry`, so editing `proceed` to
|
|
40
|
+
* `fail` makes the resume throw even though nothing about the recorded expiry changed.
|
|
41
|
+
*
|
|
42
|
+
* `escalate` never arrives here. It mints an effect rather than choosing a disposition, so it is
|
|
43
|
+
* hashed (design 5.12) and an edit to it diverges before any of this runs.
|
|
44
|
+
*/
|
|
45
|
+
export function applyCheckpointPolicy(raw, onExpiry) {
|
|
46
|
+
if (raw.outcome === "resolved") {
|
|
47
|
+
return {
|
|
48
|
+
status: "resolved",
|
|
49
|
+
...(raw.value !== undefined ? { value: raw.value } : {}),
|
|
50
|
+
...(raw.by !== undefined ? { by: raw.by } : {}),
|
|
51
|
+
...(raw.artifact !== undefined ? { artifact: raw.artifact } : {}),
|
|
52
|
+
at: raw.at,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// `escalate` reaching here means the chain is FINISHED: the interpreter already performed the
|
|
56
|
+
// one hop, and a second expiry settles exactly as `proceed` would (design 5.5, one hop). Only
|
|
57
|
+
// `fail` throws. Treating escalate as a throw made a completed escalation raise L4007, which is
|
|
58
|
+
// the opposite of what the stop rule says happens.
|
|
59
|
+
const disposition = onExpiry ?? "fail";
|
|
60
|
+
if (disposition === "proceed" || disposition === "escalate")
|
|
61
|
+
return { status: "expired", at: raw.at };
|
|
62
|
+
throw new EffectError("L4007", "checkpoint-expired", `L4007 Checkpoint expired\n\nNobody answered in time and this checkpoint's onExpiry is "fail".\n\nOptions\n onExpiry: "proceed" return { status: "expired" } and let the program decide\n onExpiry: "escalate" mint a second checkpoint addressed to someone else\n raise the timeout`);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiJH,kGAAkG;AAElG,+EAA+E;AAC/E,MAAM,OAAO,WAAY,SAAQ,KAAK;IAEzB;IACA;IAEA;IAJX,YACW,IAAY,EACZ,IAAY,EACrB,OAAe,EACN,MAA0C;QAEnD,KAAK,CAAC,OAAO,CAAC,CAAC;QALN,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAQ;QAEZ,WAAM,GAAN,MAAM,CAAoC;QAGnD,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,oFAAoF;AACpF,MAAM,OAAO,SAAU,SAAQ,KAAK;IACb;IAArB,YAAqB,MAAc;QACjC,KAAK,CAAC,cAAc,MAAM,EAAE,CAAC,CAAC;QADX,WAAM,GAAN,MAAM,CAAQ;QAEjC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAkB,EAClB,QAAqD;IAErD,IAAI,GAAG,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAC/B,OAAO;YACL,MAAM,EAAE,UAAU;YAClB,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,EAAE,EAAE,GAAG,CAAC,EAAE;SACX,CAAC;IACJ,CAAC;IACD,8FAA8F;IAC9F,8FAA8F;IAC9F,gGAAgG;IAChG,mDAAmD;IACnD,MAAM,WAAW,GAAG,QAAQ,IAAI,MAAM,CAAC;IACvC,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;IACtG,MAAM,IAAI,WAAW,CACnB,OAAO,EACP,oBAAoB,EACpB,8RAA8R,CAC/R,CAAC;AACJ,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error catalog. Errors are the primary UI of this language: their audience is an LLM
|
|
3
|
+
* repairing its own program, so every error whose cause is a call to a primitive carries that
|
|
4
|
+
* primitive's full signature and one working example, and the blame frame is always in
|
|
5
|
+
* user-program coordinates.
|
|
6
|
+
*
|
|
7
|
+
* Codes are stable and grouped: L1xxx grammar, L2xxx name resolution and static rules, L3xxx
|
|
8
|
+
* effect call shape, L4xxx runtime semantics, L5xxx durability, L6xxx simulation.
|
|
9
|
+
*/
|
|
10
|
+
/** Every code in the catalog, with the one-line title that heads the rendered error. */
|
|
11
|
+
export declare const CATALOG: {
|
|
12
|
+
readonly L1001: "Forbidden syntax: `class`";
|
|
13
|
+
readonly L1002: "Forbidden syntax: `this`";
|
|
14
|
+
readonly L1003: "Forbidden syntax: `var`";
|
|
15
|
+
readonly L1004: "Forbidden syntax: `for...in`";
|
|
16
|
+
readonly L1005: "Forbidden syntax: generator";
|
|
17
|
+
readonly L1006: "Forbidden syntax: `eval` or `Function`";
|
|
18
|
+
readonly L1007: "Forbidden syntax: regular expression literal";
|
|
19
|
+
readonly L1008: "Missing semicolon";
|
|
20
|
+
readonly L1009: "Unbraced branch";
|
|
21
|
+
readonly L1010: "`switch` case does not terminate";
|
|
22
|
+
readonly L1011: "Computed property name";
|
|
23
|
+
readonly L1012: "Array elision";
|
|
24
|
+
readonly L1013: "Forbidden syntax: `with`";
|
|
25
|
+
readonly L1014: "Forbidden syntax: symbol";
|
|
26
|
+
readonly L1015: "Forbidden syntax: accessor";
|
|
27
|
+
readonly L1016: "Forbidden syntax: `instanceof`";
|
|
28
|
+
readonly L1017: "Forbidden syntax: label";
|
|
29
|
+
readonly L1018: "Forbidden syntax: tagged template literal";
|
|
30
|
+
readonly L1019: "Forbidden syntax: `new`";
|
|
31
|
+
readonly L1020: "Forbidden syntax: `import` or `export`";
|
|
32
|
+
readonly L1021: "Forbidden syntax: `delete`";
|
|
33
|
+
readonly L1022: "Forbidden syntax: `do...while`";
|
|
34
|
+
readonly L1023: "Forbidden syntax: `await` outside an async function";
|
|
35
|
+
readonly L1024: "`return` outside a function";
|
|
36
|
+
readonly L2001: "Unknown identifier";
|
|
37
|
+
readonly L2002: "Shadows a builtin or a primitive";
|
|
38
|
+
readonly L2003: "Assignment to a `const` binding";
|
|
39
|
+
readonly L2011: "The Promise API is not available";
|
|
40
|
+
readonly L2013: "An async call is not awaited";
|
|
41
|
+
readonly L2012: "Host global is not available";
|
|
42
|
+
readonly L2031: "Mutation of a frozen value";
|
|
43
|
+
readonly L3011: "Unknown option key";
|
|
44
|
+
readonly L3012: "Missing required step name";
|
|
45
|
+
readonly L3013: "Step name is not a literal";
|
|
46
|
+
readonly L3014: "Malformed step name";
|
|
47
|
+
readonly L3021: "`fanOut` has no stable key";
|
|
48
|
+
readonly L3022: "Two agents share a worktree concurrently";
|
|
49
|
+
readonly L3023: "Array-form `parallel` holds named effects";
|
|
50
|
+
readonly L3024: "`fanOut` branch keys are not unique";
|
|
51
|
+
readonly L3041: "Value cannot cross an effect boundary";
|
|
52
|
+
readonly L3042: "Function passed as effect data";
|
|
53
|
+
readonly L3043: "`notify` fact is not a bounded decision record";
|
|
54
|
+
readonly L3044: "`to` without `onExpiry: \"escalate\"`";
|
|
55
|
+
readonly L4001: "Permit exhausted";
|
|
56
|
+
readonly L4002: "Agent down";
|
|
57
|
+
readonly L4003: "Turn deadline elapsed";
|
|
58
|
+
readonly L4004: "Handoff across worktrees";
|
|
59
|
+
readonly L4005: "Handoff to an agent outside the run";
|
|
60
|
+
readonly L4006: "`ask` never produced a conforming record";
|
|
61
|
+
readonly L4007: "Checkpoint expired";
|
|
62
|
+
readonly L4008: "Concurrent worktree write";
|
|
63
|
+
readonly L4009: "Run effect ceiling reached";
|
|
64
|
+
readonly L4013: "Step budget exhausted";
|
|
65
|
+
readonly L5001: "Run divergence";
|
|
66
|
+
readonly L5002: "Program hash not available";
|
|
67
|
+
readonly L5003: "Orphaned `spawn` on migrate";
|
|
68
|
+
readonly L5004: "Orphaned resolved checkpoint on migrate";
|
|
69
|
+
readonly L5005: "External reference gone";
|
|
70
|
+
readonly L5006: "Effect result too large";
|
|
71
|
+
readonly L5007: "Lease lost";
|
|
72
|
+
readonly L6001: "Unscripted effect in simulation";
|
|
73
|
+
readonly L6002: "Simulation script entry unused";
|
|
74
|
+
};
|
|
75
|
+
export type LangErrorCode = keyof typeof CATALOG;
|
|
76
|
+
/** A primitive's documentation, attached to any error blamed on a call to it. */
|
|
77
|
+
export interface CalleeDoc {
|
|
78
|
+
readonly signature: string;
|
|
79
|
+
readonly doc: string;
|
|
80
|
+
readonly example: string;
|
|
81
|
+
}
|
|
82
|
+
/** Where in the user's program the blame lands. Always user-program coordinates. */
|
|
83
|
+
export interface SourceSpan {
|
|
84
|
+
readonly file: string;
|
|
85
|
+
/** 1-based. */
|
|
86
|
+
readonly line: number;
|
|
87
|
+
/** 1-based. */
|
|
88
|
+
readonly column: number;
|
|
89
|
+
}
|
|
90
|
+
/** The machine-parseable form. This is what a repair loop consumes. */
|
|
91
|
+
export interface LangErrorJson {
|
|
92
|
+
readonly code: LangErrorCode;
|
|
93
|
+
readonly title: string;
|
|
94
|
+
readonly where: SourceSpan & {
|
|
95
|
+
readonly frame: string;
|
|
96
|
+
};
|
|
97
|
+
readonly cause: string;
|
|
98
|
+
readonly fix: string;
|
|
99
|
+
readonly callee?: CalleeDoc;
|
|
100
|
+
}
|
|
101
|
+
export interface LangErrorInit {
|
|
102
|
+
readonly code: LangErrorCode;
|
|
103
|
+
readonly span: SourceSpan;
|
|
104
|
+
/** Plain English: why this is wrong, in terms of what the program is trying to do. */
|
|
105
|
+
readonly cause: string;
|
|
106
|
+
/** The edit that fixes it, concretely enough to apply. */
|
|
107
|
+
readonly fix: string;
|
|
108
|
+
/** The primitive this call named, when the error is blamed on one. */
|
|
109
|
+
readonly callee?: CalleeDoc;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build the code frame: the offending line with a caret under the column. Rendering it here,
|
|
113
|
+
* from the source the parser saw, is what keeps the blame frame in user coordinates rather than
|
|
114
|
+
* in interpreter internals.
|
|
115
|
+
*/
|
|
116
|
+
export declare function codeFrame(source: string, span: SourceSpan): string;
|
|
117
|
+
/** One error. Carries its own rendering so no caller has to reinvent the format. */
|
|
118
|
+
export declare class LangError extends Error {
|
|
119
|
+
readonly code: LangErrorCode;
|
|
120
|
+
readonly title: string;
|
|
121
|
+
readonly span: SourceSpan;
|
|
122
|
+
readonly cause: string;
|
|
123
|
+
readonly fix: string;
|
|
124
|
+
readonly callee?: CalleeDoc;
|
|
125
|
+
constructor(init: LangErrorInit);
|
|
126
|
+
toJSON(source: string): LangErrorJson;
|
|
127
|
+
/** The human rendering: frame, cause, fix, then the callee's signature and example. */
|
|
128
|
+
render(source: string): string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The validator collects every error before reporting, so an author sees the whole repair list
|
|
132
|
+
* at once rather than fixing one thing per round trip.
|
|
133
|
+
*/
|
|
134
|
+
export declare class LangErrors extends Error {
|
|
135
|
+
readonly errors: readonly LangError[];
|
|
136
|
+
readonly source: string;
|
|
137
|
+
constructor(errors: readonly LangError[], source: string);
|
|
138
|
+
toJSON(): readonly LangErrorJson[];
|
|
139
|
+
render(): string;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wFAAwF;AACxF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0EV,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,OAAO,CAAC;AAEjD,iFAAiF;AACjF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,eAAe;IACf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,eAAe;IACf,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CASlE;AAED,oFAAoF;AACpF,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;gBAEhB,IAAI,EAAE,aAAa;IAW/B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAWrC,uFAAuF;IACvF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAe/B;AAED;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,MAAM,EAAE,MAAM;IAOxD,MAAM,IAAI,SAAS,aAAa,EAAE;IAIlC,MAAM,IAAI,MAAM;CAGjB"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error catalog. Errors are the primary UI of this language: their audience is an LLM
|
|
3
|
+
* repairing its own program, so every error whose cause is a call to a primitive carries that
|
|
4
|
+
* primitive's full signature and one working example, and the blame frame is always in
|
|
5
|
+
* user-program coordinates.
|
|
6
|
+
*
|
|
7
|
+
* Codes are stable and grouped: L1xxx grammar, L2xxx name resolution and static rules, L3xxx
|
|
8
|
+
* effect call shape, L4xxx runtime semantics, L5xxx durability, L6xxx simulation.
|
|
9
|
+
*/
|
|
10
|
+
/** Every code in the catalog, with the one-line title that heads the rendered error. */
|
|
11
|
+
export const CATALOG = {
|
|
12
|
+
// ---- L1xxx: grammar -----------------------------------------------------------------------
|
|
13
|
+
L1001: "Forbidden syntax: `class`",
|
|
14
|
+
L1002: "Forbidden syntax: `this`",
|
|
15
|
+
L1003: "Forbidden syntax: `var`",
|
|
16
|
+
L1004: "Forbidden syntax: `for...in`",
|
|
17
|
+
L1005: "Forbidden syntax: generator",
|
|
18
|
+
L1006: "Forbidden syntax: `eval` or `Function`",
|
|
19
|
+
L1007: "Forbidden syntax: regular expression literal",
|
|
20
|
+
L1008: "Missing semicolon",
|
|
21
|
+
L1009: "Unbraced branch",
|
|
22
|
+
L1010: "`switch` case does not terminate",
|
|
23
|
+
L1011: "Computed property name",
|
|
24
|
+
L1012: "Array elision",
|
|
25
|
+
L1013: "Forbidden syntax: `with`",
|
|
26
|
+
L1014: "Forbidden syntax: symbol",
|
|
27
|
+
L1015: "Forbidden syntax: accessor",
|
|
28
|
+
L1016: "Forbidden syntax: `instanceof`",
|
|
29
|
+
L1017: "Forbidden syntax: label",
|
|
30
|
+
L1018: "Forbidden syntax: tagged template literal",
|
|
31
|
+
L1019: "Forbidden syntax: `new`",
|
|
32
|
+
L1020: "Forbidden syntax: `import` or `export`",
|
|
33
|
+
L1021: "Forbidden syntax: `delete`",
|
|
34
|
+
L1022: "Forbidden syntax: `do...while`",
|
|
35
|
+
L1023: "Forbidden syntax: `await` outside an async function",
|
|
36
|
+
L1024: "`return` outside a function",
|
|
37
|
+
// ---- L2xxx: name resolution and static rules ----------------------------------------------
|
|
38
|
+
L2001: "Unknown identifier",
|
|
39
|
+
L2002: "Shadows a builtin or a primitive",
|
|
40
|
+
L2003: "Assignment to a `const` binding",
|
|
41
|
+
L2011: "The Promise API is not available",
|
|
42
|
+
L2013: "An async call is not awaited",
|
|
43
|
+
L2012: "Host global is not available",
|
|
44
|
+
L2031: "Mutation of a frozen value",
|
|
45
|
+
// ---- L3xxx: effect call shape --------------------------------------------------------------
|
|
46
|
+
L3011: "Unknown option key",
|
|
47
|
+
L3012: "Missing required step name",
|
|
48
|
+
L3013: "Step name is not a literal",
|
|
49
|
+
L3014: "Malformed step name",
|
|
50
|
+
L3021: "`fanOut` has no stable key",
|
|
51
|
+
L3022: "Two agents share a worktree concurrently",
|
|
52
|
+
L3023: "Array-form `parallel` holds named effects",
|
|
53
|
+
L3024: "`fanOut` branch keys are not unique",
|
|
54
|
+
L3041: "Value cannot cross an effect boundary",
|
|
55
|
+
L3042: "Function passed as effect data",
|
|
56
|
+
L3043: "`notify` fact is not a bounded decision record",
|
|
57
|
+
L3044: "`to` without `onExpiry: \"escalate\"`",
|
|
58
|
+
// ---- L4xxx: runtime semantics ---------------------------------------------------------------
|
|
59
|
+
L4001: "Permit exhausted",
|
|
60
|
+
L4002: "Agent down",
|
|
61
|
+
L4003: "Turn deadline elapsed",
|
|
62
|
+
L4004: "Handoff across worktrees",
|
|
63
|
+
L4005: "Handoff to an agent outside the run",
|
|
64
|
+
L4006: "`ask` never produced a conforming record",
|
|
65
|
+
L4007: "Checkpoint expired",
|
|
66
|
+
L4008: "Concurrent worktree write",
|
|
67
|
+
L4009: "Run effect ceiling reached",
|
|
68
|
+
L4013: "Step budget exhausted",
|
|
69
|
+
// ---- L5xxx: durability -----------------------------------------------------------------------
|
|
70
|
+
L5001: "Run divergence",
|
|
71
|
+
L5002: "Program hash not available",
|
|
72
|
+
L5003: "Orphaned `spawn` on migrate",
|
|
73
|
+
L5004: "Orphaned resolved checkpoint on migrate",
|
|
74
|
+
L5005: "External reference gone",
|
|
75
|
+
L5006: "Effect result too large",
|
|
76
|
+
L5007: "Lease lost",
|
|
77
|
+
// ---- L6xxx: simulation -------------------------------------------------------------------------
|
|
78
|
+
L6001: "Unscripted effect in simulation",
|
|
79
|
+
L6002: "Simulation script entry unused",
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Build the code frame: the offending line with a caret under the column. Rendering it here,
|
|
83
|
+
* from the source the parser saw, is what keeps the blame frame in user coordinates rather than
|
|
84
|
+
* in interpreter internals.
|
|
85
|
+
*/
|
|
86
|
+
export function codeFrame(source, span) {
|
|
87
|
+
const lines = source.split("\n");
|
|
88
|
+
const idx = span.line - 1;
|
|
89
|
+
if (idx < 0 || idx >= lines.length)
|
|
90
|
+
return "";
|
|
91
|
+
const gutter = String(span.line);
|
|
92
|
+
const pad = " ".repeat(gutter.length);
|
|
93
|
+
const text = lines[idx] ?? "";
|
|
94
|
+
const caretPad = " ".repeat(Math.max(0, span.column - 1));
|
|
95
|
+
return `${gutter} | ${text}\n${pad} | ${caretPad}^`;
|
|
96
|
+
}
|
|
97
|
+
/** One error. Carries its own rendering so no caller has to reinvent the format. */
|
|
98
|
+
export class LangError extends Error {
|
|
99
|
+
code;
|
|
100
|
+
title;
|
|
101
|
+
span;
|
|
102
|
+
cause;
|
|
103
|
+
fix;
|
|
104
|
+
callee;
|
|
105
|
+
constructor(init) {
|
|
106
|
+
super(`${init.code} ${CATALOG[init.code]}`);
|
|
107
|
+
this.name = "LangError";
|
|
108
|
+
this.code = init.code;
|
|
109
|
+
this.title = CATALOG[init.code];
|
|
110
|
+
this.span = init.span;
|
|
111
|
+
this.cause = init.cause;
|
|
112
|
+
this.fix = init.fix;
|
|
113
|
+
if (init.callee !== undefined)
|
|
114
|
+
this.callee = init.callee;
|
|
115
|
+
}
|
|
116
|
+
toJSON(source) {
|
|
117
|
+
const base = {
|
|
118
|
+
code: this.code,
|
|
119
|
+
title: this.title,
|
|
120
|
+
where: { ...this.span, frame: codeFrame(source, this.span) },
|
|
121
|
+
cause: this.cause,
|
|
122
|
+
fix: this.fix,
|
|
123
|
+
};
|
|
124
|
+
return this.callee === undefined ? base : { ...base, callee: this.callee };
|
|
125
|
+
}
|
|
126
|
+
/** The human rendering: frame, cause, fix, then the callee's signature and example. */
|
|
127
|
+
render(source) {
|
|
128
|
+
const parts = [
|
|
129
|
+
`${this.code} ${this.title}`,
|
|
130
|
+
"",
|
|
131
|
+
codeFrame(source, this.span),
|
|
132
|
+
"",
|
|
133
|
+
this.cause,
|
|
134
|
+
"",
|
|
135
|
+
`Fix: ${this.fix}`,
|
|
136
|
+
];
|
|
137
|
+
if (this.callee !== undefined) {
|
|
138
|
+
parts.push("", this.callee.signature, this.callee.doc, "", this.callee.example);
|
|
139
|
+
}
|
|
140
|
+
return parts.join("\n");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The validator collects every error before reporting, so an author sees the whole repair list
|
|
145
|
+
* at once rather than fixing one thing per round trip.
|
|
146
|
+
*/
|
|
147
|
+
export class LangErrors extends Error {
|
|
148
|
+
errors;
|
|
149
|
+
source;
|
|
150
|
+
constructor(errors, source) {
|
|
151
|
+
super(`${errors.length} error${errors.length === 1 ? "" : "s"} in program`);
|
|
152
|
+
this.name = "LangErrors";
|
|
153
|
+
this.errors = errors;
|
|
154
|
+
this.source = source;
|
|
155
|
+
}
|
|
156
|
+
toJSON() {
|
|
157
|
+
return this.errors.map((e) => e.toJSON(this.source));
|
|
158
|
+
}
|
|
159
|
+
render() {
|
|
160
|
+
return this.errors.map((e) => e.render(this.source)).join("\n\n");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The validator: one acorn parse followed by two AST walks, before anything executes.
|
|
3
|
+
*
|
|
4
|
+
* This file is where the design's central claim becomes mechanical rather than aspirational. A
|
|
5
|
+
* program that could reach ambient IO, an ambient clock, host identity, or hidden concurrency
|
|
6
|
+
* does not parse, so "determinism by convention" is not an option an author can take. Every rule
|
|
7
|
+
* in section 3 of the design doc maps to a check here and to a stable error code.
|
|
8
|
+
*
|
|
9
|
+
* Walk 1 is SHAPE: reject forbidden node types. Walk 2 is RESOLUTION: build the scope tree, bind
|
|
10
|
+
* every identifier, and check effect call shape. Both collect every error before reporting, so an
|
|
11
|
+
* author sees the whole repair list at once instead of one item per round trip.
|
|
12
|
+
*/
|
|
13
|
+
import type { Node } from "acorn";
|
|
14
|
+
import { LangError } from "./errors.js";
|
|
15
|
+
/** Acorn nodes are loosely typed; this is the shape we actually read. */
|
|
16
|
+
type AnyNode = Node & Record<string, unknown>;
|
|
17
|
+
export interface ValidateResult {
|
|
18
|
+
readonly ast: AnyNode;
|
|
19
|
+
readonly warnings: readonly LangError[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse and validate a program. Throws {@link LangErrors} carrying every problem found, so an
|
|
23
|
+
* author repairs the whole list in one pass. Returns the AST plus the lints that did not fail
|
|
24
|
+
* the program.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validate(source: string, file?: string): ValidateResult;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=grammar.d.ts.map
|