zyn 0.5.2

A proc macro framework with templates, composable elements, and built-in diagnostics
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# Roadmap: Toward a Cohesive Macro SDK

- [Guiding Principles]#guiding-principles
  - [1. The user should think in terms of zyn, not syn or quote]#1-the-user-should-think-in-terms-of-zyn-not-syn-or-quote
  - [2. Parsing, building, and diagnostics must feel like one system]#2-parsing-building-and-diagnostics-must-feel-like-one-system
  - [3. Templates are a tool, not the foundation]#3-templates-are-a-tool-not-the-foundation
  - [4. Diagnostics must be first-class]#4-diagnostics-must-be-first-class
  - [5. Incremental adoption is essential]#5-incremental-adoption-is-essential
- [Roadmap]#roadmap
  - [Phase 1 โ€” ๐ŸŽฏ Formalize the product thesis]#phase-1---formalize-the-product-thesis--in-progress
  - [Phase 2 โ€” ๐Ÿงฑ Define the stable zyn surface area]#phase-2---define-the-stable-zyn-surface-area--in-progress
  - [Phase 3 โ€” ๐Ÿ—‚๏ธ Restructure the workspace around capabilities]#phase-3---restructure-the-workspace-around-capabilities--in-progress
  - [Phase 4 โ€” ๐Ÿฉบ Build a first-class diagnostics subsystem]#phase-4---build-a-first-class-diagnostics-subsystem--in-progress
  - [Phase 5 โ€” ๐Ÿงช Expand testing into a full macro QA system]#phase-5---expand-testing-into-a-full-macro-qa-system--in-progress
  - [Phase 6 โ€” ๐Ÿ”จ Introduce structured builders]#phase-6---introduce-structured-builders--in-progress
  - [Phase 7 โ€” ๐ŸชŸ Introduce a zyn syntax facade]#phase-7---introduce-a-zyn-syntax-facade--not-started
  - [Phase 8 โ€” ๐Ÿงญ Introduce context-driven macro APIs]#phase-8---introduce-context-driven-macro-apis--not-started
  - [Phase 9 โ€” ๐Ÿšš Build the migration path]#phase-9---build-the-migration-path--not-started
  - [Phase 10 โ€” ๐Ÿถ Dogfood the framework internally]#phase-10---dogfood-the-framework-internally--not-started
  - [Phase 11 โ€” ๐Ÿ”ฌ Evaluate internal dependency replacement]#phase-11---evaluate-internal-dependency-replacement--not-started
- [Long-Term Outcome]#long-term-outcome

When I started **zyn**, my goal was not simply to build a nicer templating system for Rust procedural macros. The real goal is much larger:

> **Zyn should become the cohesive macro SDK for Rust.**

Today, Rust macro development is powerful but fragmented. The typical stack looks like this:

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#fabd2f', 'primaryTextColor': '#282828', 'primaryBorderColor': '#d79921', 'lineColor': '#83a598', 'secondaryColor': '#3c3836', 'background': '#282828', 'nodeBorder': '#504945', 'textColor': '#ebdbb2'}}}%%
graph TD
    classDef hub fill:#fabd2f,color:#282828,stroke:#d79921,font-weight:bold
    classDef leaf fill:#3c3836,color:#ebdbb2,stroke:#504945

    A[proc_macro] --> B[proc_macro2]
    B --> C[syn]
    B --> D[quote]
    B --> E[proc_macro2_diagnostics]
    B --> F[prettyplease]
    G[trybuild]
    H[cargo-expand]

    class B hub
    class A,C,D,E,F,G,H leaf
```

Each of these tools solves a specific problem well, but together they create a developer experience that feels **stitched together rather than designed**.

Zyn exists to unify that experience.

The long-term goal is to provide a **single coherent framework** that handles:

* macro entrypoints
* parsing
* syntax inspection
* code construction
* diagnostics
* testing
* debugging
* expansion tooling

Importantly, this does **not** require replacing the entire ecosystem immediately. In the near term, zyn may still rely on `syn` and `quote` internally. But those crates should become **implementation details**, not the mental model macro authors must learn.

My strategy is therefore **progressive capture**:

1. own the authoring experience
2. wrap the existing ecosystem behind zyn abstractions
3. gradually replace internal dependencies where it makes sense

---

# Guiding Principles

Before outlining the roadmap, these principles guide every design decision.

### 1. The user should think in terms of zyn, not syn or quote

If writing a zyn macro still requires constantly thinking about:

* `syn::Type`
* `proc_macro2::TokenStream`
* `quote!`
* diagnostics compatibility caveats

then zyn has not truly unified the macro experience.

Zyn should provide its own conceptual model.

---

### 2. Parsing, building, and diagnostics must feel like one system

Today these areas are fragmented across multiple crates.

In zyn they should feel like **parts of a single pipeline**:

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#fabd2f', 'primaryTextColor': '#282828', 'primaryBorderColor': '#d79921', 'lineColor': '#83a598', 'background': '#282828', 'textColor': '#ebdbb2'}}}%%
flowchart LR
    classDef step fill:#fabd2f,color:#282828,stroke:#d79921,font-weight:bold

    Parse --> Inspect --> Transform --> Emit --> Test

    class Parse,Inspect,Transform,Emit,Test step
```

