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>
Implements efficient reactive conditionals that pre-render branches once
and swap DOM nodes without recreation, enabling fast switching with
thousands of elements.
Key Fixes:
- Runtime now calls reevaluate_conditional_*() on signal changes
- Match/case swap logic uses phi nodes to load correct old case
- Previously hardcoded case_0 as old value, causing accumulation
- Branch render functions now wrap all content in container div
Implementation:
- Pre-render both if/else branches at init
- Store roots in globals (@cond_N_then_root, @cond_N_else_root)
- On signal change, swap DOM nodes via js_replace_at_marker()
- Match statements use switch/phi pattern to select old case
Tests:
- Added test_reactive_conditionals.py (5 new tests)
- Updated test_llvm_codegen_conditional.py for reactive infrastructure
- All 35 tests passing
Performance: No re-rendering on switches, perfect for dynamic content.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Critical change that makes conditionals reactive:
- Added signal_conditional_deps map to track dependencies
- Added _extract_signals_from_expr() to find signals in expressions
- Populate dependency map during _collect_conditionals()
- Replace TODO comments in signal setters with reevaluate calls
How it works:
1. During collection, analyze if/match test/subject expressions
2. Extract all signal names referenced in conditions
3. Build map: signal_name -> [conditional_ids that use it]
4. When signal is updated (assign/augassign), call reevaluate for each dependent conditional
Example: set_tab_0() now:
store i32 0, i32* @signal_Tabs_tab_index
call void @reevaluate_conditional_4()
call void @reevaluate_conditional_5()
call void @reevaluate_conditional_6()
call void @reevaluate_conditional_7()
This makes tabs fully interactive!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Implemented _emit_match_reactive() to generate init/reevaluate functions
- Modified _emit_match() to create markers and call init functions
- Init function pre-renders all cases and uses switch to insert active one
- Reevaluate function checks if subject changed and swaps DOM
Match init function:
- Calls _render_cond_X_case_Y() for each case
- Stores all case roots in globals
- Evaluates subject with switch instruction
- Inserts matching case at marker position
Fallback to _emit_match_static() if not collected.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Modified _emit_if() to:
- Create marker node via js_create_marker()
- Append marker to parent element
- Store marker ID in global
- Call _init_conditional_X() to render and insert active branch
Branch render functions work correctly:
- Build element tree locally
- Return root element ID
- Called by init function to pre-render all branches
Fallback to _emit_if_static() if conditional not collected.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Collect conditionals during IR scan (if/match statements)
- Emit conditional state globals (marker, current, branch roots)
- Generate init functions that pre-render all branches
- Generate reevaluate functions that swap DOM on condition change
- Add JS function declarations for markers and swapping
Not yet integrated with actual rendering - still emitting static if/match.
Next: modify _emit_if() to use reactive approach.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add parent_element_stack to track nesting context
- Elements inside if/match branches append to parent
- Fixes: Li elements inside if statements now append to Ul parent
- Tabs now render visibly!
- TODO: Fix duplicate appends
- All tests passing (30/30)
- Add _emit_match() using LLVM switch instruction
- Handle value patterns and wildcard (case _:) patterns
- Each case gets its own basic block with branch to end
- Wildcard case becomes default label in switch
- All tests passing (30/30)
- Tabs.wasm size: 1908 → 3185 bytes
- Handle 'assign' type statements in _emit_handler_statement()
- Evaluate value expression and store to signal global
- Enables patterns like: setting_tab = 0
- All tests passing (30/30)
- Update generate_llvm_ir() to accept list of component dicts
- Process each component with own signal/handler state
- Scope signal globals with component name prefix (@signal_ComponentName_signalName)
- Add _signal_global() helper for scoped signal names
- Update tests for scoped signal names
- All tests passing (30/30)
- Extend _emit_expr() to handle 'compare' type expressions
- Map Python comparison ops (Gt, Lt, Eq, etc) to LLVM icmp predicates
- Convert i1 result to i32 for compatibility
- All conditional tests passing (3/3)
- Add _emit_if() method to handle if statements
- Add _emit_expr() to evaluate signal references and constants
- Create basic blocks for then/else/merge
- Convert condition to i1 and branch
- Test passing: test_if_statement_codegen