Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
25a8b4b
Add IR emitters
wilmveel Feb 11, 2026
0546b8d
Remove parallel test execution configuration
wilmveel Feb 20, 2026
924f5f7
Ir emitters
wilmveel Feb 23, 2026
8285a8f
Ir emitters
wilmveel Feb 23, 2026
6806427
Add `Reflect` type support across IR emitters and generators
wilmveel Feb 23, 2026
dee2763
Update `Reflect` type handling in Python generator to use generic `ty…
wilmveel Feb 23, 2026
7f3f7dc
Update `Reflect` type handling in TypeScript generator to use `Type`
wilmveel Feb 23, 2026
e8d21e2
Add integration test for rust-petstore and refactor to shared lib
wilmveel Feb 24, 2026
1952f6d
Refactor Transform DSL and update all IR emitters
wilmveel Feb 24, 2026
e5e02af
Fix example
wilmveel Feb 25, 2026
689a4be
Add Scala ZIO example with Circe serialization, HTTP client, and tests
wilmveel Feb 26, 2026
71a2bd8
Add ZIO-based Guru API Server and Tests
wilmveel Feb 26, 2026
fbc1238
Fix rust-petstore example to match updated generated code
wilmveel Feb 26, 2026
1e71482
Remove parent `examples` POM, update Maven submodule dependencies, an…
wilmveel Feb 26, 2026
72d4394
Add comprehensive tests for `Name` operations and update Scala, Kotli…
wilmveel Feb 26, 2026
827a631
Update script for platform-specific CLI binary build and fix IR file …
wilmveel Feb 26, 2026
ab0455e
Remove unused endpoint implementations from Rust Petstore example
wilmveel Feb 27, 2026
7ae1dde
Remove `serde` attributes and simplify derives in Rust IR emitter tests
wilmveel Feb 27, 2026
de27932
Enhance Rust serialization and deserialization logic in `MockSer` to …
wilmveel Mar 1, 2026
4a2c0b0
Refactor emitters to use IR DSL for shared interfaces and extract com…
wilmveel Mar 1, 2026
7d54b34
Refactor IrEmitters to idiomatic Kotlin with statementAndExpression h…
wilmveel Mar 1, 2026
55d7dd4
Refactor TypeScriptGenerator and Restructure logic for improved reada…
wilmveel Mar 1, 2026
ca4a982
Add design doc for Rust shared code pipeline refactor
wilmveel Mar 2, 2026
37398e4
Add implementation plan for Rust shared code pipeline refactor
wilmveel Mar 2, 2026
0e1adff
Replace RustIrEmitter.shared raw template with AstShared.convert() pi…
wilmveel Mar 2, 2026
b64a4eb
Fix fragile string-based injection and regex post-processing in RustI…
wilmveel Mar 2, 2026
4e27ef7
Refactor RustGenerator and RustIrEmitter for improved code clarity, c…
wilmveel Mar 2, 2026
9a0c8ca
Refactor RustIrEmitter: extract reusable helpers and simplify endpoin…
wilmveel Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,33 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 20
- uses: sbt/setup-sbt@v1
- uses: dtolnay/rust-toolchain@stable
- name: Run
run: |
make example

verify:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
cache: gradle
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-passphrase: GPG_PASSPHRASE
- uses: actions/setup-node@v3
with:
node-version: 20
- name: Run
run: |
make verify

version:

runs-on: ubuntu-latest
Expand All @@ -114,6 +137,7 @@ jobs:
needs:
- build
- example
- verify

outputs:
version: ${{steps.version.outputs.version}}
Expand Down
237 changes: 237 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
# Wirespec - Claude Code Instructions

## Generated Code Requirements

All code generated by Wirespec emitters must be **dependency-free**. Generated output must not rely on any external libraries or third-party packages — it must be fully self-contained and runnable with only the target language's standard library.

## IR Emitter Pipeline

The Wirespec compiler uses a four-stage IR pipeline to generate idiomatic code for Java, Kotlin, TypeScript, Python, and Rust:

```
Wirespec Source
Parser ──► AST (Root / Module / Definition)
IrConverter ──► IR File (language-neutral tree)
Language Emitter ──► Transformed IR File (via Transform DSL)
CodeGenerator ──► String (target-language source code)
```

### Stage 1: Parser AST

The parser produces a tree of `Definition` nodes grouped into `Module`s inside a `Root`:

```
Root ─► Module[] ─► Definition[]
```

**Definition types** (sealed hierarchy):
- `Type` — record/struct with a `Shape` (list of `Field`s) and optional `extends`
- `Enum` — set of string entries
- `Union` — set of `Reference` entries
- `Refined` — primitive wrapper with a regex/bound constraint
- `Endpoint` — HTTP endpoint (method, path, queries, headers, requests, responses)
- `Channel` — async messaging channel with a reference type

**Reference type system** (`sealed interface Reference`):
`Any`, `Unit`, `Custom(name)`, `Primitive(type)`, `Iterable(reference)`, `Dict(reference)`. Each carries `isNullable`. `Primitive.Type` variants: `String`, `Integer`, `Number`, `Boolean`, `Bytes` (with optional precision and constraints).

Key files:
- `src/compiler/core/.../parse/ast/Definition.kt`
- `src/compiler/core/.../parse/ast/Reference.kt`
- `src/compiler/core/.../parse/ast/Root.kt`

### Stage 2: Convert (Parser AST → IR)

`IrConverter.kt` maps each parser `Definition` to an IR `File` tree. The entry point dispatches by definition type:

```kotlin
fun DefinitionWirespec.convert(): File = when (this) {
is TypeWirespec -> convert()
is EnumWirespec -> convert()
is UnionWirespec -> convert()
is RefinedWirespec -> convert()
is ChannelWirespec -> convert()
is EndpointWirespec -> convert()
}
```

Each per-definition converter produces a complete IR `File` with the appropriate structs, interfaces, functions, and validation logic. `EndpointWirespec.convert()` is the most complex — it generates Path/Queries/RequestHeaders/Request structs, a Response union hierarchy, serialization functions, and a Handler interface.

Reference conversion maps parser references to IR types: `Custom → Type.Custom`, `Iterable → Type.Array`, `Dict → Type.Dict`, `Primitive → Type.String/Integer/Number/Boolean/Bytes`, wrapping with `Type.Nullable` when `isNullable`.

Key file: `src/compiler/ir/.../converter/IrConverter.kt`

### Stage 3: IR AST

The IR is a language-neutral tree with the following node types:

**Elements** (AST nodes):
- `File(name, elements)` — top-level container
- `Struct(name, fields, constructors, interfaces, elements)` — record/class
- `Interface(name, elements, extends, isSealed, typeParameters, fields)` — interface/protocol
- `Namespace(name, elements, extends)` — grouping container
- `Union(name, members, typeParameters)` — tagged union
- `Enum(name, entries, fields, constructors, elements)` — enumeration (entries have name + values)
- `Function(name, typeParameters, parameters, returnType, body, isAsync, isStatic, isOverride)`
- `Package(path)`, `Import(path, type)`, `RawElement(code)`

**Type system** (`sealed interface Type`):
`Integer(precision)`, `Number(precision)`, `String`, `Boolean`, `Bytes`, `Unit`, `Any`, `Wildcard`, `Reflect`, `Array(elementType)`, `Dict(keyType, valueType)`, `Custom(name, generics)`, `Nullable(type)`

**Statement / Expression hierarchy**: `RawExpression`, `VariableReference`, `FieldCall`, `FunctionCall`, `BinaryOp`, `ConstructorStatement`, `Literal`, `Switch/Case`, `IfExpression`, `StringTemplate`, `MapExpression`, `ReturnStatement`, `Assignment`, constraints (`RegexMatch`, `BoundCheck`), null-handling (`NullCheck`, `NullableMap`, `NullableOf`), and more.

Key file: `src/compiler/ir/.../core/Ast.kt`

### Stage 4: Transform (detailed)

The transform layer is the heart of language-specific adaptation. It lets each emitter reshape the language-neutral IR into a form that generates idiomatic target code.

Key file: `src/compiler/ir/.../core/Transform.kt`

#### Transformer interface

Eight override points, each defaulting to recursive `transformChildren()`:

```kotlin
interface Transformer {
fun transformType(type: Type): Type
fun transformElement(element: Element): Element
fun transformStatement(statement: Statement): Statement
fun transformExpression(expression: Expression): Expression
fun transformField(field: Field): Field
fun transformParameter(parameter: Parameter): Parameter
fun transformConstructor(constructor: Constructor): Constructor
fun transformCase(case: Case): Case
}
```

#### `transformer()` DSL factory

Creates a `Transformer` using a `TransformerBuilder` with a builder-pattern DSL. Only the overrides you specify are applied; all others default to recursive `transformChildren()`:

```kotlin
inline fun transformer(block: TransformerBuilder.() -> Unit): Transformer

