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>
This commit is contained in:
Aaron SinclairandClaude committed 2025-11-15 11:07:58 -08:00
1 parent c947bcf6e0
commit adf95f424d
7 files changed
+1282 -665

No files matched your search

+82
View File
@@ -0,0 +1,82 @@
"""Tests for wrapper component pattern to reduce repetition."""
import pytest
from ritz.parser import parse_component
from ritz.llvm_codegen_signals import generate_llvm_ir
def test_tab_button_wrapper_component():
"""Test wrapper component pattern for reducing tab button repetition."""
source = """
from ritz.syntax import *
@component
def TabButton(label, index, active, onclick):
\"\"\"Wrapper component for tab buttons with active state.\"\"\"
if active:
with Button(class_="tab active", onclick=onclick):
yield label
else:
with Button(class_="tab", onclick=onclick):
yield label
@component
def SimpleTabs():
tab_index = signal(0)
def set_tab(value):
tab_index = value
with Div(class_="tab-menu"):
yield TabButton("Home", 0, tab_index == 0, lambda: set_tab(0))
yield TabButton("Profile", 1, tab_index == 1, lambda: set_tab(1))
yield TabButton("Settings", 2, tab_index == 2, lambda: set_tab(2))
"""
ir = parse_component(source)
# Should parse both components
assert isinstance(ir, list)
assert len(ir) == 2
assert ir[0]["name"] == "TabButton"
assert ir[1]["name"] == "SimpleTabs"
# TabButton should have parameters
assert len(ir[0]["params"]) == 4
assert ir[0]["params"][0]["name"] == "label"
assert ir[0]["params"][1]["name"] == "index"
assert ir[0]["params"][2]["name"] == "active"
assert ir[0]["params"][3]["name"] == "onclick"
def test_tab_button_wrapper_codegen():
"""Test LLVM codegen for wrapper component pattern."""
source = """
from ritz.syntax import *
@component
def TabButton(label, active, onclick):
if active:
with Button(class_="tab active", onclick=onclick):
yield label
else:
with Button(class_="tab", onclick=onclick):
yield label
@component
def SimpleTabs():
tab_index = signal(0)
def set_tab(value):
tab_index = value
with Div():
yield TabButton("Home", tab_index == 0, lambda: set_tab(0))
"""
ir = parse_component(source)
llvm_ir = generate_llvm_ir(ir)
# Should generate render function for TabButton with parameters
assert "define void @render_TabButton(" in llvm_ir
# Should call TabButton from SimpleTabs with arguments
assert "call void @render_TabButton(" in llvm_ir