---

### 3. Templates are a tool, not the foundation

The `zyn!` template system is an important ergonomic feature and adoption wedge. However, the long-term architecture should prioritize:

* structured builders
* composable components
* reusable transformations

Templates should exist as **ergonomic sugar**, not the only abstraction.

---

### 4. Diagnostics must be first-class

A macro framework should make it easy to produce **compiler-quality diagnostics**, including:

* labels
* notes
* help messages
* suggestions
* structured spans

Diagnostics should work consistently in:

* proc macro contexts
* tests
* debugging environments

---

### 5. Incremental adoption is essential

Most macro authors already have existing code using `syn` and `quote`. Zyn should make it possible to adopt the framework **incrementally**, without rewriting entire macro crates.

Compatibility layers and migration guides are therefore a core part of the roadmap.

---

# Roadmap

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#fabd2f', 'primaryTextColor': '#282828', 'primaryBorderColor': '#d79921', 'lineColor': '#83a598', 'background': '#282828', 'cScale0': '#fabd2f', 'cScale1': '#3c3836', 'titleColor': '#ebdbb2'}}}%%
timeline
    title zyn Roadmap
    section ๐Ÿ”„ In Progress
        Phase 1 : Formalize product thesis
        Phase 2 : Stable surface area
        Phase 3 : Workspace restructure
        Phase 4 : Diagnostics subsystem
        Phase 5 : Macro QA system
        Phase 6 : Structured builders
    section โฌœ Not Started
        Phase 7 : Syntax facade
        Phase 8 : Context-driven APIs
        Phase 9 : Migration path
        Phase 10 : Dogfood internally
        Phase 11 : Dependency replacement
```

## Phase 1 โ€” ๐ŸŽฏ Formalize the product thesis `๐Ÿ”„ In Progress`

The first step is to explicitly define what zyn is.

Zyn is not simply a templating crate. It is intended to be a **macro SDK**.

The repository should include a clear design document that defines:

* the long-term vision
* the scope of the framework
* the architectural principles
* explicit non-goals

This prevents feature drift and clarifies the project's direction.

### โœ… Exit Criteria

- [ ] a canonical design document exists
- [ ] non-goals are clearly documented
- [ ] internal dependencies (`syn`, `quote`, etc.) are explicitly treated as implementation details

---

## Phase 2 โ€” ๐Ÿงฑ Define the stable zyn surface area `๐Ÿ”„ In Progress`

Before replacing internals, I need to define the **public conceptual model** that macro authors interact with.

This means introducing zyn-owned types such as:

```
zyn::Tokens
zyn::Span
zyn::Diagnostic
zyn::Ast<T>
zyn::Result<T>
```

These types wrap the existing ecosystem primitives but provide a stable surface for users.

Initially these may simply delegate to `proc_macro2`, `syn`, and `quote`, but over time they will allow the framework to evolve independently of those crates.

### โœ… Exit Criteria

- [ ] zyn exposes its own wrapper types
- [ ] examples prefer zyn abstractions over raw ecosystem types
- [ ] `syn` re-exports remain available but are clearly positioned as compatibility APIs

---

## Phase 3 โ€” ๐Ÿ—‚๏ธ Restructure the workspace around capabilities `๐Ÿ”„ In Progress`

Currently the project contains:

```
zyn
zyn-core
zyn-derive
```

As the framework grows, the workspace should instead reflect **capabilities** rather than current implementation details.

Target structure:

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#fabd2f', 'primaryTextColor': '#282828', 'primaryBorderColor': '#d79921', 'lineColor': '#83a598', 'background': '#282828', 'nodeBorder': '#504945', 'textColor': '#ebdbb2'}}}%%
graph TD
    classDef root fill:#fabd2f,color:#282828,stroke:#d79921,font-weight:bold
    classDef crate fill:#3c3836,color:#ebdbb2,stroke:#504945
    classDef compat fill:#32302f,color:#928374,stroke:#504945

    zyn --> zyn-macro
    zyn --> zyn-syntax
    zyn --> zyn-build
    zyn --> zyn-template
    zyn --> zyn-diag
    zyn --> zyn-test
    zyn-syntax --> zyn-compat-syn
    zyn-build --> zyn-compat-quote

    class zyn root
    class zyn-macro,zyn-syntax,zyn-build,zyn-template,zyn-diag,zyn-test crate
    class zyn-compat-syn,zyn-compat-quote compat
```

This forces all dependencies on `syn` and `quote` to pass through clearly defined compatibility layers.

### โœ… Exit Criteria

- [ ] direct usage of `syn` or `quote` is isolated
- [ ] public documentation focuses on framework capabilities rather than underlying crates

---

## Phase 4 โ€” ๐Ÿฉบ Build a first-class diagnostics subsystem `๐Ÿ”„ In Progress`