// Usage:
transformer {
type { type, transformer -> /* ... */ }
element { element, transformer -> /* ... */ }
statement { statement, transformer -> /* ... */ }
expression { expression, transformer -> /* ... */ }
field { field, transformer -> /* ... */ }
parameter { parameter, transformer -> /* ... */ }
constructor { constructor, transformer -> /* ... */ }
case { case, transformer -> /* ... */ }
}
```

#### `transformChildren()` recursive traversal

Each node type has a `transformChildren(Transformer)` extension that walks into its children. For example, a `Struct` transforms its fields, constructors, and child elements; a `FunctionCall` transforms its receiver, type arguments, and argument expressions. This ensures transforms propagate through the entire tree.

Apply a transformer to any element: `fun <T : Element> T.transform(transformer: Transformer): T`

#### `TransformScope` — block-based transform API

The primary API used by language emitters. Call `element.transform { ... }` to open a scope and chain multiple transforms:

```kotlin
inline fun <E : Element> E.transform(block: TransformScope<E>.() -> Unit): E
```

`TransformScope<E>` methods:

| Method | Purpose |
|---|---|
| `matching<M : Type> { transform }` | Transform all types matching a Kotlin class |
| `matchingElements<M : Element> { transform }` | Transform all elements matching a Kotlin class |
| `fieldsWhere(predicate, transform)` | Transform fields matching a predicate |
| `parametersWhere(predicate, transform)` | Transform parameters matching a predicate |
| `renameType(oldName, newName)` | Rename a `Type.Custom` throughout the tree |
| `renameField(oldName, newName)` | Rename a field throughout the tree |
| `typeByName(name, transform)` | Transform types matching a custom name |
| `injectBefore<T> { produce }` | Insert elements before a matching container |
| `injectAfter<T> { produce }` | Insert elements after a matching container |
| `apply(transformer)` | Apply a pre-built `Transformer` |
| `type { type, transformer -> ... }` | Shorthand: create + apply a type transformer |
| `statement { stmt, transformer -> ... }` | Shorthand: create + apply a statement transformer |
| `expression { expr, transformer -> ... }` | Shorthand: create + apply an expression transformer |
| `field { field, transformer -> ... }` | Shorthand: create + apply a field transformer |
| `parameter { param, transformer -> ... }` | Shorthand: create + apply a parameter transformer |
| `constructor { ctor, transformer -> ... }` | Shorthand: create + apply a constructor transformer |
| `case { case, transformer -> ... }` | Shorthand: create + apply a case transformer |

#### Low-level helper functions

These `internal` extension functions on `Element` power the `TransformScope` methods above:

| Function | Purpose |
|---|---|
| `transformMatching<M : Type>` | Transform all types matching a Kotlin class |
| `transformMatchingElements<M : Element>` | Transform all elements matching a Kotlin class |
| `transformFieldsWhere(predicate, transform)` | Transform fields matching a predicate |
| `transformParametersWhere(predicate, transform)` | Transform parameters matching a predicate |
| `renameType(oldName, newName)` | Rename a `Type.Custom` throughout the tree |
| `renameField(oldName, newName)` | Rename a field throughout the tree |
| `transformTypeByName(name, transform)` | Transform types matching a custom name |
| `injectBefore<T>(produce)` | Insert elements before a matching container |
| `injectAfter<T>(produce)` | Insert elements after a matching container |

#### Read-only traversal utilities

Standalone functions (not an interface) for walking the IR tree without modifying it:

| Function | Purpose |
|---|---|
| `forEachType(action)` | Visit every `Type` node in the tree |
| `forEachElement(action)` | Visit every `Element` node in the tree |
| `forEachField(action)` | Visit every `Field` node in the tree |
| `collectTypes()` | Collect all `Type` nodes into a list |
| `collectCustomTypeNames()` | Collect all `Type.Custom` names into a set |
| `findAll<T>()` | Find all elements of a specific type |
| `findAllTypes<T>()` | Find all types of a specific type |
| `findElement<T>()` | Find the first child element of a specific type |

### Stage 5: Generate

Each language emitter implements `File.generate()` by delegating to a `CodeGenerator` singleton:

```kotlin
interface CodeGenerator {
fun generate(element: Element): String
}
```

Generators: `JavaGenerator`, `KotlinGenerator`, `TypeScriptGenerator`, `PythonGenerator`, `RustGenerator`. Each recursively walks the IR tree and emits the corresponding target-language syntax as a string.

Top-level entry: `fun Element.generateJava()`, `fun Element.generateKotlin()`, etc.

Key files:
- `src/compiler/ir/.../emit/IrEmitter.kt`
- `src/compiler/ir/.../generator/CodeGenerator.kt`
- `src/compiler/ir/.../generator/{Java,Kotlin,TypeScript,Python,Rust}Generator.kt`

### Key File Reference

| File | Purpose |
|---|---|
| `src/compiler/core/.../parse/ast/Definition.kt` | Parser AST definition types |
| `src/compiler/core/.../parse/ast/Reference.kt` | Parser AST reference/type system |
| `src/compiler/ir/.../converter/IrConverter.kt` | Parser AST → IR conversion |
| `src/compiler/ir/.../core/Ast.kt` | IR node types (Element, Type, Statement, Expression) |
| `src/compiler/ir/.../core/Transform.kt` | Transform DSL + TransformScope + traversal utilities |
| `src/compiler/ir/.../emit/IrEmitter.kt` | Emitter interface and orchestration |
| `src/compiler/ir/.../generator/CodeGenerator.kt` | Generator interface + top-level functions |
| `src/compiler/emitters/java/.../JavaIrEmitter.kt` | Java-specific transforms + emit |
| `src/compiler/emitters/kotlin/.../KotlinIrEmitter.kt` | Kotlin-specific transforms + emit |
| `src/compiler/emitters/typescript/.../TypeScriptIrEmitter.kt` | TypeScript-specific transforms + emit |
| `src/compiler/emitters/python/.../PythonIrEmitter.kt` | Python-specific transforms + emit |
| `src/compiler/emitters/rust/.../RustIrEmitter.kt` | Rust-specific transforms + emit |
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ update:
npm install -g @vscode/vsce

verify:
$(shell pwd)/scripts/verify.sh
./gradlew :src:verify:test -Pverify

yolo:
$(shell pwd)/scripts/yolo.sh
Loading