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,139 @@
|
||||
#!/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()
|
||||
Reference in new issue
Block a user