@sharpee/chord 3.0.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/analyzer.d.ts +31 -0
- package/analyzer.d.ts.map +1 -0
- package/analyzer.js +1656 -0
- package/analyzer.js.map +1 -0
- package/ast.d.ts +684 -0
- package/ast.d.ts.map +1 -0
- package/ast.js +3 -0
- package/ast.js.map +1 -0
- package/catalog.d.ts +43 -0
- package/catalog.d.ts.map +1 -0
- package/catalog.js +77 -0
- package/catalog.js.map +1 -0
- package/diagnostics.d.ts +38 -0
- package/diagnostics.d.ts.map +1 -0
- package/diagnostics.js +29 -0
- package/diagnostics.js.map +1 -0
- package/index.d.ts +39 -0
- package/index.d.ts.map +1 -0
- package/index.js +77 -0
- package/index.js.map +1 -0
- package/ir.d.ts +511 -0
- package/ir.d.ts.map +1 -0
- package/ir.js +6 -0
- package/ir.js.map +1 -0
- package/lexer.d.ts +49 -0
- package/lexer.d.ts.map +1 -0
- package/lexer.js +88 -0
- package/lexer.js.map +1 -0
- package/package.json +40 -0
- package/parser.d.ts +29 -0
- package/parser.d.ts.map +1 -0
- package/parser.js +2303 -0
- package/parser.js.map +1 -0
- package/span.d.ts +30 -0
- package/span.d.ts.map +1 -0
- package/span.js +34 -0
- package/span.js.map +1 -0
package/ast.d.ts
ADDED
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ast.ts — the Chord abstract syntax tree (Phase A grammar subset).
|
|
3
|
+
*
|
|
4
|
+
* Purpose: the parser's output — a faithful, span-carrying tree of the
|
|
5
|
+
* `.story` text. The AST is pre-resolution: entity/phrase/state references
|
|
6
|
+
* are still raw word sequences; event headers are unsegmented word lists
|
|
7
|
+
* (verb vocabulary belongs to the analyzer, keeping the parser
|
|
8
|
+
* platform-free per design.md §5.2).
|
|
9
|
+
*
|
|
10
|
+
* Public interface: every exported node type; StoryFile is the root.
|
|
11
|
+
* Owner context: @sharpee/chord (language frontend; browser-safe).
|
|
12
|
+
*/
|
|
13
|
+
import type { Span } from './span';
|
|
14
|
+
/** Root of a parsed `.story` file. */
|
|
15
|
+
export interface StoryFile {
|
|
16
|
+
kind: 'story-file';
|
|
17
|
+
header: StoryHeader | null;
|
|
18
|
+
declarations: Declaration[];
|
|
19
|
+
span: Span;
|
|
20
|
+
}
|
|
21
|
+
/** `story "Title" by "Author"` plus its indented `key: value` fields. */
|
|
22
|
+
export interface StoryHeader {
|
|
23
|
+
kind: 'story-header';
|
|
24
|
+
title: string;
|
|
25
|
+
author: string;
|
|
26
|
+
/** Raw field values by key (id, version, blurb, ...), trimmed. */
|
|
27
|
+
fields: Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* `states: a, b` — the story's phases (ownership package D2). The story
|
|
30
|
+
* starts in the first declared state; bare state names are condition refs.
|
|
31
|
+
*/
|
|
32
|
+
states: StateName[];
|
|
33
|
+
/** `states, reversible:` — declared back-transitions allowed (D4). */
|
|
34
|
+
statesReversible: boolean;
|
|
35
|
+
/** `score <name> worth N` lines — story-owned score identities (D12). */
|
|
36
|
+
scores: ScoreDecl[];
|
|
37
|
+
span: Span;
|
|
38
|
+
}
|
|
39
|
+
/** `score <name> worth <n>` on an owner (create/trait/action/story — D12). */
|
|
40
|
+
export interface ScoreDecl {
|
|
41
|
+
kind: 'score';
|
|
42
|
+
name: string;
|
|
43
|
+
worth: number;
|
|
44
|
+
span: Span;
|
|
45
|
+
}
|
|
46
|
+
export type Declaration = CreateDecl | DefineCondition | DefinePhrase | DefinePhrases | DefineVerb | DefineText | DefineTrait | DefineAction | DefineHatch | DefineSequence;
|
|
47
|
+
/** A raw (unresolved) name reference: optional article + word sequence. */
|
|
48
|
+
export interface NameRef {
|
|
49
|
+
kind: 'name';
|
|
50
|
+
/** Leading article if present (`the`, `a`, `an`) — resolution strips it. */
|
|
51
|
+
article: string | null;
|
|
52
|
+
/** Name words in source order, joined by single spaces. */
|
|
53
|
+
words: string[];
|
|
54
|
+
span: Span;
|
|
55
|
+
}
|
|
56
|
+
/** Prose-block text; `{…}` markers extracted but not validated (parser stage). */
|
|
57
|
+
export interface TextValue {
|
|
58
|
+
kind: 'text';
|
|
59
|
+
/**
|
|
60
|
+
* 'prose' = indented bare block — inter-line whitespace collapsed, blank
|
|
61
|
+
* lines become `\n\n` paragraph breaks. 'verbatim' = line structure and
|
|
62
|
+
* indentation preserved exactly (`define phrase X, verbatim`). The quoted
|
|
63
|
+
* same-line form was removed (grammar log 2026-07-10).
|
|
64
|
+
*/
|
|
65
|
+
form: 'prose' | 'verbatim';
|
|
66
|
+
/** The text (paragraphs separated by `\n\n`; verbatim lines by `\n`). */
|
|
67
|
+
text: string;
|
|
68
|
+
markers: TextMarker[];
|
|
69
|
+
span: Span;
|
|
70
|
+
}
|
|
71
|
+
/** One `{…}` marker inside a TextValue. */
|
|
72
|
+
export interface TextMarker {
|
|
73
|
+
/** Marker content between the braces, e.g. `garbled` or `snippet:pond`. */
|
|
74
|
+
content: string;
|
|
75
|
+
span: Span;
|
|
76
|
+
}
|
|
77
|
+
/** `create <name>` block (dedent-terminated). */
|
|
78
|
+
export interface CreateDecl {
|
|
79
|
+
kind: 'create';
|
|
80
|
+
name: NameRef;
|
|
81
|
+
/** `aka` aliases, in declaration order. */
|
|
82
|
+
aka: string[];
|
|
83
|
+
/** Kind-noun and trait-adjective composition items. */
|
|
84
|
+
compositions: CompositionItem[];
|
|
85
|
+
/** `in <place>` / `on <place>` / `starts in <place>`. */
|
|
86
|
+
placement: Placement | null;
|
|
87
|
+
/** `wears <thing>` lines (the player wears the cloak). */
|
|
88
|
+
wears: NameRef[];
|
|
89
|
+
exits: ExitDecl[];
|
|
90
|
+
blockedExits: BlockedExitDecl[];
|
|
91
|
+
/** `states: a, b, c` — ordered. */
|
|
92
|
+
states: StateName[];
|
|
93
|
+
/** `states, reversible:` — declared back-transitions allowed (D4). */
|
|
94
|
+
statesReversible: boolean;
|
|
95
|
+
/** `score <name> worth N` lines — entity-owned scores (D12). */
|
|
96
|
+
scores: ScoreDecl[];
|
|
97
|
+
/** First bare indented paragraph. */
|
|
98
|
+
description: TextValue | null;
|
|
99
|
+
/**
|
|
100
|
+
* `first time` prose block (Z1) — the first-VISIT description; compiles
|
|
101
|
+
* to `RoomTrait.initialDescription`. Rooms only (analyzer-enforced).
|
|
102
|
+
*/
|
|
103
|
+
initialDescription: TextValue | null;
|
|
104
|
+
/** Per-entity phrase overrides: `phrase <key>: <text>` lines. */
|
|
105
|
+
phraseOverrides: PhraseOverride[];
|
|
106
|
+
onClauses: OnClause[];
|
|
107
|
+
span: Span;
|
|
108
|
+
}
|
|
109
|
+
/** One composition term: `a room`, `scenery`, `a supporter with capacity 1`, `dark while <cond>`. */
|
|
110
|
+
export interface CompositionItem {
|
|
111
|
+
kind: 'composition';
|
|
112
|
+
/** Present iff the term is a kind noun (`a room`); absent for trait adjectives. */
|
|
113
|
+
article: string | null;
|
|
114
|
+
words: string[];
|
|
115
|
+
/** `with <setting> [and <setting>]…` configuration. */
|
|
116
|
+
config: ConfigSetting[];
|
|
117
|
+
/** `while <condition>` conditional composition (e.g. `dark while …`). */
|
|
118
|
+
condition: ConditionNode | null;
|
|
119
|
+
span: Span;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* One `with` setting. Values are a trailing number/string/word, or — when an
|
|
123
|
+
* article introduces the tail (`with food the handful of feed`, Phase B) — a
|
|
124
|
+
* multi-word entity name (`valueKind: 'name'`, article stripped).
|
|
125
|
+
*/
|
|
126
|
+
export interface ConfigSetting {
|
|
127
|
+
key: string[];
|
|
128
|
+
value: string;
|
|
129
|
+
valueKind: 'number' | 'string' | 'word' | 'name';
|
|
130
|
+
span: Span;
|
|
131
|
+
}
|
|
132
|
+
export interface Placement {
|
|
133
|
+
kind: 'placement';
|
|
134
|
+
/** 'in' | 'on' | 'starts-in' */
|
|
135
|
+
relation: 'in' | 'on' | 'starts-in';
|
|
136
|
+
place: NameRef;
|
|
137
|
+
span: Span;
|
|
138
|
+
}
|
|
139
|
+
export interface ExitDecl {
|
|
140
|
+
kind: 'exit';
|
|
141
|
+
direction: string;
|
|
142
|
+
to: NameRef;
|
|
143
|
+
span: Span;
|
|
144
|
+
}
|
|
145
|
+
export interface BlockedExitDecl {
|
|
146
|
+
kind: 'blocked-exit';
|
|
147
|
+
direction: string;
|
|
148
|
+
/** Phrase key emitted when the exit is tried. */
|
|
149
|
+
phraseKey: string;
|
|
150
|
+
/**
|
|
151
|
+
* `is blocked while <cond>: <key>` — refusal applies only while the
|
|
152
|
+
* condition holds (grammar log 2026-07-10, Phase B). Null = always.
|
|
153
|
+
*/
|
|
154
|
+
condition: ConditionNode | null;
|
|
155
|
+
span: Span;
|
|
156
|
+
}
|
|
157
|
+
export interface StateName {
|
|
158
|
+
name: string;
|
|
159
|
+
span: Span;
|
|
160
|
+
}
|
|
161
|
+
/** `phrase <key>: <text>` inside a create block (entity-scoped override). */
|
|
162
|
+
export interface PhraseOverride {
|
|
163
|
+
kind: 'phrase-override';
|
|
164
|
+
key: string;
|
|
165
|
+
/** Optional strategy adverb (CP3 — channel phrases carry the Z5 set), null when plain. */
|
|
166
|
+
strategy: string | null;
|
|
167
|
+
/**
|
|
168
|
+
* Optional `while <condition>` (Z3b `detail` gates; `it` = the owner).
|
|
169
|
+
* Null when ungated.
|
|
170
|
+
*/
|
|
171
|
+
condition: ConditionNode | null;
|
|
172
|
+
/** One entry when plain; several when `or`-separated variants (CP3). */
|
|
173
|
+
variants: TextValue[];
|
|
174
|
+
span: Span;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* `on|after … end on|end after` behavior clause — inside a create block or a
|
|
178
|
+
* `define trait`. Header forms (design.md §2.2 + ownership package D3/D5):
|
|
179
|
+
* `on <action> it [, before <trait> | , after <trait>] [, once]`
|
|
180
|
+
* `after <action> it [while <condition>] [, once]` → reaction (D3)
|
|
181
|
+
* `on <action> anything as the <role>` → binding 'role'
|
|
182
|
+
* `on every turn [while <condition>] [, once]` → binding 'every-turn'
|
|
183
|
+
* `on` intercepts (may refuse; phrase output is primary); `after` reacts
|
|
184
|
+
* (refuse is a parse error; phrase output appends).
|
|
185
|
+
*/
|
|
186
|
+
export interface OnClause {
|
|
187
|
+
kind: 'on-clause';
|
|
188
|
+
/** `on` = intercept, `after` = react (ratchet D3). */
|
|
189
|
+
clauseKind: 'on' | 'after';
|
|
190
|
+
/** The action word as written (gerund), e.g. `reading`; `every turn` clauses use 'every-turn'. */
|
|
191
|
+
action: string;
|
|
192
|
+
/** How the clause binds (Phase A only had 'it'). */
|
|
193
|
+
binding: 'it' | 'role' | 'every-turn';
|
|
194
|
+
/** Role name for `anything as the <role>` clauses. */
|
|
195
|
+
role: string | null;
|
|
196
|
+
/** `while <condition>` qualifier (all bindings since the ownership package). */
|
|
197
|
+
condition: ConditionNode | null;
|
|
198
|
+
/** `, once` clause modifier — one lifetime firing (ratchet D5). */
|
|
199
|
+
once: boolean;
|
|
200
|
+
/** `, before <trait>` / `, after <trait>` explicit ordering. */
|
|
201
|
+
ordering: {
|
|
202
|
+
relation: 'before' | 'after';
|
|
203
|
+
trait: string;
|
|
204
|
+
} | null;
|
|
205
|
+
body: Statement[];
|
|
206
|
+
span: Span;
|
|
207
|
+
}
|
|
208
|
+
/** `define condition <name>: <condition>` */
|
|
209
|
+
export interface DefineCondition {
|
|
210
|
+
kind: 'define-condition';
|
|
211
|
+
name: string;
|
|
212
|
+
condition: ConditionNode;
|
|
213
|
+
span: Span;
|
|
214
|
+
}
|
|
215
|
+
/** `define phrase <key>[, <strategy>|, verbatim] [while <condition>] … end phrase`. */
|
|
216
|
+
export interface DefinePhrase {
|
|
217
|
+
kind: 'define-phrase';
|
|
218
|
+
key: string;
|
|
219
|
+
/** randomly | cycling | stopping | sticky | first-time (Z5) — null for a plain phrase. */
|
|
220
|
+
strategy: string | null;
|
|
221
|
+
/** Whitespace-preserving text (grammar log 2026-07-10); excludes strategies. */
|
|
222
|
+
verbatim: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Trailing `while <condition>` header gate (Z2/CP1'): a presence condition
|
|
225
|
+
* compiles to ADR-209 `mentions`; anything else registers on the ADR-211
|
|
226
|
+
* gate seam. Null when ungated.
|
|
227
|
+
*/
|
|
228
|
+
condition: ConditionNode | null;
|
|
229
|
+
/** One entry when plain; several when `or`-separated variants. */
|
|
230
|
+
variants: TextValue[];
|
|
231
|
+
span: Span;
|
|
232
|
+
}
|
|
233
|
+
/** `define phrases <locale>` keyed-template block (dedent-terminated). */
|
|
234
|
+
export interface DefinePhrases {
|
|
235
|
+
kind: 'define-phrases';
|
|
236
|
+
locale: string;
|
|
237
|
+
entries: PhraseEntry[];
|
|
238
|
+
span: Span;
|
|
239
|
+
}
|
|
240
|
+
export interface PhraseEntry {
|
|
241
|
+
key: string;
|
|
242
|
+
value: TextValue;
|
|
243
|
+
span: Span;
|
|
244
|
+
}
|
|
245
|
+
/** `define verb hang or hook means put (something) on (something)` */
|
|
246
|
+
export interface DefineVerb {
|
|
247
|
+
kind: 'define-verb';
|
|
248
|
+
verbs: string[];
|
|
249
|
+
pattern: PatternPart[];
|
|
250
|
+
span: Span;
|
|
251
|
+
}
|
|
252
|
+
export type PatternPart = {
|
|
253
|
+
kind: 'word';
|
|
254
|
+
word: string;
|
|
255
|
+
span: Span;
|
|
256
|
+
} | {
|
|
257
|
+
kind: 'slot';
|
|
258
|
+
word: string;
|
|
259
|
+
span: Span;
|
|
260
|
+
};
|
|
261
|
+
/** `define text <name> from "<module>"` — TS escape hatch declaration. */
|
|
262
|
+
export interface DefineText {
|
|
263
|
+
kind: 'define-text';
|
|
264
|
+
name: string;
|
|
265
|
+
modulePath: string;
|
|
266
|
+
span: Span;
|
|
267
|
+
}
|
|
268
|
+
/** `define trait <name> … end trait` — data, states, phrases, behavior clauses. */
|
|
269
|
+
export interface DefineTrait {
|
|
270
|
+
kind: 'define-trait';
|
|
271
|
+
name: string;
|
|
272
|
+
data: TraitField[];
|
|
273
|
+
/**
|
|
274
|
+
* `states[, reversible]: a, b` — trait-declared states (ratchet D8):
|
|
275
|
+
* every composer gets the set; resolution is across the composer's full
|
|
276
|
+
* trait set. Replaces the removed `flag` field type.
|
|
277
|
+
*/
|
|
278
|
+
states: StateName[];
|
|
279
|
+
statesReversible: boolean;
|
|
280
|
+
/** `score <name> worth N` lines — trait-owned scores (D12). */
|
|
281
|
+
scores: ScoreDecl[];
|
|
282
|
+
/** Embedded `phrases <locale>` block, if any. */
|
|
283
|
+
phrases: DefinePhrases | null;
|
|
284
|
+
onClauses: OnClause[];
|
|
285
|
+
span: Span;
|
|
286
|
+
}
|
|
287
|
+
/** One `data` field: `body part: optional name`, `kind: one of a, b, c`. */
|
|
288
|
+
export interface TraitField {
|
|
289
|
+
/** Field name words (`body part`). */
|
|
290
|
+
name: string[];
|
|
291
|
+
/** entity | number | name | one-of. `flag` was removed (given 8 / D8). */
|
|
292
|
+
type: 'entity' | 'number' | 'name' | 'one-of';
|
|
293
|
+
optional: boolean;
|
|
294
|
+
/** `starts <value>` initial, if declared. */
|
|
295
|
+
initial: string | null;
|
|
296
|
+
/** Members when type is 'one-of' (`one of goats, rabbits, parrot, snake`). */
|
|
297
|
+
oneOf: string[] | null;
|
|
298
|
+
span: Span;
|
|
299
|
+
}
|
|
300
|
+
/** `define action <name> … ` — grammar, scope constraints, refusals, body. */
|
|
301
|
+
export interface DefineAction {
|
|
302
|
+
kind: 'define-action';
|
|
303
|
+
/** The action name as written (gerund), e.g. `petting`. */
|
|
304
|
+
name: string;
|
|
305
|
+
/** `grammar` block pattern lines. */
|
|
306
|
+
patterns: ActionPattern[];
|
|
307
|
+
/** `the <slot> must be <requirement>` lines (scope kit, no phrase key). */
|
|
308
|
+
constraints: ScopeConstraint[];
|
|
309
|
+
/** `<subject> must <predicate>: <key>` requirement lines (ratchet D6). */
|
|
310
|
+
musts: MustRequirement[];
|
|
311
|
+
/** `refuse without <slot>: <key>` / `refuse when <cond>: <key>` lines. */
|
|
312
|
+
refusals: ActionRefusal[];
|
|
313
|
+
/** `otherwise refuse <key>` — the dispatch-miss phrase. */
|
|
314
|
+
otherwise: {
|
|
315
|
+
phraseKey: string;
|
|
316
|
+
span: Span;
|
|
317
|
+
} | null;
|
|
318
|
+
/** `score <name> worth N` lines — action-owned scores (D12). */
|
|
319
|
+
scores: ScoreDecl[];
|
|
320
|
+
/** Embedded `phrases <locale>` block, if any. */
|
|
321
|
+
phrases: DefinePhrases | null;
|
|
322
|
+
/** Standard-semantics body statements (design.md §2.3 taking), if any. */
|
|
323
|
+
body: Statement[];
|
|
324
|
+
span: Span;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* `<subject> must <predicate>: <phrase-key>` — a positive requirement
|
|
328
|
+
* (ratchet D6); failing it refuses with the key. The predicate is written
|
|
329
|
+
* in the infinitive (`be hungry`, `have its food`, `hold the camera`) and
|
|
330
|
+
* normalized to the finite Predicate forms at parse.
|
|
331
|
+
* Doubles as a body statement.
|
|
332
|
+
*/
|
|
333
|
+
export interface MustRequirement {
|
|
334
|
+
kind: 'must';
|
|
335
|
+
subject: ValueExpr;
|
|
336
|
+
predicate: Predicate;
|
|
337
|
+
phraseKey: string;
|
|
338
|
+
span: Span;
|
|
339
|
+
}
|
|
340
|
+
/** One grammar-block pattern: words + `:slot`s, optional `→ each …` cardinality. */
|
|
341
|
+
export interface ActionPattern {
|
|
342
|
+
parts: PatternPart[];
|
|
343
|
+
/** Cardinality expansion words after `→` (`each reachable item not already held`). */
|
|
344
|
+
cardinality: string[] | null;
|
|
345
|
+
span: Span;
|
|
346
|
+
}
|
|
347
|
+
/** `the <slot> must be <requirement>` (reachable, visible, held, …). */
|
|
348
|
+
export interface ScopeConstraint {
|
|
349
|
+
slot: string;
|
|
350
|
+
requirement: string;
|
|
351
|
+
span: Span;
|
|
352
|
+
}
|
|
353
|
+
/** `refuse without <slot>: <key>` or `refuse when <condition>: <key>`. */
|
|
354
|
+
export interface ActionRefusal {
|
|
355
|
+
kind: 'without' | 'when';
|
|
356
|
+
/** Slot name for `without`. */
|
|
357
|
+
slot: string | null;
|
|
358
|
+
/** Condition for `when`. */
|
|
359
|
+
condition: ConditionNode | null;
|
|
360
|
+
phraseKey: string;
|
|
361
|
+
span: Span;
|
|
362
|
+
}
|
|
363
|
+
/** `define action X from "./mod.ts"` / `define behavior X from "./mod.ts"` — TS hatches. */
|
|
364
|
+
export interface DefineHatch {
|
|
365
|
+
kind: 'define-hatch';
|
|
366
|
+
hatchKind: 'action' | 'behavior';
|
|
367
|
+
name: string;
|
|
368
|
+
modulePath: string;
|
|
369
|
+
span: Span;
|
|
370
|
+
}
|
|
371
|
+
/** `define sequence <name> … end sequence` — timeline of chained steps. */
|
|
372
|
+
export interface DefineSequence {
|
|
373
|
+
kind: 'define-sequence';
|
|
374
|
+
/** Sequence name words (`closing time`). */
|
|
375
|
+
name: string[];
|
|
376
|
+
steps: SequenceStep[];
|
|
377
|
+
span: Span;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* `at turn <n>` (absolute), `<n> turns later` (relative), or
|
|
381
|
+
* `when <owner> becomes <state>` (state anchor, ratchet D10) step.
|
|
382
|
+
*/
|
|
383
|
+
export interface SequenceStep {
|
|
384
|
+
kind: 'sequence-step';
|
|
385
|
+
timing: 'at-turn' | 'later' | 'becomes';
|
|
386
|
+
/** Turn count for at-turn/later; 0 for becomes. */
|
|
387
|
+
turns: number;
|
|
388
|
+
/** Anchor owner for `becomes` steps (`the story`, an entity). */
|
|
389
|
+
owner: NameRef | null;
|
|
390
|
+
/** Anchor state for `becomes` steps. */
|
|
391
|
+
state: string | null;
|
|
392
|
+
body: Statement[];
|
|
393
|
+
span: Span;
|
|
394
|
+
}
|
|
395
|
+
export type Statement = RefuseStmt | RefuseWhenStmt | PhraseStmt | EmitStmt | SetStmt | ChangeStmt | MoveStmt | RemoveStmt | AwardStmt | WinStmt | LoseStmt | MustRequirement | SelectOnStmt | SelectStrategyStmt | OrdinalBlock | EachStmt;
|
|
396
|
+
/**
|
|
397
|
+
* `each <condition-name> … end each` — body-position iteration block
|
|
398
|
+
* (ratchet E3, 2026-07-12). Hosts: `on`/`after` clause bodies, action
|
|
399
|
+
* bodies, trait clause bodies, sequence steps — never top-level (given 9).
|
|
400
|
+
* Inside the body `the match` is the iterated entity; `it` keeps meaning
|
|
401
|
+
* the clause owner. The open-condition requirement is the analyzer's gate.
|
|
402
|
+
*/
|
|
403
|
+
export interface EachStmt {
|
|
404
|
+
kind: 'each';
|
|
405
|
+
/** The named open condition selecting the matches. */
|
|
406
|
+
condition: string;
|
|
407
|
+
body: Statement[];
|
|
408
|
+
span: Span;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* `refuse when <condition>: <key>` in body position — the prohibition half
|
|
412
|
+
* of decision 6 (requirements are `must`; prohibitions are `refuse when`).
|
|
413
|
+
*/
|
|
414
|
+
export interface RefuseWhenStmt {
|
|
415
|
+
kind: 'refuse-when';
|
|
416
|
+
condition: ConditionNode;
|
|
417
|
+
phraseKey: string;
|
|
418
|
+
span: Span;
|
|
419
|
+
}
|
|
420
|
+
/** `refuse <phrase-key> [with <param> = <value>]…` */
|
|
421
|
+
export interface RefuseStmt {
|
|
422
|
+
kind: 'refuse';
|
|
423
|
+
phraseKey: string;
|
|
424
|
+
params: ParamBinding[];
|
|
425
|
+
span: Span;
|
|
426
|
+
}
|
|
427
|
+
/** `phrase <phrase-key> [with <param> = <value>]… [when <cond>]` (given 6b). */
|
|
428
|
+
export interface PhraseStmt {
|
|
429
|
+
kind: 'phrase';
|
|
430
|
+
phraseKey: string;
|
|
431
|
+
params: ParamBinding[];
|
|
432
|
+
/**
|
|
433
|
+
* Declare-and-emit sugar (design.md §2.6/§3.3): an indented prose block
|
|
434
|
+
* after the statement registers the text under the key at load. Null when
|
|
435
|
+
* the key is declared elsewhere.
|
|
436
|
+
*/
|
|
437
|
+
inlineText: TextValue | null;
|
|
438
|
+
/** Statement `when` suffix (ratchet D7) — execute only if it holds. */
|
|
439
|
+
stmtWhen: ConditionNode | null;
|
|
440
|
+
span: Span;
|
|
441
|
+
}
|
|
442
|
+
/** `with <param> = <value>` binding for refuse/phrase. */
|
|
443
|
+
export interface ParamBinding {
|
|
444
|
+
param: string[];
|
|
445
|
+
value: ValueExpr;
|
|
446
|
+
span: Span;
|
|
447
|
+
}
|
|
448
|
+
/** `emit <event-words> [when <cond>]` */
|
|
449
|
+
export interface EmitStmt {
|
|
450
|
+
kind: 'emit';
|
|
451
|
+
event: string[];
|
|
452
|
+
stmtWhen: ConditionNode | null;
|
|
453
|
+
span: Span;
|
|
454
|
+
}
|
|
455
|
+
/** `set <field-path> to <value>` */
|
|
456
|
+
export interface SetStmt {
|
|
457
|
+
kind: 'set';
|
|
458
|
+
target: ValueExpr;
|
|
459
|
+
value: ValueExpr;
|
|
460
|
+
span: Span;
|
|
461
|
+
}
|
|
462
|
+
/** `change <entity> to <state> [when <cond>]` — explicit state transition. */
|
|
463
|
+
export interface ChangeStmt {
|
|
464
|
+
kind: 'change';
|
|
465
|
+
entity: NameRef;
|
|
466
|
+
state: string;
|
|
467
|
+
stmtWhen: ConditionNode | null;
|
|
468
|
+
span: Span;
|
|
469
|
+
}
|
|
470
|
+
/** `move <entity> to <place> [when <cond>]` */
|
|
471
|
+
export interface MoveStmt {
|
|
472
|
+
kind: 'move';
|
|
473
|
+
entity: NameRef;
|
|
474
|
+
place: NameRef;
|
|
475
|
+
stmtWhen: ConditionNode | null;
|
|
476
|
+
span: Span;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* `remove <entity> [when <cond>]` (Z6, ADR-213 Q3) — takes the entity out of
|
|
480
|
+
* play entirely (`world.removeEntity`; pre-removal observers fire; a
|
|
481
|
+
* witnessed `phrase disappeared:` narrates). Permanent — nothing restores a
|
|
482
|
+
* removed entity. Orphaning is deliberately NOT this statement.
|
|
483
|
+
*/
|
|
484
|
+
export interface RemoveStmt {
|
|
485
|
+
kind: 'remove';
|
|
486
|
+
entity: NameRef;
|
|
487
|
+
stmtWhen: ConditionNode | null;
|
|
488
|
+
span: Span;
|
|
489
|
+
}
|
|
490
|
+
/** `award <quantity-words> [, once] [when <cond>]` */
|
|
491
|
+
export interface AwardStmt {
|
|
492
|
+
kind: 'award';
|
|
493
|
+
expression: string[];
|
|
494
|
+
once: boolean;
|
|
495
|
+
stmtWhen: ConditionNode | null;
|
|
496
|
+
span: Span;
|
|
497
|
+
}
|
|
498
|
+
/** `win [<phrase-key>] [when <cond>]` */
|
|
499
|
+
export interface WinStmt {
|
|
500
|
+
kind: 'win';
|
|
501
|
+
phraseKey: string | null;
|
|
502
|
+
stmtWhen: ConditionNode | null;
|
|
503
|
+
span: Span;
|
|
504
|
+
}
|
|
505
|
+
/** `lose [<phrase-key>] [when <cond>]` */
|
|
506
|
+
export interface LoseStmt {
|
|
507
|
+
kind: 'lose';
|
|
508
|
+
phraseKey: string | null;
|
|
509
|
+
stmtWhen: ConditionNode | null;
|
|
510
|
+
span: Span;
|
|
511
|
+
}
|
|
512
|
+
/** `select on <value> / when <state> … end select` */
|
|
513
|
+
export interface SelectOnStmt {
|
|
514
|
+
kind: 'select-on';
|
|
515
|
+
subject: ValueExpr;
|
|
516
|
+
arms: SelectArm[];
|
|
517
|
+
span: Span;
|
|
518
|
+
}
|
|
519
|
+
export interface SelectArm {
|
|
520
|
+
/** The `when <value>` word. */
|
|
521
|
+
value: string;
|
|
522
|
+
body: Statement[];
|
|
523
|
+
span: Span;
|
|
524
|
+
}
|
|
525
|
+
/** `select <strategy> … or … end select` */
|
|
526
|
+
export interface SelectStrategyStmt {
|
|
527
|
+
kind: 'select-strategy';
|
|
528
|
+
strategy: string;
|
|
529
|
+
alternatives: Statement[][];
|
|
530
|
+
span: Span;
|
|
531
|
+
}
|
|
532
|
+
/** `first time` / `third time` … ordinal block inside a rule (indent-scoped). */
|
|
533
|
+
export interface OrdinalBlock {
|
|
534
|
+
kind: 'ordinal';
|
|
535
|
+
/** 1-based occurrence number the block fires on. */
|
|
536
|
+
ordinal: number;
|
|
537
|
+
/** The ordinal word as written (`first`, `third`). */
|
|
538
|
+
ordinalWord: string;
|
|
539
|
+
body: Statement[];
|
|
540
|
+
span: Span;
|
|
541
|
+
}
|
|
542
|
+
export type ConditionNode = OrNode | AndNode | NotNode | PredicateNode | ChanceNode | NamedConditionRef | AnyOfNode | NoneOfNode;
|
|
543
|
+
/**
|
|
544
|
+
* `any <condition-name>` — existential over a named open condition
|
|
545
|
+
* (ratchet E1, 2026-07-12): true iff some world entity satisfies it;
|
|
546
|
+
* false over the empty set. The open-condition requirement is the
|
|
547
|
+
* analyzer's gate.
|
|
548
|
+
*/
|
|
549
|
+
export interface AnyOfNode {
|
|
550
|
+
kind: 'any-of';
|
|
551
|
+
/** The named open condition doing the filtering. */
|
|
552
|
+
condition: string;
|
|
553
|
+
span: Span;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* `no <condition-name>` — the negated existential, its own positive
|
|
557
|
+
* spelling (ratchet E2, 2026-07-12): true iff no entity satisfies the
|
|
558
|
+
* condition; true over the empty set.
|
|
559
|
+
*/
|
|
560
|
+
export interface NoneOfNode {
|
|
561
|
+
kind: 'none-of';
|
|
562
|
+
/** The named open condition doing the filtering. */
|
|
563
|
+
condition: string;
|
|
564
|
+
span: Span;
|
|
565
|
+
}
|
|
566
|
+
export interface OrNode {
|
|
567
|
+
kind: 'or';
|
|
568
|
+
operands: ConditionNode[];
|
|
569
|
+
span: Span;
|
|
570
|
+
}
|
|
571
|
+
export interface AndNode {
|
|
572
|
+
kind: 'and';
|
|
573
|
+
operands: ConditionNode[];
|
|
574
|
+
span: Span;
|
|
575
|
+
}
|
|
576
|
+
export interface NotNode {
|
|
577
|
+
kind: 'not';
|
|
578
|
+
operand: ConditionNode;
|
|
579
|
+
span: Span;
|
|
580
|
+
}
|
|
581
|
+
/** `one chance in <n>` */
|
|
582
|
+
export interface ChanceNode {
|
|
583
|
+
kind: 'chance';
|
|
584
|
+
n: number;
|
|
585
|
+
span: Span;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* A single-word condition reference (`in-darkness`) — either a named
|
|
589
|
+
* condition or a bare state test; the analyzer decides which.
|
|
590
|
+
*/
|
|
591
|
+
export interface NamedConditionRef {
|
|
592
|
+
kind: 'condition-ref';
|
|
593
|
+
name: string;
|
|
594
|
+
span: Span;
|
|
595
|
+
}
|
|
596
|
+
/** `<subject> <predicate>` — one spelling per predicate (given 7). */
|
|
597
|
+
export interface PredicateNode {
|
|
598
|
+
kind: 'predicate';
|
|
599
|
+
subject: ValueExpr;
|
|
600
|
+
predicate: Predicate;
|
|
601
|
+
span: Span;
|
|
602
|
+
}
|
|
603
|
+
export type Predicate = {
|
|
604
|
+
kind: 'is';
|
|
605
|
+
negated: boolean;
|
|
606
|
+
value: ValueExpr;
|
|
607
|
+
span: Span;
|
|
608
|
+
} | {
|
|
609
|
+
kind: 'is-a';
|
|
610
|
+
negated: boolean;
|
|
611
|
+
classifier: string[];
|
|
612
|
+
span: Span;
|
|
613
|
+
} | {
|
|
614
|
+
kind: 'is-in';
|
|
615
|
+
negated: boolean;
|
|
616
|
+
place: NameRef;
|
|
617
|
+
span: Span;
|
|
618
|
+
}
|
|
619
|
+
/** `<subject> is here` — the Z4 deictic: subject shares the player's location. */
|
|
620
|
+
| {
|
|
621
|
+
kind: 'is-here';
|
|
622
|
+
negated: boolean;
|
|
623
|
+
span: Span;
|
|
624
|
+
} | {
|
|
625
|
+
kind: 'holds';
|
|
626
|
+
thing: NameRef;
|
|
627
|
+
span: Span;
|
|
628
|
+
} | {
|
|
629
|
+
kind: 'has';
|
|
630
|
+
thing: NameRef;
|
|
631
|
+
span: Span;
|
|
632
|
+
} | {
|
|
633
|
+
kind: 'wears';
|
|
634
|
+
thing: NameRef;
|
|
635
|
+
span: Span;
|
|
636
|
+
}
|
|
637
|
+
/** `can see <thing>` / `can reach <thing>` (design.md §2.7; Phase B). */
|
|
638
|
+
| {
|
|
639
|
+
kind: 'can';
|
|
640
|
+
ability: string;
|
|
641
|
+
thing: NameRef;
|
|
642
|
+
span: Span;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* `must be any <open-condition>` membership (David, 2026-07-12 — each
|
|
646
|
+
* package P3): the subject satisfies the named open condition. Parsed
|
|
647
|
+
* only in the `must` infinitive-predicate position, never in ordinary
|
|
648
|
+
* condition predicates.
|
|
649
|
+
*/
|
|
650
|
+
| {
|
|
651
|
+
kind: 'is-any';
|
|
652
|
+
condition: string;
|
|
653
|
+
span: Span;
|
|
654
|
+
};
|
|
655
|
+
/**
|
|
656
|
+
* A value position: a name reference, possessive chain, literal, bare word,
|
|
657
|
+
* or the `each`-block binder `the match` (ratchet E3, 2026-07-12).
|
|
658
|
+
* `its state` parses as possessive with subject `it`. In NameRef positions
|
|
659
|
+
* (`change`/`move` targets) `the match` stays a name reference — resolved
|
|
660
|
+
* to the binder at analysis, exactly as `it` is.
|
|
661
|
+
*/
|
|
662
|
+
export type ValueExpr = {
|
|
663
|
+
kind: 'ref';
|
|
664
|
+
ref: NameRef;
|
|
665
|
+
span: Span;
|
|
666
|
+
} | {
|
|
667
|
+
kind: 'possessive';
|
|
668
|
+
base: ValueExpr;
|
|
669
|
+
field: string[];
|
|
670
|
+
span: Span;
|
|
671
|
+
} | {
|
|
672
|
+
kind: 'literal';
|
|
673
|
+
value: string;
|
|
674
|
+
literalKind: 'number' | 'string';
|
|
675
|
+
span: Span;
|
|
676
|
+
} | {
|
|
677
|
+
kind: 'bare';
|
|
678
|
+
words: string[];
|
|
679
|
+
span: Span;
|
|
680
|
+
} | {
|
|
681
|
+
kind: 'match';
|
|
682
|
+
span: Span;
|
|
683
|
+
};
|
|
684
|
+
//# sourceMappingURL=ast.d.ts.map
|