Files
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

139 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""
Example Ritz Application
This actually runs in Python!
"""
from framework import (
component, signal, render,
Main, Div, P, Button, Label, H1, H2,
Article, Header, Section, Footer, Span, Strong, Em, Time
)
@component
def HighFiveApp():
"""Simple counter example"""
high_fives = signal(0)
def increment():
high_fives += 1
print(f"High fives incremented to: {high_fives.value}")
with Main():
yield H1('High Five Counter')
yield P('Give me a high 5 bro!')
yield Label(f'High fives: {high_fives}')
yield Button('Click me', onclick=increment)
@component
def Comment(author: str, text: str, replies=None):
"""Nested comment component"""
with Div(class_='comment'):
with Div(class_='comment-header'):
yield Strong(author)
yield ' says:'
with Div(class_='comment-body'):
yield text
if replies:
with Div(class_='replies'):
for reply in replies:
yield reply
@component
def BlogPost(title: str, author: str, content: str):
"""Complex component with mixed content"""
with Article(class_='blog-post'):
with Header():
yield H1(title)
yield 'By ' # Raw string!
yield Span(author, class_='author')
yield ' on '
yield Time('2024-01-15')
with Section(class_='content'):
yield P(content)
yield H2('Comments')
# Nested components with yield
yield Comment(
'Alice',
'Great post! This yield syntax is brilliant.',
replies=[
Comment('Bob', 'I agree! So Pythonic.'),
Comment('Charlie', 'Can\'t wait to see the WASM output.')
]
)
yield Comment(
'Dave',
'How does this compare to React performance-wise?'
)
@component
def TodoItem(text: str, completed: signal):
"""Todo item with reactive state"""
def toggle():
completed.value = not completed.value
print(f"Todo '{text}' toggled to: {completed.value}")
with Div(class_='todo-item'):
checkbox_props = {'type': 'checkbox', 'onclick': toggle}
if completed.value:
checkbox_props['checked'] = 'checked'
# Note: In real implementation, Input would be a special element
# For now we just demonstrate the pattern
yield Div(f'[{"✓" if completed.value else " "}] {text}',
class_='todo-checkbox',
onclick=toggle)
@component
def TodoApp():
"""Todo list with multiple signals"""
todos = [
('Build parser', signal(False)),
('Implement WASM compiler', signal(False)),
('Create reactive runtime', signal(False)),
('Optimize DOM bridge', signal(False))
]
with Div(class_='todo-app'):
yield H1('Ritz Framework TODO')
for text, completed in todos:
yield TodoItem(text, completed)
with Footer():
completed_count = sum(1 for _, c in todos if c.value)
yield P(f'Completed: {completed_count}/{len(todos)}')
def main():
"""Run examples and show output"""
print("=" * 60)
print("RITZ FRAMEWORK - Python Prototype")
print("=" * 60)
print("\n### Example 1: High Five Counter ###")
render(HighFiveApp)
print("\n" + "=" * 60)
print("\n### Example 2: Blog Post with Comments ###")
render(BlogPost,
title="Introducing Ritz Framework",
author="Aaron",
content="A new approach to web frameworks: Python syntax that compiles to WASM!")
print("\n" + "=" * 60)
print("\n### Example 3: Todo App ###")
render(TodoApp)
print("\n" + "=" * 60)
print("\nThis is actual Python running in CPython!")
print("In production, this would compile to WebAssembly.")
print("The same code runs in both environments!")
if __name__ == '__main__':
main()