Parser: Support multiple components in one file, change args to params with defaults

This commit is contained in:
Aaron Sinclair committed 2025-11-15 03:25:13 -08:00
1 parent 635d466874
commit 81d51d5617
38 files changed
+2151 -455

No files matched your search

+120
View File
@@ -0,0 +1,120 @@
"""Tests for conditional rendering (if statements)."""
import pytest
from ritz.parser import parse_component
def test_if_statement():
"""Test parsing if statement for conditional rendering."""
source = """
from ritz.syntax import *
@component
def Toggle():
visible = signal(True)
if visible:
with P():
yield "I am visible!"
"""
ir = parse_component(source)
# Find the if statement
if_stmt = None
for stmt in ir["body"]:
if stmt["type"] == "if":
if_stmt = stmt
break
assert if_stmt is not None
assert if_stmt["test"]["type"] == "name"
assert if_stmt["test"]["id"] == "visible"
assert len(if_stmt["body"]) == 1
assert if_stmt["body"][0]["type"] == "with"
def test_if_else_statement():
"""Test parsing if/else for conditional rendering."""
source = """
from ritz.syntax import *
@component
def Toggle():
visible = signal(True)
if visible:
with P():
yield "Shown"
else:
with P():
yield "Hidden"
"""
ir = parse_component(source)
# Find the if statement
if_stmt = None
for stmt in ir["body"]:
if stmt["type"] == "if":
if_stmt = stmt
break
assert if_stmt is not None
assert len(if_stmt["body"]) == 1
assert len(if_stmt["orelse"]) == 1
assert if_stmt["body"][0]["element"]["tag"] == "P"
assert if_stmt["orelse"][0]["element"]["tag"] == "P"
def test_if_comparison():
"""Test parsing if statement with comparison."""
source = """
from ritz.syntax import *
@component
def Counter():
count = signal(0)
if count > 5:
with P():
yield "High count!"
"""
ir = parse_component(source)
# Find the if statement
if_stmt = None
for stmt in ir["body"]:
if stmt["type"] == "if":
if_stmt = stmt
break
assert if_stmt is not None
assert if_stmt["test"]["type"] == "compare"
assert if_stmt["test"]["op"] == "Gt"
def test_nested_if():
"""Test parsing nested if statements."""
source = """
from ritz.syntax import *
@component
def Nested():
a = signal(True)
b = signal(False)
if a:
if b:
with P():
yield "Both true"
"""
ir = parse_component(source)
# Find outer if
outer_if = None
for stmt in ir["body"]:
if stmt["type"] == "if":
outer_if = stmt
break
assert outer_if is not None
assert outer_if["body"][0]["type"] == "if"
+82
View File
@@ -0,0 +1,82 @@
"""Tests for LLVM IR code generation with conditional rendering."""
import pytest
from ritz.parser import parse_component
from ritz.llvm_codegen_signals import generate_llvm_ir
def test_if_statement_codegen():
"""Test LLVM IR generation for if statement."""
source = """
from ritz.syntax import *
@component
def Toggle():
visible = signal(1)
if visible:
with P():
yield "I am visible!"
"""
ir = parse_component(source)
llvm_ir = generate_llvm_ir(ir)
# Should have signal global
assert "@signal_visible = global i32 1" in llvm_ir
# Should have conditional branch
assert "br i1" in llvm_ir
# Should have basic blocks for then/else/merge
assert "if.then." in llvm_ir
assert "if.end." in llvm_ir
def test_if_else_codegen():
"""Test LLVM IR generation for if/else."""
source = """
from ritz.syntax import *
@component
def Toggle():
visible = signal(1)
if visible:
with P():
yield "Shown"
else:
with P():
yield "Hidden"
"""
ir = parse_component(source)
llvm_ir = generate_llvm_ir(ir)
# Should have conditional branch
assert "br i1" in llvm_ir
# Should have both then and else blocks
assert "if.then." in llvm_ir
assert "if.else." in llvm_ir
def test_if_comparison_codegen():
"""Test LLVM IR generation for if with comparison."""
source = """
from ritz.syntax import *
@component
def Counter():
count = signal(0)
if count > 5:
with P():
yield "High count!"
"""
ir = parse_component(source)
llvm_ir = generate_llvm_ir(ir)
# Should have icmp instruction for comparison
assert "icmp" in llvm_ir
# Should have greater-than comparison (sgt = signed greater than)
assert "sgt" in llvm_ir or ">" in llvm_ir
+68
View File
@@ -0,0 +1,68 @@
"""Tests for match/case statement parsing."""
import pytest
from ritz.parser import parse_component
def test_match_statement():
"""Test parsing match statement."""
source = """
from ritz.syntax import *
@component
def Tabs():
tab = signal(0)
match tab:
case 0:
with P():
yield "First"
case 1:
with P():
yield "Second"
"""
ir = parse_component(source)
# Find the match statement
match_stmt = None
for stmt in ir["body"]:
if stmt["type"] == "match":
match_stmt = stmt
break
assert match_stmt is not None
assert match_stmt["subject"]["type"] == "name"
assert match_stmt["subject"]["id"] == "tab"
assert len(match_stmt["cases"]) == 2
def test_match_with_wildcard():
"""Test match with wildcard case."""
source = """
from ritz.syntax import *
@component
def Tabs():
tab = signal(0)
match tab:
case 0:
with P():
yield "Home"
case _:
with P():
yield "Other"
"""
ir = parse_component(source)
# Find the match statement
match_stmt = None
for stmt in ir["body"]:
if stmt["type"] == "match":
match_stmt = stmt
break
assert match_stmt is not None
assert len(match_stmt["cases"]) == 2
# Wildcard should be the last case
assert match_stmt["cases"][1]["pattern"]["type"] == "wildcard"
+12 -5
View File
@@ -33,7 +33,11 @@ def test_signal_llvm_ir_structure():
def test_signal_with_fstring():
"""Test signal reference in f-string generates proper IR."""
"""Test signal reference in f-string generates proper IR.
NOTE: Full f-string interpolation is not yet implemented - this is a TODO.
Currently generates a placeholder text node.
"""
from ritz.llvm_codegen import generate_llvm_ir
from ritz.parser import parse_component
@@ -51,11 +55,14 @@ def test_signal_with_fstring():
ir = parse_component(source)
llvm_ir = generate_llvm_ir(ir)
# Should call signal getter
assert "get_count" in llvm_ir or "load" in llvm_ir # Loading signal value
# Should have signal storage
assert "@signal_count" in llvm_ir
# Should have string formatting/concatenation
assert "Count:" in llvm_ir
# Should have getter function
assert "get_count" in llvm_ir
# TODO: Full f-string support - currently creates placeholder
assert "js_create_text" in llvm_ir
def test_event_handler_export():