Three layers of defensibility that compound over time.
Each layer protects the next. Together they create compounding advantages that a competitor cannot replicate incrementally.
Most AG systems represent grammars as classes, objects, or code-generated artifacts. This framework represents the AG itself as an AST — pure data, no closures, serializable. This single architectural decision enables everything else.
The AG can be checked for errors by another AG. Self-hosting becomes possible because grammars are just trees.
Save, send, and version control AG definitions. No opaque closures or class hierarchies to worry about.
Write tools that analyze and transform AGs programmatically. Meta-tooling on top of tooling.
Merge, extend, and subset AG definitions like data. Composition is just tree manipulation.
Pure data IR enables compilation to optimized evaluators. No reflection hacks — the compiler sees everything.
Because the AG is a tree, every tool you build for trees works on AGs. The framework eats its own dog food at every level. This isn't a feature — it's a fundamental architectural decision that cannot be bolted onto an existing system after the fact.
The validator that checks AGs for correctness is itself an attribute grammar. Self-hosting is the gold standard in language tooling — a compiler that compiles itself proves it works.
The framework doesn't just interpret AGs — it compiles them into optimized JavaScript functions. This is the second Futamura projection applied to attribute grammars: specializing the evaluator with respect to a fixed AG yields a standalone, near-hand-written evaluator.
Thunk-based, on-demand attribute evaluation. Cycle detection built in. Best for development and debugging.
Pure data tree
Index equations
Lazy thunk proxy
Computed on access
Generates a single JS function with a switch over all node kinds. Topologically sorted. Near hand-written performance.
Pure data tree
Emit JS function
Topo-sorted code
All attrs at once
Compilation is hard. Getting the topological sort, two-phase visit, and inert-kind optimization right took significant R&D. An 80% competitor can build a lazy evaluator — building a compiled one that matches hand-written performance is a different league entirely.
Composable grammars are network-effect goods. Each new grammar and AG increases the value of every other grammar in the ecosystem. Once a team's tooling is built on this framework, switching cost is like switching databases.
extendSyntax lets you build on existing grammars without forking. Your TypeScript grammar + AG primitives = full authoring syntax. No copy-paste, no divergence.
The syntax composition model (defineSyntax, extendSyntax, subsetSyntax) means grammars can be shared and composed across teams and organizations.
Published AstSyntax definitions are reusable. AGs compose on top of grammars. Each new grammar/AG increases the value for everyone in the ecosystem.
Parsers, validators, evaluators, and meta-tools all build on the same tree abstraction. Switching means rewriting everything, not just one layer.
To match this framework, a competitor would need all of the following — and they compound. This isn't a feature checklist. It's an architecture. You can't get here incrementally from a simpler starting point.
Each layer depends on the ones below it. You can't self-host without pure-data IR. You can't compile without well-defined AG theory. You can't build an ecosystem without composition. A competitor starting today faces the same multi-year R&D curve — and this framework is already shipping.
Moat dimensions compared across AG systems and the hand-written alternative.
| This Framework | JastAdd | Silver | Kiama | Hand-written | |
|---|---|---|---|---|---|
| Pure data IR | Yes | No | No | No | No |
| Self-hosted validation | Yes | No | No | No | No |
| Compiled evaluator | Yes | Yes | No | No | N/A |
| Composable grammars | Yes | Limited | Yes | No | No |
| TypeScript-native | Yes | No | No | No | Varies |
| Ecosystem lock-in potential | High | Medium | Low | Low | None |