Implement Python → LLVM IR → WASM reactive framework
MAJOR ACHIEVEMENT: Full working reactive framework! ## What's Working ✅ Python → AST → Ritz IR → LLVM IR → WASM pipeline ✅ Reactive signals stored in WASM memory (@signal_name = global i32) ✅ Event handlers exported from WASM and callable from JS ✅ Clean runtime with RitzLoader and debug tools ✅ Two working examples: HelloWorld and HighFive counter ## Core Components ### Parser (ritz/parser.py) - Uses Python's ast module to parse components - Handles @component decorator, signals, event handlers - Supports yield, with statements, f-strings, augmented assignment (+=) - Clean syntax: from ritz.syntax import * ### LLVM IR Code Generator (ritz/llvm_codegen_signals.py) - Generates LLVM IR directly (not C!) - Signals as global variables in WASM memory - Exports getter/setter functions for each signal - Exports event handler functions for JS to call - UTF-8 string handling ### Build System (ritz/build.py) - Python → AST → IR → LLVM IR → clang --target=wasm32 → WASM - Saves intermediate .ll files for inspection - Debug symbols support (-g flag) ### Runtime (runtime/ritz-runtime.js) - RitzRuntime class: DOM bridge for WASM - RitzLoader class: Simplified component loading - Debug bar with Ctrl+` toggle - Signal updates trigger DOM updates ## Examples ### HelloWorld.py Simple static content - renders <p>Hello World</p> ### HighFive.py Reactive counter with: - Signal in WASM memory (high_fives = signal(0)) - Event handler (increment function) - DOM updates on signal change ## Test Coverage - 4 parser tests (all passing) - 4 LLVM codegen tests (all passing) - 4 signal parsing tests (all passing) - Code formatted with black and ruff ## Next Steps - <script type="text/ritz"> in-browser compilation - Better signal-to-DOM binding tracking - More complex examples (TodoMVC, forms, lists) - Playwright browser tests --- This is a genuinely innovative framework: write Python, compile to WASM, run with reactive signals in WASM memory. No virtual DOM, no transpilation, just compiled Python with fine-grained reactivity. 🎉 Python → WASM → Reactive UI is REAL!
This commit is contained in:
1 parent
316c090778
commit
635d466874
54 files changed
+4393
No files matched your search
@@ -0,0 +1,163 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Ritz is a WebAssembly UI framework with Python-like syntax that compiles to high-performance WASM while remaining executable in Python for debugging. The framework uses **valid Python syntax** that can execute in CPython for prototyping/debugging, but is designed to compile to WebAssembly for production.
|
||||
|
||||
**Current Status**: Python prototype stage. The WASM compilation pipeline is conceptual/architectural.
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Running the Prototype
|
||||
```bash
|
||||
# Run example application showing various components
|
||||
python3 example.py
|
||||
|
||||
# Run simple test
|
||||
python3 test.py
|
||||
|
||||
# Test AST parser
|
||||
python3 ast_parser.py
|
||||
|
||||
# View module system concept
|
||||
python3 module_system.py
|
||||
|
||||
# View compilation pipeline concept
|
||||
python3 compiler.py
|
||||
|
||||
# View debugging concept
|
||||
python3 debug_concept.py
|
||||
```
|
||||
|
||||
## Core Architecture
|
||||
|
||||
### Component Model
|
||||
Components are defined using the `@component` decorator with Python generator syntax (yield-based):
|
||||
|
||||
```python
|
||||
@component
|
||||
def Counter():
|
||||
count = signal(0) # Reactive state
|
||||
|
||||
def increment():
|
||||
count += 1
|
||||
|
||||
with Div(class_='counter'): # Context managers for element nesting
|
||||
yield H1('Counter') # Yield elements/strings/components
|
||||
yield P(f'Count: {count}')
|
||||
yield Button('Click me', onclick=increment)
|
||||
```
|
||||
|
||||
Key patterns:
|
||||
- **Generators**: Components are generator functions that yield children
|
||||
- **Context managers**: Use `with Element():` for nested structures
|
||||
- **Signals**: Reactive state via `signal(initial_value)`
|
||||
- **Mixed content**: Can yield strings, elements, or other components
|
||||
|
||||
### File Structure
|
||||
|
||||
**Core Framework Files:**
|
||||
- `framework.py` - Python prototype runtime (Signal, VNode, Element, component decorator)
|
||||
- `ast_parser.py` - Parses Python components using Python's `ast` module to generate IR
|
||||
- `compiler.py` - Complete compilation pipeline concept (Python → IR → LLVM → WASM)
|
||||
- `module_system.py` - Progressive module loading architecture for code splitting
|
||||
|
||||
**Conceptual/Research:**
|
||||
- `debug_concept.py` - Python-in-WASM debugging architecture (DWARF symbols, source maps)
|
||||
- `RESEARCH.md` - Complete technical architecture and implementation roadmap
|
||||
|
||||
**Examples:**
|
||||
- `example.py` - Demonstrates component syntax with various examples
|
||||
- `test.py` - Simple test for debugging framework behavior
|
||||
|
||||
### Compilation Pipeline (Conceptual)
|
||||
|
||||
The planned compilation flow:
|
||||
1. **Parser**: Uses Python's `ast` module to parse components (no custom parser needed!)
|
||||
2. **IR Generation**: Transform Python AST → Ritz intermediate representation
|
||||
3. **LLVM Codegen**: Ritz IR → LLVM IR
|
||||
4. **WASM Output**: LLVM IR → WebAssembly with debug symbols (DWARF)
|
||||
5. **Module Splitting**: Split into multiple WASM modules (bootstrap, core, features)
|
||||
|
||||
### Reactive System
|
||||
|
||||
**Signals** are the primitive reactive unit:
|
||||
- Store a value and list of subscribers
|
||||
- When value changes, notify all subscribers
|
||||
- In Python prototype: simple Python class
|
||||
- In WASM target: efficient memory layout with direct DOM node references
|
||||
|
||||
**Key insight**: No virtual DOM. Signals map directly to DOM nodes for updates.
|
||||
|
||||
### Module System Architecture
|
||||
|
||||
Apps split into multiple WASM modules for security and performance:
|
||||
- `bootstrap.wasm` (~50KB) - Login only, no auth required, no business logic
|
||||
- `app-core.wasm` (~200KB) - Main app, requires authentication
|
||||
- `features/*.wasm` - Lazy-loaded feature modules
|
||||
|
||||
**Security benefit**: Unauthenticated users never receive app code containing API endpoints or business logic.
|
||||
|
||||
## Important Implementation Details
|
||||
|
||||
### AST Parsing
|
||||
The framework uses **Python's own `ast` module** to parse components (not a custom parser). This provides:
|
||||
- Zero parsing overhead
|
||||
- Perfect Python compatibility
|
||||
- Automatic syntax error messages
|
||||
- Type hints support
|
||||
|
||||
See `ast_parser.py` for the `RitzASTTransformer` that converts Python AST to Ritz IR.
|
||||
|
||||
### VNode Structure
|
||||
Internal representation during Python execution:
|
||||
- `VNode(tag, props, children)` - Virtual DOM node
|
||||
- `to_html()` - Render to HTML string
|
||||
- `to_ir()` - Convert to intermediate representation for compilation
|
||||
|
||||
### Context Stack
|
||||
`_context_stack` is a global list tracking nested `with Element():` blocks. The `@component` decorator manages this stack to build the component tree.
|
||||
|
||||
## Debugging Philosophy
|
||||
|
||||
**Revolutionary concept**: Debug Python code running in WASM, not JavaScript!
|
||||
- DWARF debug symbols embedded in WASM
|
||||
- Source maps linking WASM instructions → Python source lines
|
||||
- Chrome DevTools can set breakpoints in Python files
|
||||
- Inspect Python variables, not mangled JS
|
||||
|
||||
See `debug_concept.py` and RESEARCH.md sections on debugging.
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Python-executable, WASM-compilable**: The same code runs in both environments
|
||||
2. **Yield-based composition**: Natural Python syntax for building component trees
|
||||
3. **Fine-grained reactivity**: Signals update DOM directly, no virtual DOM diffing
|
||||
4. **Progressive loading**: Split code into secure, cacheable modules
|
||||
5. **Developer experience**: Debug in Python, ship as WASM
|
||||
|
||||
## Performance Targets
|
||||
|
||||
Based on SolidJS/Leptos research:
|
||||
- Bundle size: < 200KB compressed
|
||||
- Startup time: < 500ms on slow 3G
|
||||
- Update performance: Within 10% of vanilla JS
|
||||
- Memory usage: 70% less than React
|
||||
- DOM mutations: 99% fewer than virtual DOM frameworks
|
||||
|
||||
## When Modifying Code
|
||||
|
||||
1. **Python prototype** (`framework.py`): Currently functional, can be tested with Python
|
||||
2. **Compilation pipeline** (`compiler.py`, `ast_parser.py`): Architectural/conceptual code that demonstrates intended design
|
||||
3. **Module system** (`module_system.py`): Demonstrates progressive loading strategy
|
||||
4. Components must be valid Python and use generator syntax with yield
|
||||
5. All examples should run with `python3 example.py`
|
||||
|
||||
## Key Technical Decisions
|
||||
|
||||
- **Why yield?** Natural Python syntax, composable, clear execution order
|
||||
- **Why compile vs interpret?** 10-100x performance, smaller bundle, type safety
|
||||
- **Why LLVM?** Mature toolchain, excellent WASM backend, optimization passes
|
||||
- **Why Python's ast module?** No custom parser needed, perfect compatibility
|
||||
Reference in new issue
Block a user