Commit Graph
8 Commits
Author SHA1 Message Date
Aaron SinclairandClaude adf95f424d Fix lambda event handlers & add ternary expression support
Fixes:
- Lambda functions now correctly pass arguments to handlers
- Function parameters properly emitted in LLVM IR
- Event handlers defined with parameter lists

New feature - Ternary expressions:
- Support Python ternary syntax (x if cond else y) in props
- Eliminates repetitive if/else blocks for active states
- Before: 6 lines per tab button
- After: 1 line with ternary expression

Example:
  class_='tab active' if active else 'tab'

All tests passing (51 passed, 2 skipped)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 11:07:58 -08:00
Aaron SinclairandClaude e09a6dedc8 Add component props and lambda event handlers (TDD)
Implements two major features using Test-Driven Development:

1. Component Props/Parameters:
   - Components can accept parameters: @component def Button(label)
   - Arguments passed when yielding: yield Button("Click me")
   - Default values supported: def Tabs(orientation=0)
   - Codegen passes arguments correctly to render functions

2. Lambda Event Handlers:
   - Support onclick=lambda: function_call() syntax
   - Parser converts lambdas to synthetic functions
   - Synthetic functions auto-named: _lambda_0_ComponentName
   - Codegen emits lambda functions as event handlers
   - Clean syntax vs set_tab_0/1/2 boilerplate

Implementation:
   - Added _process_lambdas_in_component() to scan & convert
   - Lambda detection in _transform_expr()
   - "expr" statement type for lambda bodies
   - Component argument passing in _emit_yield_component()
   - Constants vs variables handled correctly in args

Tests (TDD Style):
   - test_component_props.py (8 tests) - all passing
   - test_lambda_simple.py (3 tests) - all passing
   - 46 total tests passing

Examples:
   # Before (verbose)
   def set_tab_0(): tab = 0
   def set_tab_1(): tab = 1
   with Button(onclick=set_tab_0): yield "Tab 0"

   # After (clean)
   with Button(onclick=lambda: set_tab(0)): yield "Tab 0"
   with Button(onclick=lambda: set_tab(1)): yield "Tab 1"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 10:45:17 -08:00
Aaron SinclairandClaude e686903170 Fix reactive conditional rendering with proper branch swapping
Implements efficient reactive conditionals that pre-render branches once
and swap DOM nodes without recreation, enabling fast switching with
thousands of elements.

Key Fixes:
- Runtime now calls reevaluate_conditional_*() on signal changes
- Match/case swap logic uses phi nodes to load correct old case
- Previously hardcoded case_0 as old value, causing accumulation
- Branch render functions now wrap all content in container div

Implementation:
- Pre-render both if/else branches at init
- Store roots in globals (@cond_N_then_root, @cond_N_else_root)
- On signal change, swap DOM nodes via js_replace_at_marker()
- Match statements use switch/phi pattern to select old case

Tests:
- Added test_reactive_conditionals.py (5 new tests)
- Updated test_llvm_codegen_conditional.py for reactive infrastructure
- All 35 tests passing

Performance: No re-rendering on switches, perfect for dynamic content.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 10:32:40 -08:00
Aaron Sinclair 74ff1e7e9f Support multiple components in single file with scoped signals
- Update generate_llvm_ir() to accept list of component dicts
- Process each component with own signal/handler state
- Scope signal globals with component name prefix (@signal_ComponentName_signalName)
- Add _signal_global() helper for scoped signal names
- Update tests for scoped signal names
- All tests passing (30/30)
2025-11-15 03:32:38 -08:00
Aaron Sinclair 044eda2293 Implement basic if statement rendering in LLVM IR
- Add _emit_if() method to handle if statements
- Add _emit_expr() to evaluate signal references and constants
- Create basic blocks for then/else/merge
- Convert condition to i1 and branch
- Test passing: test_if_statement_codegen
2025-11-15 03:28:44 -08:00
Aaron Sinclair a3cd1df40a Fix parser test: args → params 2025-11-15 03:25:46 -08:00
Aaron Sinclair 81d51d5617 Parser: Support multiple components in one file, change args to params with defaults 2025-11-15 03:25:13 -08:00
Aaron Sinclair 635d466874 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!
2025-11-15 01:50:40 -08:00