Fix nested components - render functions now return i32
Changes: - Component render functions return i32 (root element) instead of void - Nested components (yield SomeComponent()) now work correctly - Added main() entry point that calls top-level component and sets root - Updated runtime to call main() instead of render_ComponentName() Note: Active state in ternary expressions still needs reactive updates This commit fixes the nested component rendering issue 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:
1 parent
adf95f424d
commit
b0e38db22c
26 files changed
+2310
-1222
No files matched your search
@@ -306,15 +306,13 @@ class RitzLoader {
|
||||
|
||||
this.setStatus(`⏳ Rendering ${componentName}...`);
|
||||
|
||||
// Call the render function with props
|
||||
const renderFn = instance.exports[`render_${componentName}`];
|
||||
if (!renderFn) {
|
||||
throw new Error(`render_${componentName} not found in WASM exports`);
|
||||
// Call the main entry point (which renders top-level component and sets root)
|
||||
const mainFn = instance.exports.main;
|
||||
if (!mainFn) {
|
||||
throw new Error(`main function not found in WASM exports`);
|
||||
}
|
||||
|
||||
// Pass props as positional arguments
|
||||
const propValues = Object.values(props);
|
||||
renderFn(...propValues);
|
||||
mainFn();
|
||||
|
||||
// Update signals
|
||||
runtime.updateSignals();
|
||||
|
||||
Binary file not shown.
+542
-1047
File diff suppressed because it is too large.
Load diff
+20
-44
@@ -20,28 +20,19 @@ def VerticalTabs():
|
||||
setting_tab = value
|
||||
|
||||
with Div(class_="vertical-tabs"):
|
||||
# Vertical tab menu
|
||||
# Vertical tab menu - clean ternary syntax!
|
||||
with Div(class_="vertical-tab-menu"):
|
||||
if setting_tab == 0:
|
||||
with Button(class_="vertical-tab active", onclick=lambda: set_setting(0)):
|
||||
yield "⚙️ General"
|
||||
else:
|
||||
with Button(class_="vertical-tab", onclick=lambda: set_setting(0)):
|
||||
yield "⚙️ General"
|
||||
with Button(class_='vertical-tab active' if setting_tab == 0 else 'vertical-tab',
|
||||
onclick=lambda: set_setting(0)):
|
||||
yield "⚙️ General"
|
||||
|
||||
if setting_tab == 1:
|
||||
with Button(class_="vertical-tab active", onclick=lambda: set_setting(1)):
|
||||
yield "🔒 Privacy"
|
||||
else:
|
||||
with Button(class_="vertical-tab", onclick=lambda: set_setting(1)):
|
||||
yield "🔒 Privacy"
|
||||
with Button(class_='vertical-tab active' if setting_tab == 1 else 'vertical-tab',
|
||||
onclick=lambda: set_setting(1)):
|
||||
yield "🔒 Privacy"
|
||||
|
||||
if setting_tab == 2:
|
||||
with Button(class_="vertical-tab active", onclick=lambda: set_setting(2)):
|
||||
yield "🚀 Advanced"
|
||||
else:
|
||||
with Button(class_="vertical-tab", onclick=lambda: set_setting(2)):
|
||||
yield "🚀 Advanced"
|
||||
with Button(class_='vertical-tab active' if setting_tab == 2 else 'vertical-tab',
|
||||
onclick=lambda: set_setting(2)):
|
||||
yield "🚀 Advanced"
|
||||
|
||||
# Vertical tab content
|
||||
with Div(class_="vertical-tab-content"):
|
||||
@@ -94,34 +85,19 @@ def Tabs(orientation=0): # 0 = horizontal, 1 = vertical
|
||||
with P(class_="subtitle"):
|
||||
yield "Beautiful composition with TabMenu and TabPane components"
|
||||
|
||||
# Tab menu - ul/li structure with active states
|
||||
# Tab menu - clean ternary syntax!
|
||||
with Ul(class_="tab-menu"):
|
||||
if tab_index == 0:
|
||||
with Li(class_="tab active"):
|
||||
with Button(onclick=lambda: set_tab(0)):
|
||||
yield "🏠 Home"
|
||||
else:
|
||||
with Li(class_="tab"):
|
||||
with Button(onclick=lambda: set_tab(0)):
|
||||
yield "🏠 Home"
|
||||
with Li(class_='tab active' if tab_index == 0 else 'tab'):
|
||||
with Button(onclick=lambda: set_tab(0)):
|
||||
yield "🏠 Home"
|
||||
|
||||
if tab_index == 1:
|
||||
with Li(class_="tab active"):
|
||||
with Button(onclick=lambda: set_tab(1)):
|
||||
yield "👤 Profile"
|
||||
else:
|
||||
with Li(class_="tab"):
|
||||
with Button(onclick=lambda: set_tab(1)):
|
||||
yield "👤 Profile"
|
||||
with Li(class_='tab active' if tab_index == 1 else 'tab'):
|
||||
with Button(onclick=lambda: set_tab(1)):
|
||||
yield "👤 Profile"
|
||||
|
||||
if tab_index == 2:
|
||||
with Li(class_="tab active"):
|
||||
with Button(onclick=lambda: set_tab(2)):
|
||||
yield "⚙️ Settings"
|
||||
else:
|
||||
with Li(class_="tab"):
|
||||
with Button(onclick=lambda: set_tab(2)):
|
||||
yield "⚙️ Settings"
|
||||
with Li(class_='tab active' if tab_index == 2 else 'tab'):
|
||||
with Button(onclick=lambda: set_tab(2)):
|
||||
yield "⚙️ Settings"
|
||||
|
||||
# Tab panes - match/case for clean switching
|
||||
with Div(class_="tab-content"):
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,70 @@
|
||||
"""
|
||||
Cleaner Tabs implementation using wrapper components to reduce repetition.
|
||||
"""
|
||||
|
||||
from ritz.syntax import *
|
||||
|
||||
|
||||
@component
|
||||
def VerticalTab(label, is_active, tab_value):
|
||||
"""Reusable vertical tab button with active state handling."""
|
||||
# Note: In current implementation, we still need the if/else for class
|
||||
# But it's encapsulated in one place instead of repeated everywhere
|
||||
if is_active:
|
||||
with Button(class_="vertical-tab active"):
|
||||
yield label
|
||||
else:
|
||||
with Button(class_="vertical-tab"):
|
||||
yield label
|
||||
|
||||
|
||||
@component
|
||||
def VerticalTabs():
|
||||
"""Vertical tabs for settings categories."""
|
||||
setting_tab = signal(0)
|
||||
|
||||
def set_setting(value):
|
||||
setting_tab = value
|
||||
|
||||
with Div(class_="vertical-tabs"):
|
||||
# Vertical tab menu
|
||||
with Div(class_="vertical-tab-menu"):
|
||||
# Now each tab is just one line instead of 6!
|
||||
yield VerticalTab("⚙️ General", setting_tab == 0, 0)
|
||||
yield VerticalTab("🔒 Privacy", setting_tab == 1, 1)
|
||||
yield VerticalTab("🚀 Advanced", setting_tab == 2, 2)
|
||||
|
||||
# Tab content (same as before)
|
||||
with Div(class_="vertical-tab-content"):
|
||||
match setting_tab:
|
||||
case 0:
|
||||
with Div(class_="setting-pane"):
|
||||
with H3():
|
||||
yield "⚙️ General Settings"
|
||||
with P():
|
||||
yield "Language: English"
|
||||
with P():
|
||||
yield "Time Zone: UTC"
|
||||
|
||||
case 1:
|
||||
with Div(class_="setting-pane"):
|
||||
with H3():
|
||||
yield "🔒 Privacy Settings"
|
||||
with P():
|
||||
yield "Data Collection: Disabled"
|
||||
with P():
|
||||
yield "Analytics: Opt-out"
|
||||
|
||||
case 2:
|
||||
with Div(class_="setting-pane"):
|
||||
with H3():
|
||||
yield "🚀 Advanced Settings"
|
||||
with P():
|
||||
yield "Debug Mode: Off"
|
||||
with P():
|
||||
yield "Experimental Features: Disabled"
|
||||
|
||||
case _:
|
||||
with Div(class_="setting-pane"):
|
||||
with P():
|
||||
yield "Invalid setting"
|
||||
@@ -0,0 +1,805 @@
|
||||
; Generated by Ritz Framework with Signals
|
||||
; Components: VerticalTabs, Tabs
|
||||
|
||||
; String constants
|
||||
@.str.0 = private unnamed_addr constant [4 x i8] c"div\00"
|
||||
@.str.1 = private unnamed_addr constant [6 x i8] c"class\00"
|
||||
@.str.2 = private unnamed_addr constant [13 x i8] c"setting-pane\00"
|
||||
@.str.3 = private unnamed_addr constant [3 x i8] c"h3\00"
|
||||
@.str.4 = private unnamed_addr constant [24 x i8] c"⚙️ General Settings\00"
|
||||
@.str.5 = private unnamed_addr constant [2 x i8] c"p\00"
|
||||
@.str.6 = private unnamed_addr constant [18 x i8] c"Language: English\00"
|
||||
@.str.7 = private unnamed_addr constant [15 x i8] c"Time Zone: UTC\00"
|
||||
@.str.8 = private unnamed_addr constant [22 x i8] c"🔒 Privacy Settings\00"
|
||||
@.str.9 = private unnamed_addr constant [26 x i8] c"Data Collection: Disabled\00"
|
||||
@.str.10 = private unnamed_addr constant [19 x i8] c"Analytics: Opt-out\00"
|
||||
@.str.11 = private unnamed_addr constant [23 x i8] c"🚀 Advanced Settings\00"
|
||||
@.str.12 = private unnamed_addr constant [16 x i8] c"Debug Mode: Off\00"
|
||||
@.str.13 = private unnamed_addr constant [32 x i8] c"Experimental Features: Disabled\00"
|
||||
@.str.14 = private unnamed_addr constant [16 x i8] c"Invalid setting\00"
|
||||
@.str.15 = private unnamed_addr constant [14 x i8] c"vertical-tabs\00"
|
||||
@.str.16 = private unnamed_addr constant [18 x i8] c"vertical-tab-menu\00"
|
||||
@.str.17 = private unnamed_addr constant [7 x i8] c"button\00"
|
||||
@.str.18 = private unnamed_addr constant [20 x i8] c"vertical-tab active\00"
|
||||
@.str.19 = private unnamed_addr constant [13 x i8] c"vertical-tab\00"
|
||||
@.str.20 = private unnamed_addr constant [6 x i8] c"click\00"
|
||||
@.str.21 = private unnamed_addr constant [23 x i8] c"_lambda_0_VerticalTabs\00"
|
||||
@.str.22 = private unnamed_addr constant [15 x i8] c"⚙️ General\00"
|
||||
@.str.23 = private unnamed_addr constant [23 x i8] c"_lambda_1_VerticalTabs\00"
|
||||
@.str.24 = private unnamed_addr constant [13 x i8] c"🔒 Privacy\00"
|
||||
@.str.25 = private unnamed_addr constant [23 x i8] c"_lambda_2_VerticalTabs\00"
|
||||
@.str.26 = private unnamed_addr constant [14 x i8] c"🚀 Advanced\00"
|
||||
@.str.27 = private unnamed_addr constant [21 x i8] c"vertical-tab-content\00"
|
||||
@.str.28 = private unnamed_addr constant [14 x i8] c"tab-pane home\00"
|
||||
@.str.29 = private unnamed_addr constant [3 x i8] c"h2\00"
|
||||
@.str.30 = private unnamed_addr constant [18 x i8] c"🏠 Welcome Home\00"
|
||||
@.str.31 = private unnamed_addr constant [29 x i8] c"This is your home dashboard.\00"
|
||||
@.str.32 = private unnamed_addr constant [17 x i8] c"tab-pane profile\00"
|
||||
@.str.33 = private unnamed_addr constant [18 x i8] c"👤 Your Profile\00"
|
||||
@.str.34 = private unnamed_addr constant [30 x i8] c"Manage your account settings.\00"
|
||||
@.str.35 = private unnamed_addr constant [18 x i8] c"tab-pane settings\00"
|
||||
@.str.36 = private unnamed_addr constant [16 x i8] c"⚙️ Settings\00"
|
||||
@.str.37 = private unnamed_addr constant [55 x i8] c"Configure your preferences using the categories below:\00"
|
||||
@.str.38 = private unnamed_addr constant [15 x i8] c"tab-pane error\00"
|
||||
@.str.39 = private unnamed_addr constant [28 x i8] c"⚠️ Invalid tab selected\00"
|
||||
@.str.40 = private unnamed_addr constant [15 x i8] c"tabs-container\00"
|
||||
@.str.41 = private unnamed_addr constant [3 x i8] c"h1\00"
|
||||
@.str.42 = private unnamed_addr constant [19 x i8] c"Tab Component Demo\00"
|
||||
@.str.43 = private unnamed_addr constant [9 x i8] c"subtitle\00"
|
||||
@.str.44 = private unnamed_addr constant [47 x i8] c"Beautiful composition with ternary expressions\00"
|
||||
@.str.45 = private unnamed_addr constant [3 x i8] c"ul\00"
|
||||
@.str.46 = private unnamed_addr constant [9 x i8] c"tab-menu\00"
|
||||
@.str.47 = private unnamed_addr constant [3 x i8] c"li\00"
|
||||
@.str.48 = private unnamed_addr constant [11 x i8] c"tab active\00"
|
||||
@.str.49 = private unnamed_addr constant [4 x i8] c"tab\00"
|
||||
@.str.50 = private unnamed_addr constant [15 x i8] c"_lambda_0_Tabs\00"
|
||||
@.str.51 = private unnamed_addr constant [10 x i8] c"🏠 Home\00"
|
||||
@.str.52 = private unnamed_addr constant [15 x i8] c"_lambda_1_Tabs\00"
|
||||
@.str.53 = private unnamed_addr constant [13 x i8] c"👤 Profile\00"
|
||||
@.str.54 = private unnamed_addr constant [15 x i8] c"_lambda_2_Tabs\00"
|
||||
@.str.55 = private unnamed_addr constant [12 x i8] c"tab-content\00"
|
||||
|
||||
; JavaScript bridge function declarations
|
||||
declare i32 @js_create_element(i8*)
|
||||
declare i32 @js_create_text(i8*)
|
||||
declare void @js_append_child(i32, i32)
|
||||
declare void @js_set_attribute(i32, i8*, i8*)
|
||||
declare void @js_set_root(i32)
|
||||
declare void @js_bind_event(i32, i8*, i8*)
|
||||
declare void @js_update_text_content(i32, i8*)
|
||||
declare i32 @js_create_marker()
|
||||
declare void @js_replace_at_marker(i32, i32, i32)
|
||||
|
||||
; Signal storage for VerticalTabs (reactive state in WASM memory)
|
||||
@signal_VerticalTabs_setting_tab = global i32 0
|
||||
|
||||
; Conditional rendering state
|
||||
@cond_0_marker = global i32 0
|
||||
@cond_0_current = global i32 0
|
||||
@cond_0_case_0_root = global i32 0
|
||||
@cond_0_case_1_root = global i32 0
|
||||
@cond_0_case_2_root = global i32 0
|
||||
@cond_0_case_3_root = global i32 0
|
||||
|
||||
; Signal helper functions
|
||||
define i32 @get_setting_tab() {
|
||||
entry:
|
||||
%val = load i32, i32* @signal_VerticalTabs_setting_tab
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define void @set_setting_tab(i32 %newval) {
|
||||
entry:
|
||||
store i32 %newval, i32* @signal_VerticalTabs_setting_tab
|
||||
; TODO: Trigger DOM update callback
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: _lambda_0_VerticalTabs
|
||||
define void @_lambda_0_VerticalTabs() {
|
||||
entry:
|
||||
call void @set_setting(i32 0)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: _lambda_1_VerticalTabs
|
||||
define void @_lambda_1_VerticalTabs() {
|
||||
entry:
|
||||
call void @set_setting(i32 1)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: _lambda_2_VerticalTabs
|
||||
define void @_lambda_2_VerticalTabs() {
|
||||
entry:
|
||||
call void @set_setting(i32 2)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: set_setting
|
||||
define void @set_setting(i32 %value) {
|
||||
entry:
|
||||
store i32 %value, i32* @signal_VerticalTabs_setting_tab
|
||||
call void @reevaluate_conditional_0()
|
||||
ret void
|
||||
}
|
||||
|
||||
; Initialize conditional 0 (match)
|
||||
define void @_init_conditional_0() {
|
||||
entry:
|
||||
; Render all cases upfront
|
||||
%var0 = call i32 @_render_cond_0_case_0()
|
||||
store i32 %var0, i32* @cond_0_case_0_root
|
||||
%var1 = call i32 @_render_cond_0_case_1()
|
||||
store i32 %var1, i32* @cond_0_case_1_root
|
||||
%var2 = call i32 @_render_cond_0_case_2()
|
||||
store i32 %var2, i32* @cond_0_case_2_root
|
||||
%var3 = call i32 @_render_cond_0_case_3()
|
||||
store i32 %var3, i32* @cond_0_case_3_root
|
||||
%var4 = load i32, i32* @signal_VerticalTabs_setting_tab
|
||||
%var5 = load i32, i32* @cond_0_marker
|
||||
switch i32 %var4, label %insert_case_3 [
|
||||
i32 0, label %insert_case_0
|
||||
i32 1, label %insert_case_1
|
||||
i32 2, label %insert_case_2
|
||||
]
|
||||
insert_case_0:
|
||||
call void @js_replace_at_marker(i32 %var5, i32 0, i32 %var0)
|
||||
store i32 0, i32* @cond_0_current
|
||||
ret void
|
||||
insert_case_1:
|
||||
call void @js_replace_at_marker(i32 %var5, i32 0, i32 %var1)
|
||||
store i32 1, i32* @cond_0_current
|
||||
ret void
|
||||
insert_case_2:
|
||||
call void @js_replace_at_marker(i32 %var5, i32 0, i32 %var2)
|
||||
store i32 2, i32* @cond_0_current
|
||||
ret void
|
||||
insert_case_3:
|
||||
call void @js_replace_at_marker(i32 %var5, i32 0, i32 %var3)
|
||||
store i32 3, i32* @cond_0_current
|
||||
ret void
|
||||
}
|
||||
|
||||
; Re-evaluate conditional 0 (match)
|
||||
define void @reevaluate_conditional_0() {
|
||||
entry:
|
||||
%var6 = load i32, i32* @signal_VerticalTabs_setting_tab
|
||||
%var7 = load i32, i32* @cond_0_current
|
||||
switch i32 %var6, label %case_3 [
|
||||
i32 0, label %case_0
|
||||
i32 1, label %case_1
|
||||
i32 2, label %case_2
|
||||
]
|
||||
case_0:
|
||||
%var8 = icmp ne i32 %var7, 0
|
||||
br i1 %var8, label %swap_0, label %done
|
||||
swap_0:
|
||||
%var9 = load i32, i32* @cond_0_marker
|
||||
%var10 = load i32, i32* @cond_0_case_0_root
|
||||
switch i32 %var7, label %load_old_0_3 [
|
||||
i32 0, label %load_old_0_0
|
||||
i32 1, label %load_old_0_1
|
||||
i32 2, label %load_old_0_2
|
||||
i32 3, label %load_old_0_3
|
||||
]
|
||||
load_old_0_0:
|
||||
%var12 = load i32, i32* @cond_0_case_0_root
|
||||
br label %merge_0
|
||||
load_old_0_1:
|
||||
%var13 = load i32, i32* @cond_0_case_1_root
|
||||
br label %merge_0
|
||||
load_old_0_2:
|
||||
%var14 = load i32, i32* @cond_0_case_2_root
|
||||
br label %merge_0
|
||||
load_old_0_3:
|
||||
%var15 = load i32, i32* @cond_0_case_3_root
|
||||
br label %merge_0
|
||||
merge_0:
|
||||
%var11 = phi i32 [ %var12, %load_old_0_0 ], [ %var13, %load_old_0_1 ], [ %var14, %load_old_0_2 ], [ %var15, %load_old_0_3 ]
|
||||
call void @js_replace_at_marker(i32 %var9, i32 %var11, i32 %var10)
|
||||
store i32 0, i32* @cond_0_current
|
||||
br label %done
|
||||
case_1:
|
||||
%var16 = icmp ne i32 %var7, 1
|
||||
br i1 %var16, label %swap_1, label %done
|
||||
swap_1:
|
||||
%var17 = load i32, i32* @cond_0_marker
|
||||
%var18 = load i32, i32* @cond_0_case_1_root
|
||||
switch i32 %var7, label %load_old_1_3 [
|
||||
i32 0, label %load_old_1_0
|
||||
i32 1, label %load_old_1_1
|
||||
i32 2, label %load_old_1_2
|
||||
i32 3, label %load_old_1_3
|
||||
]
|
||||
load_old_1_0:
|
||||
%var20 = load i32, i32* @cond_0_case_0_root
|
||||
br label %merge_1
|
||||
load_old_1_1:
|
||||
%var21 = load i32, i32* @cond_0_case_1_root
|
||||
br label %merge_1
|
||||
load_old_1_2:
|
||||
%var22 = load i32, i32* @cond_0_case_2_root
|
||||
br label %merge_1
|
||||
load_old_1_3:
|
||||
%var23 = load i32, i32* @cond_0_case_3_root
|
||||
br label %merge_1
|
||||
merge_1:
|
||||
%var19 = phi i32 [ %var20, %load_old_1_0 ], [ %var21, %load_old_1_1 ], [ %var22, %load_old_1_2 ], [ %var23, %load_old_1_3 ]
|
||||
call void @js_replace_at_marker(i32 %var17, i32 %var19, i32 %var18)
|
||||
store i32 1, i32* @cond_0_current
|
||||
br label %done
|
||||
case_2:
|
||||
%var24 = icmp ne i32 %var7, 2
|
||||
br i1 %var24, label %swap_2, label %done
|
||||
swap_2:
|
||||
%var25 = load i32, i32* @cond_0_marker
|
||||
%var26 = load i32, i32* @cond_0_case_2_root
|
||||
switch i32 %var7, label %load_old_2_3 [
|
||||
i32 0, label %load_old_2_0
|
||||
i32 1, label %load_old_2_1
|
||||
i32 2, label %load_old_2_2
|
||||
i32 3, label %load_old_2_3
|
||||
]
|
||||
load_old_2_0:
|
||||
%var28 = load i32, i32* @cond_0_case_0_root
|
||||
br label %merge_2
|
||||
load_old_2_1:
|
||||
%var29 = load i32, i32* @cond_0_case_1_root
|
||||
br label %merge_2
|
||||
load_old_2_2:
|
||||
%var30 = load i32, i32* @cond_0_case_2_root
|
||||
br label %merge_2
|
||||
load_old_2_3:
|
||||
%var31 = load i32, i32* @cond_0_case_3_root
|
||||
br label %merge_2
|
||||
merge_2:
|
||||
%var27 = phi i32 [ %var28, %load_old_2_0 ], [ %var29, %load_old_2_1 ], [ %var30, %load_old_2_2 ], [ %var31, %load_old_2_3 ]
|
||||
call void @js_replace_at_marker(i32 %var25, i32 %var27, i32 %var26)
|
||||
store i32 2, i32* @cond_0_current
|
||||
br label %done
|
||||
case_3:
|
||||
%var32 = icmp ne i32 %var7, 3
|
||||
br i1 %var32, label %swap_3, label %done
|
||||
swap_3:
|
||||
%var33 = load i32, i32* @cond_0_marker
|
||||
%var34 = load i32, i32* @cond_0_case_3_root
|
||||
switch i32 %var7, label %load_old_3_3 [
|
||||
i32 0, label %load_old_3_0
|
||||
i32 1, label %load_old_3_1
|
||||
i32 2, label %load_old_3_2
|
||||
i32 3, label %load_old_3_3
|
||||
]
|
||||
load_old_3_0:
|
||||
%var36 = load i32, i32* @cond_0_case_0_root
|
||||
br label %merge_3
|
||||
load_old_3_1:
|
||||
%var37 = load i32, i32* @cond_0_case_1_root
|
||||
br label %merge_3
|
||||
load_old_3_2:
|
||||
%var38 = load i32, i32* @cond_0_case_2_root
|
||||
br label %merge_3
|
||||
load_old_3_3:
|
||||
%var39 = load i32, i32* @cond_0_case_3_root
|
||||
br label %merge_3
|
||||
merge_3:
|
||||
%var35 = phi i32 [ %var36, %load_old_3_0 ], [ %var37, %load_old_3_1 ], [ %var38, %load_old_3_2 ], [ %var39, %load_old_3_3 ]
|
||||
call void @js_replace_at_marker(i32 %var33, i32 %var35, i32 %var34)
|
||||
store i32 3, i32* @cond_0_current
|
||||
br label %done
|
||||
done:
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @_render_cond_0_case_0() {
|
||||
entry:
|
||||
%var40 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var41 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var41, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0))
|
||||
%var42 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var43 = call i32 @js_create_text(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str.4, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var42, i32 %var43)
|
||||
call void @js_append_child(i32 %var41, i32 %var42)
|
||||
call void @js_append_child(i32 %var41, i32 %var42)
|
||||
%var44 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var45 = call i32 @js_create_text(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.6, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var44, i32 %var45)
|
||||
call void @js_append_child(i32 %var41, i32 %var44)
|
||||
call void @js_append_child(i32 %var41, i32 %var44)
|
||||
%var46 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var47 = call i32 @js_create_text(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.7, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var46, i32 %var47)
|
||||
call void @js_append_child(i32 %var41, i32 %var46)
|
||||
call void @js_append_child(i32 %var41, i32 %var46)
|
||||
call void @js_append_child(i32 %var40, i32 %var41)
|
||||
ret i32 %var40
|
||||
}
|
||||
|
||||
define i32 @_render_cond_0_case_1() {
|
||||
entry:
|
||||
%var48 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var49 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var49, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0))
|
||||
%var50 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var51 = call i32 @js_create_text(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.8, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var50, i32 %var51)
|
||||
call void @js_append_child(i32 %var49, i32 %var50)
|
||||
call void @js_append_child(i32 %var49, i32 %var50)
|
||||
%var52 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var53 = call i32 @js_create_text(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.9, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var52, i32 %var53)
|
||||
call void @js_append_child(i32 %var49, i32 %var52)
|
||||
call void @js_append_child(i32 %var49, i32 %var52)
|
||||
%var54 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var55 = call i32 @js_create_text(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.10, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var54, i32 %var55)
|
||||
call void @js_append_child(i32 %var49, i32 %var54)
|
||||
call void @js_append_child(i32 %var49, i32 %var54)
|
||||
call void @js_append_child(i32 %var48, i32 %var49)
|
||||
ret i32 %var48
|
||||
}
|
||||
|
||||
define i32 @_render_cond_0_case_2() {
|
||||
entry:
|
||||
%var56 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var57 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var57, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0))
|
||||
%var58 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var59 = call i32 @js_create_text(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.11, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var58, i32 %var59)
|
||||
call void @js_append_child(i32 %var57, i32 %var58)
|
||||
call void @js_append_child(i32 %var57, i32 %var58)
|
||||
%var60 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var61 = call i32 @js_create_text(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.12, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var60, i32 %var61)
|
||||
call void @js_append_child(i32 %var57, i32 %var60)
|
||||
call void @js_append_child(i32 %var57, i32 %var60)
|
||||
%var62 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var63 = call i32 @js_create_text(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @.str.13, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var62, i32 %var63)
|
||||
call void @js_append_child(i32 %var57, i32 %var62)
|
||||
call void @js_append_child(i32 %var57, i32 %var62)
|
||||
call void @js_append_child(i32 %var56, i32 %var57)
|
||||
ret i32 %var56
|
||||
}
|
||||
|
||||
define i32 @_render_cond_0_case_3() {
|
||||
entry:
|
||||
%var64 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var65 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var65, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0))
|
||||
%var66 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var67 = call i32 @js_create_text(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.14, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var66, i32 %var67)
|
||||
call void @js_append_child(i32 %var65, i32 %var66)
|
||||
call void @js_append_child(i32 %var65, i32 %var66)
|
||||
call void @js_append_child(i32 %var64, i32 %var65)
|
||||
ret i32 %var64
|
||||
}
|
||||
|
||||
; Component render function
|
||||
define void @render_VerticalTabs() {
|
||||
entry:
|
||||
%var68 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var68, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.15, i32 0, i32 0))
|
||||
%var69 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var69, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.16, i32 0, i32 0))
|
||||
%var70 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.17, i32 0, i32 0))
|
||||
%var71 = load i32, i32* @signal_VerticalTabs_setting_tab
|
||||
%var72 = icmp eq i32 %var71, 0
|
||||
%var73 = zext i1 %var72 to i32
|
||||
%var74 = icmp ne i32 %var73, 0
|
||||
%var75 = select i1 %var74, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.18, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0)
|
||||
call void @js_set_attribute(i32 %var70, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* %var75)
|
||||
call void @js_bind_event(i32 %var70, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.20, i32 0, i32 0), i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.21, i32 0, i32 0))
|
||||
%var76 = call i32 @js_create_text(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.22, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var70, i32 %var76)
|
||||
call void @js_append_child(i32 %var69, i32 %var70)
|
||||
call void @js_append_child(i32 %var69, i32 %var70)
|
||||
%var77 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.17, i32 0, i32 0))
|
||||
%var78 = load i32, i32* @signal_VerticalTabs_setting_tab
|
||||
%var79 = icmp eq i32 %var78, 1
|
||||
%var80 = zext i1 %var79 to i32
|
||||
%var81 = icmp ne i32 %var80, 0
|
||||
%var82 = select i1 %var81, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.18, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0)
|
||||
call void @js_set_attribute(i32 %var77, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* %var82)
|
||||
call void @js_bind_event(i32 %var77, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.20, i32 0, i32 0), i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.23, i32 0, i32 0))
|
||||
%var83 = call i32 @js_create_text(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.24, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var77, i32 %var83)
|
||||
call void @js_append_child(i32 %var69, i32 %var77)
|
||||
call void @js_append_child(i32 %var69, i32 %var77)
|
||||
%var84 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.17, i32 0, i32 0))
|
||||
%var85 = load i32, i32* @signal_VerticalTabs_setting_tab
|
||||
%var86 = icmp eq i32 %var85, 2
|
||||
%var87 = zext i1 %var86 to i32
|
||||
%var88 = icmp ne i32 %var87, 0
|
||||
%var89 = select i1 %var88, i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str.18, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.19, i32 0, i32 0)
|
||||
call void @js_set_attribute(i32 %var84, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* %var89)
|
||||
call void @js_bind_event(i32 %var84, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.20, i32 0, i32 0), i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.25, i32 0, i32 0))
|
||||
%var90 = call i32 @js_create_text(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.26, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var84, i32 %var90)
|
||||
call void @js_append_child(i32 %var69, i32 %var84)
|
||||
call void @js_append_child(i32 %var69, i32 %var84)
|
||||
call void @js_append_child(i32 %var68, i32 %var69)
|
||||
call void @js_append_child(i32 %var68, i32 %var69)
|
||||
%var91 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var91, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.27, i32 0, i32 0))
|
||||
%var92 = call i32 @js_create_marker()
|
||||
call void @js_append_child(i32 %var91, i32 %var92)
|
||||
store i32 %var92, i32* @cond_0_marker
|
||||
call void @_init_conditional_0()
|
||||
call void @js_append_child(i32 %var68, i32 %var91)
|
||||
call void @js_append_child(i32 %var68, i32 %var91)
|
||||
call void @js_set_root(i32 %var68)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Signal storage for Tabs (reactive state in WASM memory)
|
||||
@signal_Tabs_tab_index = global i32 0
|
||||
|
||||
; Conditional rendering state
|
||||
@cond_1_marker = global i32 0
|
||||
@cond_1_current = global i32 0
|
||||
@cond_1_case_0_root = global i32 0
|
||||
@cond_1_case_1_root = global i32 0
|
||||
@cond_1_case_2_root = global i32 0
|
||||
@cond_1_case_3_root = global i32 0
|
||||
|
||||
; Signal helper functions
|
||||
define i32 @get_tab_index() {
|
||||
entry:
|
||||
%val = load i32, i32* @signal_Tabs_tab_index
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define void @set_tab_index(i32 %newval) {
|
||||
entry:
|
||||
store i32 %newval, i32* @signal_Tabs_tab_index
|
||||
; TODO: Trigger DOM update callback
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: _lambda_0_Tabs
|
||||
define void @_lambda_0_Tabs() {
|
||||
entry:
|
||||
call void @set_tab(i32 0)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: _lambda_1_Tabs
|
||||
define void @_lambda_1_Tabs() {
|
||||
entry:
|
||||
call void @set_tab(i32 1)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: _lambda_2_Tabs
|
||||
define void @_lambda_2_Tabs() {
|
||||
entry:
|
||||
call void @set_tab(i32 2)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Event handler: set_tab
|
||||
define void @set_tab(i32 %value) {
|
||||
entry:
|
||||
store i32 %value, i32* @signal_Tabs_tab_index
|
||||
call void @reevaluate_conditional_1()
|
||||
ret void
|
||||
}
|
||||
|
||||
; Initialize conditional 1 (match)
|
||||
define void @_init_conditional_1() {
|
||||
entry:
|
||||
; Render all cases upfront
|
||||
%var93 = call i32 @_render_cond_1_case_0()
|
||||
store i32 %var93, i32* @cond_1_case_0_root
|
||||
%var94 = call i32 @_render_cond_1_case_1()
|
||||
store i32 %var94, i32* @cond_1_case_1_root
|
||||
%var95 = call i32 @_render_cond_1_case_2()
|
||||
store i32 %var95, i32* @cond_1_case_2_root
|
||||
%var96 = call i32 @_render_cond_1_case_3()
|
||||
store i32 %var96, i32* @cond_1_case_3_root
|
||||
%var97 = load i32, i32* @signal_Tabs_tab_index
|
||||
%var98 = load i32, i32* @cond_1_marker
|
||||
switch i32 %var97, label %insert_case_3 [
|
||||
i32 0, label %insert_case_0
|
||||
i32 1, label %insert_case_1
|
||||
i32 2, label %insert_case_2
|
||||
]
|
||||
insert_case_0:
|
||||
call void @js_replace_at_marker(i32 %var98, i32 0, i32 %var93)
|
||||
store i32 0, i32* @cond_1_current
|
||||
ret void
|
||||
insert_case_1:
|
||||
call void @js_replace_at_marker(i32 %var98, i32 0, i32 %var94)
|
||||
store i32 1, i32* @cond_1_current
|
||||
ret void
|
||||
insert_case_2:
|
||||
call void @js_replace_at_marker(i32 %var98, i32 0, i32 %var95)
|
||||
store i32 2, i32* @cond_1_current
|
||||
ret void
|
||||
insert_case_3:
|
||||
call void @js_replace_at_marker(i32 %var98, i32 0, i32 %var96)
|
||||
store i32 3, i32* @cond_1_current
|
||||
ret void
|
||||
}
|
||||
|
||||
; Re-evaluate conditional 1 (match)
|
||||
define void @reevaluate_conditional_1() {
|
||||
entry:
|
||||
%var99 = load i32, i32* @signal_Tabs_tab_index
|
||||
%var100 = load i32, i32* @cond_1_current
|
||||
switch i32 %var99, label %case_3 [
|
||||
i32 0, label %case_0
|
||||
i32 1, label %case_1
|
||||
i32 2, label %case_2
|
||||
]
|
||||
case_0:
|
||||
%var101 = icmp ne i32 %var100, 0
|
||||
br i1 %var101, label %swap_0, label %done
|
||||
swap_0:
|
||||
%var102 = load i32, i32* @cond_1_marker
|
||||
%var103 = load i32, i32* @cond_1_case_0_root
|
||||
switch i32 %var100, label %load_old_0_3 [
|
||||
i32 0, label %load_old_0_0
|
||||
i32 1, label %load_old_0_1
|
||||
i32 2, label %load_old_0_2
|
||||
i32 3, label %load_old_0_3
|
||||
]
|
||||
load_old_0_0:
|
||||
%var105 = load i32, i32* @cond_1_case_0_root
|
||||
br label %merge_0
|
||||
load_old_0_1:
|
||||
%var106 = load i32, i32* @cond_1_case_1_root
|
||||
br label %merge_0
|
||||
load_old_0_2:
|
||||
%var107 = load i32, i32* @cond_1_case_2_root
|
||||
br label %merge_0
|
||||
load_old_0_3:
|
||||
%var108 = load i32, i32* @cond_1_case_3_root
|
||||
br label %merge_0
|
||||
merge_0:
|
||||
%var104 = phi i32 [ %var105, %load_old_0_0 ], [ %var106, %load_old_0_1 ], [ %var107, %load_old_0_2 ], [ %var108, %load_old_0_3 ]
|
||||
call void @js_replace_at_marker(i32 %var102, i32 %var104, i32 %var103)
|
||||
store i32 0, i32* @cond_1_current
|
||||
br label %done
|
||||
case_1:
|
||||
%var109 = icmp ne i32 %var100, 1
|
||||
br i1 %var109, label %swap_1, label %done
|
||||
swap_1:
|
||||
%var110 = load i32, i32* @cond_1_marker
|
||||
%var111 = load i32, i32* @cond_1_case_1_root
|
||||
switch i32 %var100, label %load_old_1_3 [
|
||||
i32 0, label %load_old_1_0
|
||||
i32 1, label %load_old_1_1
|
||||
i32 2, label %load_old_1_2
|
||||
i32 3, label %load_old_1_3
|
||||
]
|
||||
load_old_1_0:
|
||||
%var113 = load i32, i32* @cond_1_case_0_root
|
||||
br label %merge_1
|
||||
load_old_1_1:
|
||||
%var114 = load i32, i32* @cond_1_case_1_root
|
||||
br label %merge_1
|
||||
load_old_1_2:
|
||||
%var115 = load i32, i32* @cond_1_case_2_root
|
||||
br label %merge_1
|
||||
load_old_1_3:
|
||||
%var116 = load i32, i32* @cond_1_case_3_root
|
||||
br label %merge_1
|
||||
merge_1:
|
||||
%var112 = phi i32 [ %var113, %load_old_1_0 ], [ %var114, %load_old_1_1 ], [ %var115, %load_old_1_2 ], [ %var116, %load_old_1_3 ]
|
||||
call void @js_replace_at_marker(i32 %var110, i32 %var112, i32 %var111)
|
||||
store i32 1, i32* @cond_1_current
|
||||
br label %done
|
||||
case_2:
|
||||
%var117 = icmp ne i32 %var100, 2
|
||||
br i1 %var117, label %swap_2, label %done
|
||||
swap_2:
|
||||
%var118 = load i32, i32* @cond_1_marker
|
||||
%var119 = load i32, i32* @cond_1_case_2_root
|
||||
switch i32 %var100, label %load_old_2_3 [
|
||||
i32 0, label %load_old_2_0
|
||||
i32 1, label %load_old_2_1
|
||||
i32 2, label %load_old_2_2
|
||||
i32 3, label %load_old_2_3
|
||||
]
|
||||
load_old_2_0:
|
||||
%var121 = load i32, i32* @cond_1_case_0_root
|
||||
br label %merge_2
|
||||
load_old_2_1:
|
||||
%var122 = load i32, i32* @cond_1_case_1_root
|
||||
br label %merge_2
|
||||
load_old_2_2:
|
||||
%var123 = load i32, i32* @cond_1_case_2_root
|
||||
br label %merge_2
|
||||
load_old_2_3:
|
||||
%var124 = load i32, i32* @cond_1_case_3_root
|
||||
br label %merge_2
|
||||
merge_2:
|
||||
%var120 = phi i32 [ %var121, %load_old_2_0 ], [ %var122, %load_old_2_1 ], [ %var123, %load_old_2_2 ], [ %var124, %load_old_2_3 ]
|
||||
call void @js_replace_at_marker(i32 %var118, i32 %var120, i32 %var119)
|
||||
store i32 2, i32* @cond_1_current
|
||||
br label %done
|
||||
case_3:
|
||||
%var125 = icmp ne i32 %var100, 3
|
||||
br i1 %var125, label %swap_3, label %done
|
||||
swap_3:
|
||||
%var126 = load i32, i32* @cond_1_marker
|
||||
%var127 = load i32, i32* @cond_1_case_3_root
|
||||
switch i32 %var100, label %load_old_3_3 [
|
||||
i32 0, label %load_old_3_0
|
||||
i32 1, label %load_old_3_1
|
||||
i32 2, label %load_old_3_2
|
||||
i32 3, label %load_old_3_3
|
||||
]
|
||||
load_old_3_0:
|
||||
%var129 = load i32, i32* @cond_1_case_0_root
|
||||
br label %merge_3
|
||||
load_old_3_1:
|
||||
%var130 = load i32, i32* @cond_1_case_1_root
|
||||
br label %merge_3
|
||||
load_old_3_2:
|
||||
%var131 = load i32, i32* @cond_1_case_2_root
|
||||
br label %merge_3
|
||||
load_old_3_3:
|
||||
%var132 = load i32, i32* @cond_1_case_3_root
|
||||
br label %merge_3
|
||||
merge_3:
|
||||
%var128 = phi i32 [ %var129, %load_old_3_0 ], [ %var130, %load_old_3_1 ], [ %var131, %load_old_3_2 ], [ %var132, %load_old_3_3 ]
|
||||
call void @js_replace_at_marker(i32 %var126, i32 %var128, i32 %var127)
|
||||
store i32 3, i32* @cond_1_current
|
||||
br label %done
|
||||
done:
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @_render_cond_1_case_0() {
|
||||
entry:
|
||||
%var133 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var134 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var134, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.28, i32 0, i32 0))
|
||||
%var135 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.29, i32 0, i32 0))
|
||||
%var136 = call i32 @js_create_text(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.30, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var135, i32 %var136)
|
||||
call void @js_append_child(i32 %var134, i32 %var135)
|
||||
call void @js_append_child(i32 %var134, i32 %var135)
|
||||
%var137 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var138 = call i32 @js_create_text(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @.str.31, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var137, i32 %var138)
|
||||
call void @js_append_child(i32 %var134, i32 %var137)
|
||||
call void @js_append_child(i32 %var134, i32 %var137)
|
||||
call void @js_append_child(i32 %var133, i32 %var134)
|
||||
ret i32 %var133
|
||||
}
|
||||
|
||||
define i32 @_render_cond_1_case_1() {
|
||||
entry:
|
||||
%var139 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var140 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var140, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.32, i32 0, i32 0))
|
||||
%var141 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.29, i32 0, i32 0))
|
||||
%var142 = call i32 @js_create_text(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.33, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var141, i32 %var142)
|
||||
call void @js_append_child(i32 %var140, i32 %var141)
|
||||
call void @js_append_child(i32 %var140, i32 %var141)
|
||||
%var143 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var144 = call i32 @js_create_text(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @.str.34, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var143, i32 %var144)
|
||||
call void @js_append_child(i32 %var140, i32 %var143)
|
||||
call void @js_append_child(i32 %var140, i32 %var143)
|
||||
call void @js_append_child(i32 %var139, i32 %var140)
|
||||
ret i32 %var139
|
||||
}
|
||||
|
||||
define i32 @_render_cond_1_case_2() {
|
||||
entry:
|
||||
%var145 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var146 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var146, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.35, i32 0, i32 0))
|
||||
%var147 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.29, i32 0, i32 0))
|
||||
%var148 = call i32 @js_create_text(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.36, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var147, i32 %var148)
|
||||
call void @js_append_child(i32 %var146, i32 %var147)
|
||||
call void @js_append_child(i32 %var146, i32 %var147)
|
||||
%var149 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var150 = call i32 @js_create_text(i8* getelementptr inbounds ([55 x i8], [55 x i8]* @.str.37, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var149, i32 %var150)
|
||||
call void @js_append_child(i32 %var146, i32 %var149)
|
||||
call void @js_append_child(i32 %var146, i32 %var149)
|
||||
call void @render_VerticalTabs()
|
||||
call void @js_append_child(i32 %var145, i32 %var146)
|
||||
ret i32 %var145
|
||||
}
|
||||
|
||||
define i32 @_render_cond_1_case_3() {
|
||||
entry:
|
||||
%var151 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var152 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var152, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.38, i32 0, i32 0))
|
||||
%var153 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
%var154 = call i32 @js_create_text(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.str.39, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var153, i32 %var154)
|
||||
call void @js_append_child(i32 %var152, i32 %var153)
|
||||
call void @js_append_child(i32 %var152, i32 %var153)
|
||||
call void @js_append_child(i32 %var151, i32 %var152)
|
||||
ret i32 %var151
|
||||
}
|
||||
|
||||
; Component render function
|
||||
define void @render_Tabs() {
|
||||
entry:
|
||||
%var155 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var155, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.40, i32 0, i32 0))
|
||||
%var156 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.41, i32 0, i32 0))
|
||||
%var157 = call i32 @js_create_text(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str.42, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var156, i32 %var157)
|
||||
call void @js_append_child(i32 %var155, i32 %var156)
|
||||
call void @js_append_child(i32 %var155, i32 %var156)
|
||||
%var158 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var158, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.43, i32 0, i32 0))
|
||||
%var159 = call i32 @js_create_text(i8* getelementptr inbounds ([47 x i8], [47 x i8]* @.str.44, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var158, i32 %var159)
|
||||
call void @js_append_child(i32 %var155, i32 %var158)
|
||||
call void @js_append_child(i32 %var155, i32 %var158)
|
||||
%var160 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.45, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var160, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.46, i32 0, i32 0))
|
||||
%var161 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.47, i32 0, i32 0))
|
||||
%var162 = load i32, i32* @signal_Tabs_tab_index
|
||||
%var163 = icmp eq i32 %var162, 0
|
||||
%var164 = zext i1 %var163 to i32
|
||||
%var165 = icmp ne i32 %var164, 0
|
||||
%var166 = select i1 %var165, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.48, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.49, i32 0, i32 0)
|
||||
call void @js_set_attribute(i32 %var161, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* %var166)
|
||||
%var167 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.17, i32 0, i32 0))
|
||||
call void @js_bind_event(i32 %var167, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.20, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.50, i32 0, i32 0))
|
||||
%var168 = call i32 @js_create_text(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.51, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var167, i32 %var168)
|
||||
call void @js_append_child(i32 %var161, i32 %var167)
|
||||
call void @js_append_child(i32 %var161, i32 %var167)
|
||||
call void @js_append_child(i32 %var160, i32 %var161)
|
||||
call void @js_append_child(i32 %var160, i32 %var161)
|
||||
%var169 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.47, i32 0, i32 0))
|
||||
%var170 = load i32, i32* @signal_Tabs_tab_index
|
||||
%var171 = icmp eq i32 %var170, 1
|
||||
%var172 = zext i1 %var171 to i32
|
||||
%var173 = icmp ne i32 %var172, 0
|
||||
%var174 = select i1 %var173, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.48, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.49, i32 0, i32 0)
|
||||
call void @js_set_attribute(i32 %var169, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* %var174)
|
||||
%var175 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.17, i32 0, i32 0))
|
||||
call void @js_bind_event(i32 %var175, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.20, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.52, i32 0, i32 0))
|
||||
%var176 = call i32 @js_create_text(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.53, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var175, i32 %var176)
|
||||
call void @js_append_child(i32 %var169, i32 %var175)
|
||||
call void @js_append_child(i32 %var169, i32 %var175)
|
||||
call void @js_append_child(i32 %var160, i32 %var169)
|
||||
call void @js_append_child(i32 %var160, i32 %var169)
|
||||
%var177 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.47, i32 0, i32 0))
|
||||
%var178 = load i32, i32* @signal_Tabs_tab_index
|
||||
%var179 = icmp eq i32 %var178, 2
|
||||
%var180 = zext i1 %var179 to i32
|
||||
%var181 = icmp ne i32 %var180, 0
|
||||
%var182 = select i1 %var181, i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.48, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.49, i32 0, i32 0)
|
||||
call void @js_set_attribute(i32 %var177, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* %var182)
|
||||
%var183 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.17, i32 0, i32 0))
|
||||
call void @js_bind_event(i32 %var183, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.20, i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.54, i32 0, i32 0))
|
||||
%var184 = call i32 @js_create_text(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.36, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var183, i32 %var184)
|
||||
call void @js_append_child(i32 %var177, i32 %var183)
|
||||
call void @js_append_child(i32 %var177, i32 %var183)
|
||||
call void @js_append_child(i32 %var160, i32 %var177)
|
||||
call void @js_append_child(i32 %var160, i32 %var177)
|
||||
call void @js_append_child(i32 %var155, i32 %var160)
|
||||
call void @js_append_child(i32 %var155, i32 %var160)
|
||||
%var185 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var185, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.55, i32 0, i32 0))
|
||||
%var186 = call i32 @js_create_marker()
|
||||
call void @js_append_child(i32 %var185, i32 %var186)
|
||||
store i32 %var186, i32* @cond_1_marker
|
||||
call void @_init_conditional_1()
|
||||
call void @js_append_child(i32 %var155, i32 %var185)
|
||||
call void @js_append_child(i32 %var155, i32 %var185)
|
||||
call void @js_set_root(i32 %var155)
|
||||
ret void
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Ritz Runtime - WebAssembly DOM Bridge
|
||||
*
|
||||
* Provides the runtime environment for Ritz components compiled to WASM.
|
||||
*/
|
||||
|
||||
class RitzRuntime {
|
||||
constructor(rootElement) {
|
||||
this.rootElement = rootElement || document.getElementById('app');
|
||||
this.nodes = new Map();
|
||||
this.nextNodeId = 1;
|
||||
this.log = [];
|
||||
this.wasmInstance = null;
|
||||
this.debugEnabled = true;
|
||||
}
|
||||
|
||||
// ===== DOM Manipulation Bridge =====
|
||||
|
||||
js_create_element(tagPtr) {
|
||||
const tag = this.readString(tagPtr);
|
||||
const element = document.createElement(tag);
|
||||
const id = this.nextNodeId++;
|
||||
this.nodes.set(id, element);
|
||||
this._log(`createElement("${tag}") = ${id}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
js_create_text(textPtr) {
|
||||
const text = this.readString(textPtr);
|
||||
const textNode = document.createTextNode(text);
|
||||
const id = this.nextNodeId++;
|
||||
this.nodes.set(id, textNode);
|
||||
this._log(`createTextNode("${text}") = ${id}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
js_append_child(parentId, childId) {
|
||||
const parent = this.nodes.get(parentId);
|
||||
const child = this.nodes.get(childId);
|
||||
if (parent && child) {
|
||||
parent.appendChild(child);
|
||||
this._log(`appendChild(${parentId}, ${childId})`);
|
||||
}
|
||||
}
|
||||
|
||||
js_set_attribute(elemId, namePtr, valuePtr) {
|
||||
const element = this.nodes.get(elemId);
|
||||
const name = this.readString(namePtr);
|
||||
const value = this.readString(valuePtr);
|
||||
if (element) {
|
||||
if (name === 'class') {
|
||||
element.className = value;
|
||||
} else {
|
||||
element.setAttribute(name, value);
|
||||
}
|
||||
this._log(`setAttribute(${elemId}, "${name}", "${value}")`);
|
||||
}
|
||||
}
|
||||
|
||||
js_bind_event(elemId, eventNamePtr, handlerNamePtr) {
|
||||
const element = this.nodes.get(elemId);
|
||||
const eventName = this.readString(eventNamePtr);
|
||||
const handlerName = this.readString(handlerNamePtr);
|
||||
|
||||
if (element && this.wasmInstance) {
|
||||
const handler = this.wasmInstance.exports[handlerName];
|
||||
if (handler) {
|
||||
element.addEventListener(eventName, () => {
|
||||
this._log(`[Event] ${eventName} → ${handlerName}()`);
|
||||
handler();
|
||||
this.updateSignals();
|
||||
});
|
||||
this._log(`bindEvent(${elemId}, "${eventName}", "${handlerName}")`);
|
||||
} else {
|
||||
console.error(`Handler ${handlerName} not found in WASM exports`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
js_set_root(elemId) {
|
||||
const element = this.nodes.get(elemId);
|
||||
if (element) {
|
||||
this.rootElement.innerHTML = '';
|
||||
this.rootElement.appendChild(element);
|
||||
this._log(`setRoot(${elemId})`);
|
||||
}
|
||||
}
|
||||
|
||||
js_update_text_content(nodeId, textPtr) {
|
||||
const node = this.nodes.get(nodeId);
|
||||
const text = this.readString(textPtr);
|
||||
if (node) {
|
||||
node.textContent = text;
|
||||
this._log(`updateTextContent(${nodeId}, "${text}")`);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Signal Management =====
|
||||
|
||||
updateSignals() {
|
||||
// Discover and update all signals
|
||||
if (!this.wasmInstance) return;
|
||||
|
||||
const exports = this.wasmInstance.exports;
|
||||
|
||||
// Find all get_* functions (signal getters)
|
||||
for (const [name, fn] of Object.entries(exports)) {
|
||||
if (name.startsWith('get_') && typeof fn === 'function') {
|
||||
const signalName = name.substring(4); // Remove 'get_' prefix
|
||||
const value = fn();
|
||||
this._log(`[Signal] ${signalName} = ${value}`);
|
||||
|
||||
// Update DOM elements bound to this signal
|
||||
// TODO: Track signal-to-DOM bindings during render for efficiency
|
||||
this.updateSignalDisplay(signalName, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-evaluate all reactive conditionals
|
||||
for (const [name, fn] of Object.entries(exports)) {
|
||||
if (name.startsWith('reevaluate_conditional_') && typeof fn === 'function') {
|
||||
fn();
|
||||
this._log(`[Reactive] ${name}()`);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-evaluate all reactive match statements
|
||||
for (const [name, fn] of Object.entries(exports)) {
|
||||
if (name.startsWith('reevaluate_match_') && typeof fn === 'function') {
|
||||
fn();
|
||||
this._log(`[Reactive] ${name}()`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateSignalDisplay(signalName, value) {
|
||||
// Find DOM elements that should display this signal
|
||||
// For now, update any element with class matching signal name or data-signal attribute
|
||||
const selectors = [
|
||||
`[data-signal="${signalName}"]`,
|
||||
`.${signalName}`,
|
||||
'.count', // Hardcoded for demo - TODO: track bindings properly
|
||||
];
|
||||
|
||||
selectors.forEach(selector => {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
elements.forEach(el => {
|
||||
// Check if text contains the signal name or looks like a counter
|
||||
const text = el.textContent;
|
||||
if (text.includes(signalName) || text.match(/\d+/)) {
|
||||
// Replace the number in the text
|
||||
el.textContent = text.replace(/\d+/, value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Reactive Conditional Rendering =====
|
||||
|
||||
js_create_marker() {
|
||||
// Create a comment node as a marker for conditional insertion
|
||||
const marker = document.createComment('conditional-marker');
|
||||
const id = this.nextNodeId++;
|
||||
this.nodes.set(id, marker);
|
||||
this._log(`Created marker node ${id}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
js_replace_at_marker(markerId, oldNodeId, newNodeId) {
|
||||
// Replace DOM node at marker position
|
||||
const marker = this.nodes.get(markerId);
|
||||
if (!marker) {
|
||||
console.error(`[replace_at_marker] Marker ${markerId} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
const parent = marker.parentNode;
|
||||
if (!parent) {
|
||||
console.error(`[replace_at_marker] Marker ${markerId} has no parent`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._log(`[replace_at_marker] marker=${markerId}, old=${oldNodeId}, new=${newNodeId}`);
|
||||
|
||||
// Remove old node if it exists (0 means no old node to remove)
|
||||
if (oldNodeId !== 0) {
|
||||
const oldNode = this.nodes.get(oldNodeId);
|
||||
if (!oldNode) {
|
||||
console.warn(`[replace_at_marker] Old node ${oldNodeId} not found in registry`);
|
||||
} else if (!oldNode.parentNode) {
|
||||
console.warn(`[replace_at_marker] Old node ${oldNodeId} not in DOM`);
|
||||
} else if (oldNode.parentNode !== parent) {
|
||||
console.warn(`[replace_at_marker] Old node ${oldNodeId} in wrong parent`);
|
||||
oldNode.parentNode.removeChild(oldNode);
|
||||
this._log(`[replace_at_marker] Removed ${oldNodeId} from wrong parent`);
|
||||
} else {
|
||||
// Remove from correct parent
|
||||
parent.removeChild(oldNode);
|
||||
this._log(`[replace_at_marker] Removed ${oldNodeId} from correct parent`);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert new node after marker (only if newNodeId is not 0)
|
||||
if (newNodeId !== 0) {
|
||||
const newNode = this.nodes.get(newNodeId);
|
||||
if (!newNode) {
|
||||
console.error(`[replace_at_marker] New node ${newNodeId} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert right after the marker
|
||||
// If newNode is already in DOM elsewhere, this will move it
|
||||
const nextSibling = marker.nextSibling;
|
||||
if (nextSibling) {
|
||||
parent.insertBefore(newNode, nextSibling);
|
||||
this._log(`[replace_at_marker] Inserted ${newNodeId} before sibling`);
|
||||
} else {
|
||||
parent.appendChild(newNode);
|
||||
this._log(`[replace_at_marker] Appended ${newNodeId} (no sibling)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Memory & String Utilities =====
|
||||
|
||||
readString(ptr) {
|
||||
if (!this.memory) return '';
|
||||
const bytes = new Uint8Array(this.memory.buffer, ptr);
|
||||
let length = 0;
|
||||
while (bytes[length] !== 0) length++;
|
||||
return new TextDecoder().decode(bytes.slice(0, length));
|
||||
}
|
||||
|
||||
setMemory(memory) {
|
||||
this.memory = memory;
|
||||
}
|
||||
|
||||
setWasmInstance(instance) {
|
||||
this.wasmInstance = instance;
|
||||
}
|
||||
|
||||
// ===== Logging & Debug =====
|
||||
|
||||
_log(message) {
|
||||
if (this.debugEnabled) {
|
||||
this.log.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
getLog() {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
clearLog() {
|
||||
this.log = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RitzLoader - Simplified WASM loading
|
||||
*/
|
||||
class RitzLoader {
|
||||
constructor(options = {}) {
|
||||
this.rootElement = options.rootElement || document.getElementById('app');
|
||||
this.statusElement = options.statusElement || document.getElementById('status');
|
||||
this.onLoad = options.onLoad || (() => {});
|
||||
this.onError = options.onError || ((err) => console.error(err));
|
||||
}
|
||||
|
||||
async load(wasmPath, componentName, props = {}) {
|
||||
try {
|
||||
this.setStatus('⏳ Creating runtime...');
|
||||
const runtime = new RitzRuntime(this.rootElement);
|
||||
|
||||
this.setStatus(`⏳ Loading ${wasmPath}...`);
|
||||
const response = await fetch(wasmPath);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load ${wasmPath}: ${response.status}`);
|
||||
}
|
||||
|
||||
const wasmBytes = await response.arrayBuffer();
|
||||
|
||||
this.setStatus('⏳ Instantiating WASM...');
|
||||
|
||||
// Create imports for WASM
|
||||
const imports = {
|
||||
env: {
|
||||
js_create_element: (ptr) => runtime.js_create_element(ptr),
|
||||
js_create_text: (ptr) => runtime.js_create_text(ptr),
|
||||
js_append_child: (p, c) => runtime.js_append_child(p, c),
|
||||
js_set_attribute: (e, n, v) => runtime.js_set_attribute(e, n, v),
|
||||
js_set_root: (e) => runtime.js_set_root(e),
|
||||
js_bind_event: (e, n, h) => runtime.js_bind_event(e, n, h),
|
||||
js_update_text_content: (n, t) => runtime.js_update_text_content(n, t),
|
||||
js_create_marker: () => runtime.js_create_marker(),
|
||||
js_replace_at_marker: (m, o, n) => runtime.js_replace_at_marker(m, o, n),
|
||||
}
|
||||
};
|
||||
|
||||
const { instance } = await WebAssembly.instantiate(wasmBytes, imports);
|
||||
|
||||
// Setup runtime
|
||||
runtime.setMemory(instance.exports.memory);
|
||||
runtime.setWasmInstance(instance);
|
||||
|
||||
this.setStatus(`⏳ Rendering ${componentName}...`);
|
||||
|
||||
// Call the render function with props
|
||||
const renderFn = instance.exports[`render_${componentName}`];
|
||||
if (!renderFn) {
|
||||
throw new Error(`render_${componentName} not found in WASM exports`);
|
||||
}
|
||||
|
||||
// Pass props as positional arguments
|
||||
const propValues = Object.values(props);
|
||||
renderFn(...propValues);
|
||||
|
||||
// Update signals
|
||||
runtime.updateSignals();
|
||||
|
||||
this.setStatus(`✅ ${componentName} loaded!`, 'success');
|
||||
|
||||
// Make runtime globally available for debugging
|
||||
window.ritzRuntime = runtime;
|
||||
window.ritzInstance = instance;
|
||||
|
||||
this.onLoad(runtime, instance);
|
||||
|
||||
return { runtime, instance };
|
||||
|
||||
} catch (error) {
|
||||
this.setStatus(`❌ Error: ${error.message}`, 'error');
|
||||
this.onError(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
setStatus(message, type = '') {
|
||||
if (this.statusElement) {
|
||||
this.statusElement.textContent = message;
|
||||
this.statusElement.className = 'status ' + type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Export for use in modules or global scope
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = { RitzRuntime, RitzLoader };
|
||||
} else {
|
||||
window.RitzRuntime = RitzRuntime;
|
||||
window.RitzLoader = RitzLoader;
|
||||
}
|
||||
+119
-108
@@ -1,5 +1,5 @@
|
||||
; Generated by Ritz Framework with Signals
|
||||
; Component: Toggle
|
||||
; Components: Toggle
|
||||
|
||||
; String constants
|
||||
@.str.0 = private unnamed_addr constant [4 x i8] c"div\00"
|
||||
@@ -23,16 +23,6 @@
|
||||
@.str.18 = private unnamed_addr constant [18 x i8] c"Increment Counter\00"
|
||||
@.str.19 = private unnamed_addr constant [8 x i8] c"display\00"
|
||||
|
||||
; Signal storage (reactive state in WASM memory)
|
||||
@signal_count = global i32 0
|
||||
|
||||
; Conditional rendering state
|
||||
@cond_0_parent = global i32 0
|
||||
@cond_0_marker = global i32 0
|
||||
@cond_0_current = global i32 0
|
||||
@cond_0_then_root = global i32 0
|
||||
@cond_0_else_root = global i32 0
|
||||
|
||||
; JavaScript bridge function declarations
|
||||
declare i32 @js_create_element(i8*)
|
||||
declare i32 @js_create_text(i8*)
|
||||
@@ -44,16 +34,25 @@ declare void @js_update_text_content(i32, i8*)
|
||||
declare i32 @js_create_marker()
|
||||
declare void @js_replace_at_marker(i32, i32, i32)
|
||||
|
||||
; Signal storage for Toggle (reactive state in WASM memory)
|
||||
@signal_Toggle_count = global i32 0
|
||||
|
||||
; Conditional rendering state
|
||||
@cond_0_marker = global i32 0
|
||||
@cond_0_current = global i32 0
|
||||
@cond_0_then_root = global i32 0
|
||||
@cond_0_else_root = global i32 0
|
||||
|
||||
; Signal helper functions
|
||||
define i32 @get_count() {
|
||||
entry:
|
||||
%val = load i32, i32* @signal_count
|
||||
%val = load i32, i32* @signal_Toggle_count
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define void @set_count(i32 %newval) {
|
||||
entry:
|
||||
store i32 %newval, i32* @signal_count
|
||||
store i32 %newval, i32* @signal_Toggle_count
|
||||
; TODO: Trigger DOM update callback
|
||||
ret void
|
||||
}
|
||||
@@ -61,65 +60,33 @@ entry:
|
||||
; Event handler: increment
|
||||
define void @increment() {
|
||||
entry:
|
||||
%var0 = load i32, i32* @signal_count
|
||||
%var0 = load i32, i32* @signal_Toggle_count
|
||||
%var1 = add i32 %var0, 1
|
||||
store i32 %var1, i32* @signal_count
|
||||
store i32 %var1, i32* @signal_Toggle_count
|
||||
call void @reevaluate_conditional_0()
|
||||
ret void
|
||||
}
|
||||
|
||||
; Conditional 0 - then branch
|
||||
define i32 @_render_cond_0_then() {
|
||||
entry:
|
||||
%var2 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0))
|
||||
%var3 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var4 = call i32 @js_create_text(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str.4, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var3, i32 %var4)
|
||||
call void @js_append_child(i32 %var2, i32 %var3)
|
||||
%var5 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var5, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.5, i32 0, i32 0))
|
||||
; TODO: Format f-string with signal count
|
||||
%var6 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var5, i32 %var6)
|
||||
call void @js_append_child(i32 %var2, i32 %var5)
|
||||
ret i32 %var2
|
||||
}
|
||||
|
||||
; Conditional 0 - else branch
|
||||
define i32 @_render_cond_0_else() {
|
||||
entry:
|
||||
%var7 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var7, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.7, i32 0, i32 0))
|
||||
%var8 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var9 = call i32 @js_create_text(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.8, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var8, i32 %var9)
|
||||
call void @js_append_child(i32 %var7, i32 %var8)
|
||||
%var10 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var10, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.5, i32 0, i32 0))
|
||||
; TODO: Format f-string with signal count
|
||||
%var11 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var10, i32 %var11)
|
||||
call void @js_append_child(i32 %var7, i32 %var10)
|
||||
ret i32 %var7
|
||||
}
|
||||
|
||||
; Initialize conditional 0 - render both branches
|
||||
define void @_init_conditional_0(i1 %cond) {
|
||||
; Initialize conditional 0
|
||||
define void @_init_conditional_0() {
|
||||
entry:
|
||||
; Render both branches upfront
|
||||
%then_root = call i32 @_render_cond_0_then()
|
||||
%else_root = call i32 @_render_cond_0_else()
|
||||
store i32 %then_root, i32* @cond_0_then_root
|
||||
store i32 %else_root, i32* @cond_0_else_root
|
||||
%marker = load i32, i32* @cond_0_marker
|
||||
br i1 %cond, label %insert_then, label %insert_else
|
||||
%var2 = call i32 @_render_cond_0_then()
|
||||
%var3 = call i32 @_render_cond_0_else()
|
||||
store i32 %var2, i32* @cond_0_then_root
|
||||
store i32 %var3, i32* @cond_0_else_root
|
||||
%var4 = load i32, i32* @signal_Toggle_count
|
||||
%var5 = icmp sgt i32 %var4, 5
|
||||
%var6 = zext i1 %var5 to i32
|
||||
%var7 = icmp ne i32 %var6, 0
|
||||
%var8 = load i32, i32* @cond_0_marker
|
||||
br i1 %var7, label %insert_then, label %insert_else
|
||||
insert_then:
|
||||
call void @js_replace_at_marker(i32 %marker, i32 0, i32 %then_root)
|
||||
call void @js_replace_at_marker(i32 %var8, i32 0, i32 %var2)
|
||||
store i32 1, i32* @cond_0_current
|
||||
ret void
|
||||
insert_else:
|
||||
call void @js_replace_at_marker(i32 %marker, i32 0, i32 %else_root)
|
||||
call void @js_replace_at_marker(i32 %var8, i32 0, i32 %var3)
|
||||
store i32 0, i32* @cond_0_current
|
||||
ret void
|
||||
}
|
||||
@@ -127,66 +94,110 @@ insert_else:
|
||||
; Re-evaluate conditional 0
|
||||
define void @reevaluate_conditional_0() {
|
||||
entry:
|
||||
%var12 = load i32, i32* @signal_count
|
||||
%var13 = icmp sgt i32 %var12, 5
|
||||
%var15 = load i32, i32* @cond_0_current
|
||||
%var16 = zext i1 %var13 to i32
|
||||
%var17 = icmp ne i32 %var15, %var16
|
||||
br i1 %var17, label %swap, label %done
|
||||
%var9 = load i32, i32* @signal_Toggle_count
|
||||
%var10 = icmp sgt i32 %var9, 5
|
||||
%var11 = zext i1 %var10 to i32
|
||||
%var12 = icmp ne i32 %var11, 0
|
||||
%var13 = zext i1 %var12 to i32
|
||||
%var14 = load i32, i32* @cond_0_current
|
||||
%var15 = icmp ne i32 %var14, %var13
|
||||
br i1 %var15, label %swap, label %done
|
||||
swap:
|
||||
br i1 %var13, label %swap_to_then, label %swap_to_else
|
||||
br i1 %var12, label %swap_to_then, label %swap_to_else
|
||||
swap_to_then:
|
||||
%var18 = load i32, i32* @cond_0_else_root
|
||||
%var19 = load i32, i32* @cond_0_then_root
|
||||
%var20 = load i32, i32* @cond_0_marker
|
||||
call void @js_replace_at_marker(i32 %var20, i32 %var18, i32 %var19)
|
||||
%var16 = load i32, i32* @cond_0_else_root
|
||||
%var17 = load i32, i32* @cond_0_then_root
|
||||
%var18 = load i32, i32* @cond_0_marker
|
||||
call void @js_replace_at_marker(i32 %var18, i32 %var16, i32 %var17)
|
||||
store i32 1, i32* @cond_0_current
|
||||
br label %done
|
||||
swap_to_else:
|
||||
%var21 = load i32, i32* @cond_0_then_root
|
||||
%var22 = load i32, i32* @cond_0_else_root
|
||||
%var23 = load i32, i32* @cond_0_marker
|
||||
call void @js_replace_at_marker(i32 %var23, i32 %var21, i32 %var22)
|
||||
%var19 = load i32, i32* @cond_0_then_root
|
||||
%var20 = load i32, i32* @cond_0_else_root
|
||||
%var21 = load i32, i32* @cond_0_marker
|
||||
call void @js_replace_at_marker(i32 %var21, i32 %var19, i32 %var20)
|
||||
store i32 0, i32* @cond_0_current
|
||||
br label %done
|
||||
done:
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @_render_cond_0_then() {
|
||||
entry:
|
||||
%var22 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var23 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var23, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0))
|
||||
%var24 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var25 = call i32 @js_create_text(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str.4, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var24, i32 %var25)
|
||||
call void @js_append_child(i32 %var23, i32 %var24)
|
||||
call void @js_append_child(i32 %var23, i32 %var24)
|
||||
%var26 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var26, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.5, i32 0, i32 0))
|
||||
; TODO: Format f-string with signal count
|
||||
%var27 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var26, i32 %var27)
|
||||
call void @js_append_child(i32 %var23, i32 %var26)
|
||||
call void @js_append_child(i32 %var23, i32 %var26)
|
||||
call void @js_append_child(i32 %var22, i32 %var23)
|
||||
ret i32 %var22
|
||||
}
|
||||
|
||||
define i32 @_render_cond_0_else() {
|
||||
entry:
|
||||
%var28 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var29 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var29, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.7, i32 0, i32 0))
|
||||
%var30 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
%var31 = call i32 @js_create_text(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.8, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var30, i32 %var31)
|
||||
call void @js_append_child(i32 %var29, i32 %var30)
|
||||
call void @js_append_child(i32 %var29, i32 %var30)
|
||||
%var32 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var32, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.5, i32 0, i32 0))
|
||||
; TODO: Format f-string with signal count
|
||||
%var33 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var32, i32 %var33)
|
||||
call void @js_append_child(i32 %var29, i32 %var32)
|
||||
call void @js_append_child(i32 %var29, i32 %var32)
|
||||
call void @js_append_child(i32 %var28, i32 %var29)
|
||||
ret i32 %var28
|
||||
}
|
||||
|
||||
; Component render function
|
||||
define void @render_Toggle() {
|
||||
entry:
|
||||
%var24 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var24, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.9, i32 0, i32 0))
|
||||
%var25 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.10, i32 0, i32 0))
|
||||
%var26 = call i32 @js_create_text(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.11, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var25, i32 %var26)
|
||||
call void @js_append_child(i32 %var24, i32 %var25)
|
||||
%var27 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var27, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0))
|
||||
%var28 = call i32 @js_create_text(i8* getelementptr inbounds ([44 x i8], [44 x i8]* @.str.13, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var27, i32 %var28)
|
||||
call void @js_append_child(i32 %var24, i32 %var27)
|
||||
%var29 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var29, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.14, i32 0, i32 0))
|
||||
%var30 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.15, i32 0, i32 0))
|
||||
call void @js_bind_event(i32 %var30, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.16, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0))
|
||||
%var31 = call i32 @js_create_text(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.18, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var30, i32 %var31)
|
||||
call void @js_append_child(i32 %var29, i32 %var30)
|
||||
call void @js_append_child(i32 %var24, i32 %var29)
|
||||
%var32 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var32, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.19, i32 0, i32 0))
|
||||
%var33 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
%var34 = call i32 @js_create_marker()
|
||||
call void @js_append_child(i32 %var33, i32 %var34)
|
||||
store i32 %var34, i32* @cond_0_marker
|
||||
store i32 %var33, i32* @cond_0_parent
|
||||
%var35 = load i32, i32* @signal_count
|
||||
%var36 = icmp sgt i32 %var35, 5
|
||||
call void @_init_conditional_0(i1 %var36)
|
||||
call void @js_append_child(i32 %var32, i32 %var33)
|
||||
call void @js_append_child(i32 %var24, i32 %var32)
|
||||
call void @js_set_root(i32 %var24)
|
||||
%var34 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var34, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.9, i32 0, i32 0))
|
||||
%var35 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.10, i32 0, i32 0))
|
||||
%var36 = call i32 @js_create_text(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.11, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var35, i32 %var36)
|
||||
call void @js_append_child(i32 %var34, i32 %var35)
|
||||
call void @js_append_child(i32 %var34, i32 %var35)
|
||||
%var37 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var37, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.12, i32 0, i32 0))
|
||||
%var38 = call i32 @js_create_text(i8* getelementptr inbounds ([44 x i8], [44 x i8]* @.str.13, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var37, i32 %var38)
|
||||
call void @js_append_child(i32 %var34, i32 %var37)
|
||||
call void @js_append_child(i32 %var34, i32 %var37)
|
||||
%var39 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var39, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.14, i32 0, i32 0))
|
||||
%var40 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.15, i32 0, i32 0))
|
||||
call void @js_bind_event(i32 %var40, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.16, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0))
|
||||
%var41 = call i32 @js_create_text(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.18, i32 0, i32 0))
|
||||
call void @js_append_child(i32 %var40, i32 %var41)
|
||||
call void @js_append_child(i32 %var39, i32 %var40)
|
||||
call void @js_append_child(i32 %var39, i32 %var40)
|
||||
call void @js_append_child(i32 %var34, i32 %var39)
|
||||
call void @js_append_child(i32 %var34, i32 %var39)
|
||||
%var42 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||
call void @js_set_attribute(i32 %var42, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.19, i32 0, i32 0))
|
||||
%var43 = call i32 @js_create_marker()
|
||||
call void @js_append_child(i32 %var42, i32 %var43)
|
||||
store i32 %var43, i32* @cond_0_marker
|
||||
call void @_init_conditional_0()
|
||||
call void @js_append_child(i32 %var34, i32 %var42)
|
||||
call void @js_append_child(i32 %var34, i32 %var42)
|
||||
call void @js_set_root(i32 %var34)
|
||||
ret void
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Ritz Runtime - WebAssembly DOM Bridge
|
||||
*
|
||||
* Provides the runtime environment for Ritz components compiled to WASM.
|
||||
*/
|
||||
|
||||
class RitzRuntime {
|
||||
constructor(rootElement) {
|
||||
this.rootElement = rootElement || document.getElementById('app');
|
||||
this.nodes = new Map();
|
||||
this.nextNodeId = 1;
|
||||
this.log = [];
|
||||
this.wasmInstance = null;
|
||||
this.debugEnabled = true;
|
||||
}
|
||||
|
||||
// ===== DOM Manipulation Bridge =====
|
||||
|
||||
js_create_element(tagPtr) {
|
||||
const tag = this.readString(tagPtr);
|
||||
const element = document.createElement(tag);
|
||||
const id = this.nextNodeId++;
|
||||
this.nodes.set(id, element);
|
||||
this._log(`createElement("${tag}") = ${id}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
js_create_text(textPtr) {
|
||||
const text = this.readString(textPtr);
|
||||
const textNode = document.createTextNode(text);
|
||||
const id = this.nextNodeId++;
|
||||
this.nodes.set(id, textNode);
|
||||
this._log(`createTextNode("${text}") = ${id}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
js_append_child(parentId, childId) {
|
||||
const parent = this.nodes.get(parentId);
|
||||
const child = this.nodes.get(childId);
|
||||
if (parent && child) {
|
||||
parent.appendChild(child);
|
||||
this._log(`appendChild(${parentId}, ${childId})`);
|
||||
}
|
||||
}
|
||||
|
||||
js_set_attribute(elemId, namePtr, valuePtr) {
|
||||
const element = this.nodes.get(elemId);
|
||||
const name = this.readString(namePtr);
|
||||
const value = this.readString(valuePtr);
|
||||
if (element) {
|
||||
if (name === 'class') {
|
||||
element.className = value;
|
||||
} else {
|
||||
element.setAttribute(name, value);
|
||||
}
|
||||
this._log(`setAttribute(${elemId}, "${name}", "${value}")`);
|
||||
}
|
||||
}
|
||||
|
||||
js_bind_event(elemId, eventNamePtr, handlerNamePtr) {
|
||||
const element = this.nodes.get(elemId);
|
||||
const eventName = this.readString(eventNamePtr);
|
||||
const handlerName = this.readString(handlerNamePtr);
|
||||
|
||||
if (element && this.wasmInstance) {
|
||||
const handler = this.wasmInstance.exports[handlerName];
|
||||
if (handler) {
|
||||
element.addEventListener(eventName, () => {
|
||||
this._log(`[Event] ${eventName} → ${handlerName}()`);
|
||||
handler();
|
||||
this.updateSignals();
|
||||
});
|
||||
this._log(`bindEvent(${elemId}, "${eventName}", "${handlerName}")`);
|
||||
} else {
|
||||
console.error(`Handler ${handlerName} not found in WASM exports`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
js_set_root(elemId) {
|
||||
const element = this.nodes.get(elemId);
|
||||
if (element) {
|
||||
this.rootElement.innerHTML = '';
|
||||
this.rootElement.appendChild(element);
|
||||
this._log(`setRoot(${elemId})`);
|
||||
}
|
||||
}
|
||||
|
||||
js_update_text_content(nodeId, textPtr) {
|
||||
const node = this.nodes.get(nodeId);
|
||||
const text = this.readString(textPtr);
|
||||
if (node) {
|
||||
node.textContent = text;
|
||||
this._log(`updateTextContent(${nodeId}, "${text}")`);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Signal Management =====
|
||||
|
||||
updateSignals() {
|
||||
// Discover and update all signals
|
||||
if (!this.wasmInstance) return;
|
||||
|
||||
const exports = this.wasmInstance.exports;
|
||||
|
||||
// Find all get_* functions (signal getters)
|
||||
for (const [name, fn] of Object.entries(exports)) {
|
||||
if (name.startsWith('get_') && typeof fn === 'function') {
|
||||
const signalName = name.substring(4); // Remove 'get_' prefix
|
||||
const value = fn();
|
||||
this._log(`[Signal] ${signalName} = ${value}`);
|
||||
|
||||
// Update DOM elements bound to this signal
|
||||
// TODO: Track signal-to-DOM bindings during render for efficiency
|
||||
this.updateSignalDisplay(signalName, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-evaluate all reactive conditionals
|
||||
for (const [name, fn] of Object.entries(exports)) {
|
||||
if (name.startsWith('reevaluate_conditional_') && typeof fn === 'function') {
|
||||
fn();
|
||||
this._log(`[Reactive] ${name}()`);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-evaluate all reactive match statements
|
||||
for (const [name, fn] of Object.entries(exports)) {
|
||||
if (name.startsWith('reevaluate_match_') && typeof fn === 'function') {
|
||||
fn();
|
||||
this._log(`[Reactive] ${name}()`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateSignalDisplay(signalName, value) {
|
||||
// Find DOM elements that should display this signal
|
||||
// For now, update any element with class matching signal name or data-signal attribute
|
||||
const selectors = [
|
||||
`[data-signal="${signalName}"]`,
|
||||
`.${signalName}`,
|
||||
'.count', // Hardcoded for demo - TODO: track bindings properly
|
||||
];
|
||||
|
||||
selectors.forEach(selector => {
|
||||
const elements = document.querySelectorAll(selector);
|
||||
elements.forEach(el => {
|
||||
// Check if text contains the signal name or looks like a counter
|
||||
const text = el.textContent;
|
||||
if (text.includes(signalName) || text.match(/\d+/)) {
|
||||
// Replace the number in the text
|
||||
el.textContent = text.replace(/\d+/, value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Reactive Conditional Rendering =====
|
||||
|
||||
js_create_marker() {
|
||||
// Create a comment node as a marker for conditional insertion
|
||||
const marker = document.createComment('conditional-marker');
|
||||
const id = this.nextNodeId++;
|
||||
this.nodes.set(id, marker);
|
||||
this._log(`Created marker node ${id}`);
|
||||
return id;
|
||||
}
|
||||
|
||||
js_replace_at_marker(markerId, oldNodeId, newNodeId) {
|
||||
// Replace DOM node at marker position
|
||||
const marker = this.nodes.get(markerId);
|
||||
if (!marker) {
|
||||
console.error(`[replace_at_marker] Marker ${markerId} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
const parent = marker.parentNode;
|
||||
if (!parent) {
|
||||
console.error(`[replace_at_marker] Marker ${markerId} has no parent`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._log(`[replace_at_marker] marker=${markerId}, old=${oldNodeId}, new=${newNodeId}`);
|
||||
|
||||
// Remove old node if it exists (0 means no old node to remove)
|
||||
if (oldNodeId !== 0) {
|
||||
const oldNode = this.nodes.get(oldNodeId);
|
||||
if (!oldNode) {
|
||||
console.warn(`[replace_at_marker] Old node ${oldNodeId} not found in registry`);
|
||||
} else if (!oldNode.parentNode) {
|
||||
console.warn(`[replace_at_marker] Old node ${oldNodeId} not in DOM`);
|
||||
} else if (oldNode.parentNode !== parent) {
|
||||
console.warn(`[replace_at_marker] Old node ${oldNodeId} in wrong parent`);
|
||||
oldNode.parentNode.removeChild(oldNode);
|
||||
this._log(`[replace_at_marker] Removed ${oldNodeId} from wrong parent`);
|
||||
} else {
|
||||
// Remove from correct parent
|
||||
parent.removeChild(oldNode);
|
||||
this._log(`[replace_at_marker] Removed ${oldNodeId} from correct parent`);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert new node after marker (only if newNodeId is not 0)
|
||||
if (newNodeId !== 0) {
|
||||
const newNode = this.nodes.get(newNodeId);
|
||||
if (!newNode) {
|
||||
console.error(`[replace_at_marker] New node ${newNodeId} not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert right after the marker
|
||||
// If newNode is already in DOM elsewhere, this will move it
|
||||
const nextSibling = marker.nextSibling;
|
||||
if (nextSibling) {
|
||||
parent.insertBefore(newNode, nextSibling);
|
||||
this._log(`[replace_at_marker] Inserted ${newNodeId} before sibling`);
|
||||
} else {
|
||||
parent.appendChild(newNode);
|
||||
this._log(`[replace_at_marker] Appended ${newNodeId} (no sibling)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Memory & String Utilities =====
|
||||
|
||||
readString(ptr) {
|
||||
if (!this.memory) return '';
|
||||
const bytes = new Uint8Array(this.memory.buffer, ptr);
|
||||
let length = 0;
|
||||
while (bytes[length] !== 0) length++;
|
||||
return new TextDecoder().decode(bytes.slice(0, length));
|
||||
}
|
||||
|
||||
setMemory(memory) {
|
||||
this.memory = memory;
|
||||
}
|
||||
|
||||
setWasmInstance(instance) {
|
||||
this.wasmInstance = instance;
|
||||
}
|
||||
|
||||
// ===== Logging & Debug =====
|
||||
|
||||
_log(message) {
|
||||
if (this.debugEnabled) {
|
||||
this.log.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
getLog() {
|
||||
return this.log;
|
||||
}
|
||||
|
||||
clearLog() {
|
||||
this.log = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RitzLoader - Simplified WASM loading
|
||||
*/
|
||||
class RitzLoader {
|
||||
constructor(options = {}) {
|
||||
this.rootElement = options.rootElement || document.getElementById('app');
|
||||
this.statusElement = options.statusElement || document.getElementById('status');
|
||||
this.onLoad = options.onLoad || (() => {});
|
||||
this.onError = options.onError || ((err) => console.error(err));
|
||||
}
|
||||
|
||||
async load(wasmPath, componentName, props = {}) {
|
||||
try {
|
||||
this.setStatus('⏳ Creating runtime...');
|
||||
const runtime = new RitzRuntime(this.rootElement);
|
||||
|
||||
this.setStatus(`⏳ Loading ${wasmPath}...`);
|
||||
const response = await fetch(wasmPath);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load ${wasmPath}: ${response.status}`);
|
||||
}
|
||||
|
||||
const wasmBytes = await response.arrayBuffer();
|
||||
|
||||
this.setStatus('⏳ Instantiating WASM...');
|
||||
|
||||
// Create imports for WASM
|
||||
const imports = {
|
||||
env: {
|
||||
js_create_element: (ptr) => runtime.js_create_element(ptr),
|
||||
js_create_text: (ptr) => runtime.js_create_text(ptr),
|
||||
js_append_child: (p, c) => runtime.js_append_child(p, c),
|
||||
js_set_attribute: (e, n, v) => runtime.js_set_attribute(e, n, v),
|
||||
js_set_root: (e) => runtime.js_set_root(e),
|
||||
js_bind_event: (e, n, h) => runtime.js_bind_event(e, n, h),
|
||||
js_update_text_content: (n, t) => runtime.js_update_text_content(n, t),
|
||||
js_create_marker: () => runtime.js_create_marker(),
|
||||
js_replace_at_marker: (m, o, n) => runtime.js_replace_at_marker(m, o, n),
|
||||
}
|
||||
};
|
||||
|
||||
const { instance } = await WebAssembly.instantiate(wasmBytes, imports);
|
||||
|
||||
// Setup runtime
|
||||
runtime.setMemory(instance.exports.memory);
|
||||
runtime.setWasmInstance(instance);
|
||||
|
||||
this.setStatus(`⏳ Rendering ${componentName}...`);
|
||||
|
||||
// Call the render function with props
|
||||
const renderFn = instance.exports[`render_${componentName}`];
|
||||
if (!renderFn) {
|
||||
throw new Error(`render_${componentName} not found in WASM exports`);
|
||||
}
|
||||
|
||||
// Pass props as positional arguments
|
||||
const propValues = Object.values(props);
|
||||
renderFn(...propValues);
|
||||
|
||||
// Update signals
|
||||
runtime.updateSignals();
|
||||
|
||||
this.setStatus(`✅ ${componentName} loaded!`, 'success');
|
||||
|
||||
// Make runtime globally available for debugging
|
||||
window.ritzRuntime = runtime;
|
||||
window.ritzInstance = instance;
|
||||
|
||||
this.onLoad(runtime, instance);
|
||||
|
||||
return { runtime, instance };
|
||||
|
||||
} catch (error) {
|
||||
this.setStatus(`❌ Error: ${error.message}`, 'error');
|
||||
this.onError(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
setStatus(message, type = '') {
|
||||
if (this.statusElement) {
|
||||
this.statusElement.textContent = message;
|
||||
this.statusElement.className = 'status ' + type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Export for use in modules or global scope
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = { RitzRuntime, RitzLoader };
|
||||
} else {
|
||||
window.RitzRuntime = RitzRuntime;
|
||||
window.RitzLoader = RitzLoader;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -87,6 +87,10 @@ class SignalLLVMIRGenerator:
|
||||
self._emit_conditional_functions()
|
||||
self._emit_component(component)
|
||||
|
||||
# Emit main entry point for the last (top-level) component
|
||||
if self.components:
|
||||
self._emit_main_entry(self.components[-1]["name"])
|
||||
|
||||
# Prepend string constants
|
||||
return self._finalize_with_strings()
|
||||
|
||||
@@ -641,6 +645,17 @@ class SignalLLVMIRGenerator:
|
||||
self.lines.append("}")
|
||||
self.lines.append("")
|
||||
|
||||
def _emit_main_entry(self, component_name: str) -> None:
|
||||
"""Emit main entry point that renders top-level component and sets root."""
|
||||
self.lines.append("; Main entry point")
|
||||
self.lines.append("define void @main() {")
|
||||
self.lines.append("entry:")
|
||||
self.lines.append(f" %root = call i32 @render_{component_name}()")
|
||||
self.lines.append(" call void @js_set_root(i32 %root)")
|
||||
self.lines.append(" ret void")
|
||||
self.lines.append("}")
|
||||
self.lines.append("")
|
||||
|
||||
def _emit_component(self, ir: dict[str, Any]) -> None:
|
||||
"""Emit component render function."""
|
||||
component_name = ir["name"]
|
||||
@@ -654,7 +669,7 @@ class SignalLLVMIRGenerator:
|
||||
param_str = ", ".join(param_list) if param_list else ""
|
||||
|
||||
self.lines.append("; Component render function")
|
||||
self.lines.append(f"define void @render_{component_name}({param_str}) {{")
|
||||
self.lines.append(f"define i32 @render_{component_name}({param_str}) {{")
|
||||
self.lines.append("entry:")
|
||||
|
||||
# Process component body (skip signals and functions, already handled)
|
||||
@@ -666,11 +681,13 @@ class SignalLLVMIRGenerator:
|
||||
if root_var is None and var:
|
||||
root_var = var
|
||||
|
||||
# Set root element
|
||||
# Return root element (caller decides whether to set as root or append)
|
||||
if root_var:
|
||||
self.lines.append(f" call void @js_set_root(i32 %{root_var})")
|
||||
self.lines.append(f" ret i32 %{root_var}")
|
||||
else:
|
||||
# No root element - return 0
|
||||
self.lines.append(" ret i32 0")
|
||||
|
||||
self.lines.append(" ret void")
|
||||
self.lines.append("}")
|
||||
self.lines.append("")
|
||||
|
||||
@@ -767,14 +784,20 @@ class SignalLLVMIRGenerator:
|
||||
arg_var = self._emit_expr(arg)
|
||||
arg_values.append(f"i32 {arg_var}")
|
||||
|
||||
# Build argument list and call
|
||||
# Call component render function and capture returned root element
|
||||
elem_var = self._new_var()
|
||||
if arg_values:
|
||||
arg_list = ", ".join(arg_values)
|
||||
self.lines.append(f" call void @render_{component_name}({arg_list})")
|
||||
self.lines.append(f" %{elem_var} = call i32 @render_{component_name}({arg_list})")
|
||||
else:
|
||||
self.lines.append(f" call void @render_{component_name}()")
|
||||
self.lines.append(f" %{elem_var} = call i32 @render_{component_name}()")
|
||||
|
||||
return None
|
||||
# Append to parent if we have one
|
||||
if self.parent_element_stack:
|
||||
parent_var = self.parent_element_stack[-1]
|
||||
self.lines.append(f" call void @js_append_child(i32 %{parent_var}, i32 %{elem_var})")
|
||||
|
||||
return elem_var
|
||||
|
||||
def _emit_match(self, stmt: dict[str, Any]) -> str | None:
|
||||
"""Emit a match/case statement with reactive rendering."""
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -57,7 +57,7 @@ def Button(label):
|
||||
llvm_ir = generate_llvm_ir(ir)
|
||||
|
||||
# Should generate render function with parameter
|
||||
assert "define void @render_Button(i32 %label)" in llvm_ir
|
||||
assert "define i32 @render_Button(i32 %label)" in llvm_ir
|
||||
|
||||
|
||||
def test_parse_yield_component_with_args():
|
||||
@@ -111,8 +111,8 @@ def Parent():
|
||||
components = parse_component(source)
|
||||
llvm_ir = generate_llvm_ir(components)
|
||||
|
||||
# Should call render_Child with argument
|
||||
assert "call void @render_Child(i32 42)" in llvm_ir
|
||||
# Should call render_Child with argument and capture return value
|
||||
assert "call i32 @render_Child(i32 42)" in llvm_ir
|
||||
|
||||
|
||||
def test_component_with_default_param():
|
||||
@@ -180,7 +180,7 @@ def Counter(initial_count):
|
||||
llvm_ir = generate_llvm_ir(ir)
|
||||
|
||||
# Should accept parameter
|
||||
assert "define void @render_Counter(i32 %initial_count)" in llvm_ir
|
||||
assert "define i32 @render_Counter(i32 %initial_count)" in llvm_ir
|
||||
|
||||
# Signal should be initialized with parameter value
|
||||
# This will require storing the param value to the signal global
|
||||
@@ -25,7 +25,7 @@ def test_llvm_hello_world_structure():
|
||||
llvm_ir = generate_llvm_ir(ir_dict)
|
||||
|
||||
# Check basic LLVM IR structure
|
||||
assert "define void @render_HelloWorld()" in llvm_ir
|
||||
assert "define i32 @render_HelloWorld()" in llvm_ir
|
||||
assert "ret void" in llvm_ir
|
||||
|
||||
# Should have string constants
|
||||
@@ -115,10 +115,12 @@ def test_llvm_ir_syntax_valid():
|
||||
llvm_ir = generate_llvm_ir(ir_dict)
|
||||
|
||||
# Basic syntax checks
|
||||
assert llvm_ir.count("define") == llvm_ir.count("ret void") # All functions return
|
||||
assert llvm_ir.count("define") == llvm_ir.count("ret") # All functions have returns
|
||||
assert "%" in llvm_ir # Has SSA variables
|
||||
assert "call" in llvm_ir # Has function calls
|
||||
assert "@" in llvm_ir # Has global symbols
|
||||
assert "define void @main()" in llvm_ir # Has main entry point
|
||||
assert "define i32 @render_" in llvm_ir # Component functions return i32
|
||||
|
||||
|
||||
def test_llvm_ir_compiles_with_llc():
|
||||
|
||||
@@ -76,7 +76,7 @@ def SimpleTabs():
|
||||
llvm_ir = generate_llvm_ir(ir)
|
||||
|
||||
# Should generate render function for TabButton with parameters
|
||||
assert "define void @render_TabButton(" in llvm_ir
|
||||
assert "define i32 @render_TabButton(" in llvm_ir
|
||||
|
||||
# Should call TabButton from SimpleTabs with arguments
|
||||
assert "call void @render_TabButton(" in llvm_ir
|
||||
assert "call i32 @render_TabButton(" in llvm_ir
|
||||
Reference in new issue
Block a user