Skip to content

Commit 245c304

Browse files
authored
docs: More ADR-0003 updates (#106)
1 parent 87c188b commit 245c304

3 files changed

Lines changed: 38 additions & 20 deletions

File tree

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Plotnik extends Tree-sitter's query syntax with:
126126
- **Named expressions** for composition and reuse
127127
- **Recursion** for arbitrarily nested structures
128128
- **Type annotations** for precise output shapes
129-
- **Tagged alternations** for discriminated unions
129+
- **Alternations**: untagged for simplicity, tagged for precision (discriminated unions)
130130

131131
## Use cases
132132

@@ -161,12 +161,12 @@ This produces:
161161

162162
```typescript
163163
type Statement =
164-
| { tag: "Assign"; target: string; value: Expression }
165-
| { tag: "Call"; func: string; args: Expression[] };
164+
| { $tag: "Assign"; $data: { target: string; value: Expression } }
165+
| { $tag: "Call"; $data: { func: string; args: Expression[] } };
166166

167167
type Expression =
168-
| { tag: "Ident"; name: string }
169-
| { tag: "Num"; value: string };
168+
| { $tag: "Ident"; $data: { name: string } }
169+
| { $tag: "Num"; $data: { value: string } };
170170

171171
type TopDefinitions = {
172172
statements: [Statement, ...Statement[]];
@@ -177,12 +177,12 @@ Then process the results:
177177

178178
```typescript
179179
for (const stmt of result.statements) {
180-
switch (stmt.tag) {
180+
switch (stmt.$tag) {
181181
case "Assign":
182-
console.log(`Assignment to ${stmt.target}`);
182+
console.log(`Assignment to ${stmt.$data.target}`);
183183
break;
184184
case "Call":
185-
console.log(`Call to ${stmt.func} with ${stmt.args.length} args`);
185+
console.log(`Call to ${stmt.$data.func} with ${stmt.$data.args.length} args`);
186186
break;
187187
}
188188
}

docs/REFERENCE.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,9 @@ interface Section {
492492

493493
Match one of several alternatives with `[...]`:
494494

495+
- **Untagged** (no labels): Simpler output, fields merge. Use when you only need the captured data.
496+
- **Tagged** (with labels): Precise discriminated union. Use when you need to know which branch matched.
497+
495498
```
496499
[
497500
(identifier)
@@ -589,10 +592,12 @@ Labels create a discriminated union:
589592
] @stmt :: Stmt
590593
```
591594

592-
Output type (discriminant is always `tag`):
595+
Output type (discriminant is always `$tag`, payload in `$data`):
593596

594597
```typescript
595-
type Stmt = { tag: "Assign"; left: Node } | { tag: "Call"; func: Node };
598+
type Stmt =
599+
| { $tag: "Assign"; $data: { left: Node } }
600+
| { $tag: "Call"; $data: { func: Node } };
596601
```
597602

598603
In Rust, tagged alternations become enums:
@@ -754,8 +759,8 @@ Output type:
754759

755760
```typescript
756761
type MemberChain =
757-
| { tag: "Base"; name: Node }
758-
| { tag: "Access"; object: MemberChain; property: Node };
762+
| { $tag: "Base"; $data: { name: Node } }
763+
| { $tag: "Access"; $data: { object: MemberChain; property: Node } };
759764
```
760765

761766
---
@@ -787,14 +792,14 @@ Output types:
787792

788793
```typescript
789794
type Statement =
790-
| { tag: "Assign"; target: string; value: Expression }
791-
| { tag: "Call"; func: string; args: Expression[] }
792-
| { tag: "Return"; value?: Expression };
795+
| { $tag: "Assign"; $data: { target: string; value: Expression } }
796+
| { $tag: "Call"; $data: { func: string; args: Expression[] } }
797+
| { $tag: "Return"; $data: { value?: Expression } };
793798

794799
type Expression =
795-
| { tag: "Ident"; name: string }
796-
| { tag: "Num"; value: string }
797-
| { tag: "Str"; value: string };
800+
| { $tag: "Ident"; $data: { name: string } }
801+
| { $tag: "Num"; $data: { value: string } }
802+
| { $tag: "Str"; $data: { value: string } };
798803

799804
type Root = {
800805
statements: [Statement, ...Statement[]];

docs/adr/ADR-0003-query-intermediate-representation.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,19 @@ EndObject
351351
EndVariant
352352
```
353353

354-
The resulting `Value::Variant` preserves the tag distinct from the payload, preventing name collisions. When serialized to JSON, it flattens to match the documented data model: `{ tag: "A", ...payload }`.
354+
The resulting `Value::Variant` preserves the tag distinct from the payload, preventing name collisions.
355+
356+
**JSON serialization** always uses `$data` wrapper for uniformity:
357+
358+
```json
359+
{ "$tag": "A", "$data": { "x": 1, "y": 2 } }
360+
{ "$tag": "B", "$data": [1, 2, 3] }
361+
{ "$tag": "C", "$data": "foo" }
362+
```
363+
364+
The `$tag` and `$data` keys avoid collisions with user-defined captures. Uniform structure simplifies parsing (always access `.$data`) and eliminates conditional flatten-vs-wrap logic.
365+
366+
This mirrors Rust's serde adjacently-tagged representation and remains fully readable for LLMs. No query validation restriction—all payload types are valid.
355367

356368
**Constraint: branches must produce objects.** Top-level quantifiers in tagged branches are disallowed:
357369

@@ -430,7 +442,7 @@ struct Interpreter<'a> {
430442

431443
After initial construction, epsilon transitions can be eliminated by computing epsilon closures. The `pre_effects`/`post_effects` split is essential for correctness here.
432444

433-
**Why the split matters**: A match transition overwrites `current` with the matched node. Effects from *preceding* epsilon transitions (like `PushElement`) need the *previous* `current` value. Without the split, merging them into a single post-match list would use the wrong value.
445+
**Why the split matters**: A match transition overwrites `current` with the matched node. Effects from _preceding_ epsilon transitions (like `PushElement`) need the _previous_ `current` value. Without the split, merging them into a single post-match list would use the wrong value.
434446

435447
```
436448
Before (raw graph):
@@ -446,6 +458,7 @@ T3': Match(B) + [PushElement] // PushElement runs after Match(
446458
```
447459

448460
**Accumulation rules**:
461+
449462
- Effects from incoming epsilon paths → accumulate into `pre_effects`
450463
- Effects from outgoing epsilon paths → accumulate into `post_effects`
451464

0 commit comments

Comments
 (0)