@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/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