P3 Engineers P4 Technical Investors

The Technical Moat

Three layers of defensibility that compound over time.

Architecture of Defensibility

Three Concentric Moats

Each layer protects the next. Together they create compounding advantages that a competitor cannot replicate incrementally.

Layer 1 — The Foundation

AG as Pure Data: The Core Insight

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.

Validatable

The AG can be checked for errors by another AG. Self-hosting becomes possible because grammars are just trees.

Serializable

Save, send, and version control AG definitions. No opaque closures or class hierarchies to worry about.

Transformable

Write tools that analyze and transform AGs programmatically. Meta-tooling on top of tooling.

Composable

Merge, extend, and subset AG definitions like data. Composition is just tree manipulation.

Compilable

Pure data IR enables compilation to optimized evaluators. No reflection hacks — the compiler sees everything.

Traditional Approach

AG as Code / Classes

  • Opaque — can't inspect at runtime
  • Can't validate one AG with another
  • Closures prevent serialization
  • Composition requires inheritance hacks
  • Compilation requires reflection or codegen
This Framework

AG as AST (Pure Data)

  • Transparent — fully inspectable tree
  • Validated by a self-hosted AG
  • Serializable — save, send, version
  • Composition is tree manipulation
  • Compilation reads the IR directly
AG Tree Structure
AGRoot | +-- AttrDecl { name: "type", direction: "syn" } | +-- NtRef { name: "Expr" } | +-- ProdEq { kind: "BinaryExpr" } | +-- SynEq { attrName: "type" } | | +-- body: BinaryExpr(ChildSynExpr(...), ...) | +-- ChildInhEq { childName: "left", attrName: "env" } | +-- DefaultEq { attrName: "type" }

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.

Layer 2 — The Quality Flywheel

Self-Hosting: The Validator Is an AG

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.

AG Framework Core engine Validator AG Built with the framework User AGs Your grammars builds validates validates itself Improvements to framework improve validation, which catches more bugs The Quality Flywheel
What the Validator Checks
C

Completeness

Missing equations detection

Every declared attribute must have equations for all relevant productions. If you declare a type attribute on Expr nodes, the validator ensures every Expr production (BinaryExpr, CallExpr, LiteralExpr, ...) has a corresponding equation. Missing one? Caught at definition time, not at runtime.

M

MWDA

Well-definedness analysis

The Modified Well-Definedness Analysis ensures no attribute depends on itself through an unresolvable dependency path. MWDA is a stronger guarantee than simple cycle detection — it proves that for any possible input tree, evaluation will terminate and produce a unique result.

D

Cycle Detection

Circular dependency identification

Identifies circular dependencies in attribute equations — cases where attribute A depends on B which depends on C which depends on A. These would cause infinite loops at evaluation time. The validator catches them statically, before any tree is ever evaluated.

F

Flow-Type Inference

List-child attribute flow

Infers how inherited attributes flow through list children. When a list child's inherited attribute depends on a sibling's synthesized attribute, the validator determines the correct evaluation order — left-to-right, right-to-left, or broadcast — and flags conflicts automatically.

G

Grammar Validation

Target grammar conformance

Checks that equation references match the target grammar. If your AG references a child named "left" on a node kind that doesn't have that child, or references an attribute that doesn't exist, the validator catches it. Typos in attribute names become compile-time errors, not silent bugs.

  • Self-hosting is the gold standard in language tooling. A compiler that compiles itself proves it works. The validator validating itself proves the framework is expressive enough for real, complex grammars.
  • Catches bugs at definition time, not runtime. Mistyped attribute names, missing equations, circular dependencies — all caught before a single user tree is ever evaluated.
  • Creates a quality flywheel. Every improvement to the framework immediately improves the validator. Better validation catches more bugs. Fewer bugs increase confidence. Higher confidence enables more ambitious grammars.
Layer 3 — The Performance Moat

The Compiled Evaluator (Futamura Projection)

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.

Pipeline 1 — Lazy (Dev)

Thunk-based, on-demand attribute evaluation. Cycle detection built in. Best for development and debugging.

AG Definition

Pure data tree

compileAG()

Index equations

decorate()

Lazy thunk proxy

node.type

Computed on access

Pipeline 2 — Compiled (Production)

Generates a single JS function with a switch over all node kinds. Topologically sorted. Near hand-written performance.

AG Definition

Pure data tree

compileEvaluator()

Emit JS function

Single Switch

Topo-sorted code

evaluate(tree)

All attrs at once

Key Compilation Techniques
T

Topological Sort

Dependency-ordered computation

Attributes within each production are dependency-ordered via extractLocalSynDeps() plus topological sort. The generated code computes each attribute exactly once, in exactly the right order. No wasted re-computation, no dependency tracking overhead at runtime.

2

Two-Phase Visit

Sibling-dependent list children

For list-child productions where child-inherited equations read sibling-synthesized attributes, children are visited twice. Phase 1 computes sibling-independent attributes. Phase 2 feeds sibling results back. This handles patterns like "each statement's environment is the previous statement's output environment."

I

Inert-Kind Optimization

Phase 2 skip for unaffected subtrees

Subtrees that don't read sibling-dependent attributes skip Phase 2 entirely. computeInertKinds() statically determines which node kinds are "inert" with respect to sibling dependencies. This avoids unnecessary re-traversal of large subtrees — a significant performance win on real-world trees.

P

Per-Child Sibling-Dep

Index-varying equations in loops

If a sibling-dependent equation also varies by child index (via ProvChildIdxExpr), it's computed inside the Phase 2 loop rather than hoisted outside. This handles patterns where the inherited attribute for child i depends on both sibling results and the child's position in the list.

Relative Performance (Lower = Faster)
Hand-written visitor
100%
Compiled AG evaluator
~120%
Lazy AG evaluator
~400%
Interpreted AG
~1000%+

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.

Layer 4 — The Network Effect

Ecosystem & Switching Cost

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.

Composable Grammars

extendSyntax lets you build on existing grammars without forking. Your TypeScript grammar + AG primitives = full authoring syntax. No copy-paste, no divergence.

Cross-Team Reuse

The syntax composition model (defineSyntax, extendSyntax, subsetSyntax) means grammars can be shared and composed across teams and organizations.

Published Grammar Ecosystem

Published AstSyntax definitions are reusable. AGs compose on top of grammars. Each new grammar/AG increases the value for everyone in the ecosystem.

Deep Integration Lock-in

Parsers, validators, evaluators, and meta-tools all build on the same tree abstraction. Switching means rewriting everything, not just one layer.

Strategic Analysis

The Competitor's Dilemma

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.

  1. 1
    Deep AG Theory Expertise MWDA, flow-type inference, topological evaluation ordering — this is decades-old theory that very few engineers have working knowledge of. Not something you pick up in a sprint.
  2. 2
    Pure-Data IR Architecture A fundamental design decision made at day zero. It cannot be bolted onto an existing class-based or closure-based AG system after the fact. It shapes every API surface.
  3. 3
    Self-Hosted Validation Requires the framework to already be expressive enough to build complex AGs. You need a working framework before you can self-host. Chicken-and-egg, solved only by sustained R&D.
  4. 4
    Compiled Evaluator Topological sort, two-phase visits, inert-kind optimization, per-child sibling deps — each is a research-level problem. Together they produce hand-written-competitive performance.
  5. 5
    Composable Syntax Model defineSyntax / extendSyntax / subsetSyntax is architectural, not a feature flag. It requires the tree representation, type system, and tooling to all agree on a composition protocol.

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.

Head-to-Head

Competitive Comparison

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