Architecture
This is a brief overview for contributors. For detailed implementation notes, see the project’s CLAUDE.md.
Compilation Pipeline
TypeScript (.ts)
↓ Parse (SWC)
↓ AST
↓ Lower (perry-hir)
↓ HIR (High-level IR)
↓ Transform (inline, closure conversion, async lowering)
↓ Codegen (Cranelift)
↓ Object file (.o)
↓ Link (system cc)
↓
Native Executable
Crate Map
| Crate | Purpose |
|---|---|
perry | CLI driver, command parsing, compilation orchestration |
perry-parser | SWC wrapper for TypeScript parsing |
perry-types | Type system definitions |
perry-hir | HIR data structures (ir.rs) and AST→HIR lowering (lower.rs) |
perry-transform | IR passes: function inlining, closure conversion, async lowering |
perry-codegen | Cranelift-based native code generation (12 modules) |
perry-codegen-js | JavaScript code generation for --target web |
perry-codegen-swiftui | SwiftUI code generation for WidgetKit extensions |
perry-runtime | Runtime library: NaN-boxed values, GC, arena allocator, objects, arrays, strings |
perry-stdlib | Node.js API implementations: mysql2, redis, fastify, bcrypt, etc. |
perry-ui | Shared UI types |
perry-ui-macos | macOS UI (AppKit) |
perry-ui-ios | iOS UI (UIKit) |
perry-jsruntime | JavaScript interop via QuickJS |
Key Concepts
NaN-Boxing
All JavaScript values are represented as 64-bit NaN-boxed values. The upper 16 bits encode the type tag:
| Tag | Type |
|---|---|
0x7FFF | String (lower 48 bits = pointer) |
0x7FFD | Pointer/Object (lower 48 bits = pointer) |
0x7FFE | Int32 (lower 32 bits = integer) |
0x7FFA | BigInt (lower 48 bits = pointer) |
| Special constants | undefined, null, true, false |
| Any other | Float64 (the full 64 bits) |
Garbage Collection
Mark-sweep GC with conservative stack scanning. Arena-allocated objects (arrays, objects) are found by linear block walking. Malloc-allocated objects (strings, closures, promises) are tracked in a thread-local Vec.
Handle-Based UI
UI widgets are represented as small integer handles NaN-boxed with POINTER_TAG. Each handle maps to a native platform widget (NSButton, UILabel, GtkButton, etc.). Two dispatch tables route method calls and property accesses to the correct FFI function.
Source Code Organization
The codegen crate was split into 12 focused modules:
perry-codegen/src/
codegen.rs # Main entry, module compilation
types.rs # Type definitions, context structs
util.rs # Helper functions
stubs.rs # Stub generation for unresolved deps
runtime_decls.rs # Runtime function declarations
classes.rs # Class compilation
functions.rs # Function compilation
closures.rs # Closure compilation
module_init.rs # Module initialization
stmt.rs # Statement compilation
expr.rs # Expression compilation
The HIR lowering was split into 8 modules:
perry-hir/src/
lower.rs # Main lowering entry
analysis.rs # Code analysis passes
enums.rs # Enum lowering
jsx.rs # JSX lowering
lower_types.rs # Type lowering
lower_patterns.rs # Pattern lowering
destructuring.rs # Destructuring lowering
lower_decl.rs # Declaration lowering
Next Steps
- Building from Source
- See
CLAUDE.mdin the repository root for detailed implementation notes