Diagnostics are one of the fastest ways to make macro development feel more professional.

Zyn already provides diagnostic macros like `error!`, `warn!`, `note!`, and `help!`. These should evolve into a complete diagnostics subsystem.

The system should support:

* structured diagnostics
* labeled spans
* notes and help text
* accumulation of multiple diagnostics
* rendering in multiple environments

Backends may include:

* proc macro emission
* test snapshot rendering
* debugging output

### โœ… Exit Criteria

- [ ] diagnostics can be constructed without macros
- [ ] diagnostics can be snapshot tested
- [ ] backend implementations are internal details

---

## Phase 5 โ€” ๐Ÿงช Expand testing into a full macro QA system `๐Ÿ”„ In Progress`

Testing macro output today typically involves ad-hoc combinations of tools.

Zyn should provide a unified testing system supporting:

* expansion snapshots
* diagnostic snapshots
* structured AST assertions
* compile-fail tests
* golden-file comparisons

### โœ… Exit Criteria

- [ ] zyn includes a dedicated testing crate
- [ ] examples demonstrate snapshot testing
- [ ] macro refactors can be validated through stable tests

---

## Phase 6 โ€” ๐Ÿ”จ Introduce structured builders `๐Ÿ”„ In Progress`

At this stage, the framework should provide APIs for constructing Rust syntax programmatically.

Examples:

```
Item::impl_block(...)
Method::new(...)
Field::new(...)
Expr::call(...)
Path::from_segments(...)
```

Templates (`zyn!`) should remain available but should compile into or interoperate with these structured representations.

### โœ… Exit Criteria

- [ ] complex macros can be implemented without templates
- [ ] builders and templates compose naturally
- [ ] documentation encourages builders for reusable transformations

---

## Phase 7 โ€” ๐ŸชŸ Introduce a zyn syntax facade `โฌœ Not Started`

Replacing `syn` entirely would be extremely expensive and unnecessary.

Instead, I plan to introduce a **thin syntax facade** that covers the subset of Rust syntax most macro authors work with.

Initially this facade will delegate to `syn`. Over time it may diverge where appropriate.

### โœ… Exit Criteria

- [ ] macro inputs can be represented using zyn syntax types
- [ ] most examples no longer require direct use of `syn`
- [ ] conversion layers exist between zyn syntax and `syn`

---

## Phase 8 โ€” ๐Ÿงญ Introduce context-driven macro APIs `โฌœ Not Started`

Zyn currently supports extractors for macro inputs.

The next step is to introduce explicit context objects:

```
MacroContext
DeriveContext
AttributeContext
FunctionContext
```

These contexts provide structured access to macro inputs while extractors remain available as ergonomic sugar.

### โœ… Exit Criteria

- [ ] each macro type has a context object
- [ ] advanced documentation focuses on context-based APIs
- [ ] extractors remain optional

---

## Phase 9 โ€” ๐Ÿšš Build the migration path `โฌœ Not Started`

Adoption requires a clear migration story.

The project should provide guides such as:

* migrating from `quote!` to `zyn!`
* migrating `syn` parsing patterns to zyn syntax
* incremental adoption strategies

Compatibility traits and conversions should make it easy to interoperate with existing code.

### โœ… Exit Criteria

- [ ] comprehensive migration guides exist
- [ ] compatibility layers are documented and stable

---

## Phase 10 โ€” ๐Ÿถ Dogfood the framework internally `โฌœ Not Started`

Once the abstractions exist, the zyn codebase should begin using them extensively.

Key components to migrate include:

* pipes
* attribute parsing
* macro entrypoints
* debugging tools
* documentation examples

### โœ… Exit Criteria

- [ ] most internal macro logic uses zyn abstractions
- [ ] direct usage of `quote!` becomes rare
- [ ] `syn` usage is isolated to parser/compat modules

---

## Phase 11 โ€” ๐Ÿ”ฌ Evaluate internal dependency replacement `โฌœ Not Started`

Only after the previous phases are complete does it make sense to consider replacing internal dependencies.

At this point it may be possible to:

* replace parts of `quote`
* implement custom emitters
* develop alternative parsing strategies

However, these decisions should be driven by clear benefits rather than ideology.

The primary goal is to ensure that **users of zyn never need to care about the underlying implementation**.

---

# Long-Term Outcome

If this roadmap succeeds, zyn will evolve from a templating system into a **true macro development platform**.

Instead of learning a patchwork of tools, macro authors will work within a single coherent framework:

```mermaid
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#fabd2f', 'primaryTextColor': '#282828', 'primaryBorderColor': '#d79921', 'lineColor': '#83a598', 'background': '#282828', 'textColor': '#ebdbb2'}}}%%
mindmap
  root((zyn))
    Syntax Inspection
    Code Generation
    First-class Diagnostics
    Testing & Debugging
```

In other words, the experience of writing macros in Rust will feel like using a **designed system rather than an ecosystem workaround**.

That is the long-term goal of this project.