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:
Aaron Sinclair committed 2025-11-15 01:50:40 -08:00
1 parent 316c090778
commit 635d466874
54 files changed
+4393

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
"""Tests for C code generation from IR."""
def test_codegen_hello_world():
"""Test generating C code for simple HelloWorld component."""
from ritz.codegen import generate_c_code
ir = {
"type": "component",
"name": "HelloWorld",
"args": [],
"body": [
{
"type": "with",
"element": {"tag": "P", "props": {}},
"body": [
{
"type": "yield",
"value": {"type": "constant", "value": "Hello World"},
}
],
}
],
}
c_code = generate_c_code(ir)
# Verify C code structure
assert "#include <emscripten.h>" in c_code
assert "void HelloWorld()" in c_code or "void render_HelloWorld()" in c_code
# Should create a P element
assert "create_element" in c_code or "createElement" in c_code
assert '"p"' in c_code or '"P"' in c_code.lower()
# Should create text node
assert '"Hello World"' in c_code
assert "create_text" in c_code or "createTextNode" in c_code or "set_text_content" in c_code
def test_codegen_with_props():
"""Test generating C code for element with props."""
from ritz.codegen import generate_c_code
ir = {
"type": "component",
"name": "StyledDiv",
"args": [],
"body": [
{
"type": "with",
"element": {
"tag": "Div",
"props": {
"class_": {"type": "constant", "value": "container"},
"id": {"type": "constant", "value": "main"},
},
},
"body": [{"type": "yield", "value": {"type": "constant", "value": "Content"}}],
}
],
}
c_code = generate_c_code(ir)
# Should set attributes
assert "set_attribute" in c_code or "setAttribute" in c_code
assert '"class"' in c_code or '"className"' in c_code
assert '"container"' in c_code
assert '"id"' in c_code
assert '"main"' in c_code
def test_codegen_nested_elements():
"""Test generating C code for nested elements."""
from ritz.codegen import generate_c_code
ir = {
"type": "component",
"name": "Nested",
"args": [],
"body": [
{
"type": "with",
"element": {"tag": "Div", "props": {}},
"body": [
{
"type": "with",
"element": {"tag": "P", "props": {}},
"body": [
{"type": "yield", "value": {"type": "constant", "value": "Inner"}}
],
}
],
}
],
}
c_code = generate_c_code(ir)
# Should have append_child calls to build hierarchy
assert "append_child" in c_code or "appendChild" in c_code
def test_codegen_includes_runtime_functions():
"""Test that generated C code includes necessary runtime declarations."""
from ritz.codegen import generate_c_code
ir = {
"type": "component",
"name": "Simple",
"args": [],
"body": [
{
"type": "with",
"element": {"tag": "P", "props": {}},
"body": [{"type": "yield", "value": {"type": "constant", "value": "test"}}],
}
],
}
c_code = generate_c_code(ir)
# Should include emscripten
assert "#include <emscripten.h>" in c_code
# Should have EMSCRIPTEN_KEEPALIVE for exported function
assert "EMSCRIPTEN_KEEPALIVE" in c_code