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}...`);
|
this.setStatus(`⏳ Rendering ${componentName}...`);
|
||||||
|
|
||||||
// Call the render function with props
|
// Call the main entry point (which renders top-level component and sets root)
|
||||||
const renderFn = instance.exports[`render_${componentName}`];
|
const mainFn = instance.exports.main;
|
||||||
if (!renderFn) {
|
if (!mainFn) {
|
||||||
throw new Error(`render_${componentName} not found in WASM exports`);
|
throw new Error(`main function not found in WASM exports`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass props as positional arguments
|
mainFn();
|
||||||
const propValues = Object.values(props);
|
|
||||||
renderFn(...propValues);
|
|
||||||
|
|
||||||
// Update signals
|
// Update signals
|
||||||
runtime.updateSignals();
|
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
|
setting_tab = value
|
||||||
|
|
||||||
with Div(class_="vertical-tabs"):
|
with Div(class_="vertical-tabs"):
|
||||||
# Vertical tab menu
|
# Vertical tab menu - clean ternary syntax!
|
||||||
with Div(class_="vertical-tab-menu"):
|
with Div(class_="vertical-tab-menu"):
|
||||||
if setting_tab == 0:
|
with Button(class_='vertical-tab active' if setting_tab == 0 else 'vertical-tab',
|
||||||
with Button(class_="vertical-tab active", onclick=lambda: set_setting(0)):
|
onclick=lambda: set_setting(0)):
|
||||||
yield "⚙️ General"
|
yield "⚙️ General"
|
||||||
else:
|
|
||||||
with Button(class_="vertical-tab", onclick=lambda: set_setting(0)):
|
|
||||||
yield "⚙️ General"
|
|
||||||
|
|
||||||
if setting_tab == 1:
|
with Button(class_='vertical-tab active' if setting_tab == 1 else 'vertical-tab',
|
||||||
with Button(class_="vertical-tab active", onclick=lambda: set_setting(1)):
|
onclick=lambda: set_setting(1)):
|
||||||
yield "🔒 Privacy"
|
yield "🔒 Privacy"
|
||||||
else:
|
|
||||||
with Button(class_="vertical-tab", onclick=lambda: set_setting(1)):
|
|
||||||
yield "🔒 Privacy"
|
|
||||||
|
|
||||||
if setting_tab == 2:
|
with Button(class_='vertical-tab active' if setting_tab == 2 else 'vertical-tab',
|
||||||
with Button(class_="vertical-tab active", onclick=lambda: set_setting(2)):
|
onclick=lambda: set_setting(2)):
|
||||||
yield "🚀 Advanced"
|
yield "🚀 Advanced"
|
||||||
else:
|
|
||||||
with Button(class_="vertical-tab", onclick=lambda: set_setting(2)):
|
|
||||||
yield "🚀 Advanced"
|
|
||||||
|
|
||||||
# Vertical tab content
|
# Vertical tab content
|
||||||
with Div(class_="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"):
|
with P(class_="subtitle"):
|
||||||
yield "Beautiful composition with TabMenu and TabPane components"
|
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"):
|
with Ul(class_="tab-menu"):
|
||||||
if tab_index == 0:
|
with Li(class_='tab active' if tab_index == 0 else 'tab'):
|
||||||
with Li(class_="tab active"):
|
with Button(onclick=lambda: set_tab(0)):
|
||||||
with Button(onclick=lambda: set_tab(0)):
|
yield "🏠 Home"
|
||||||
yield "🏠 Home"
|
|
||||||
else:
|
|
||||||
with Li(class_="tab"):
|
|
||||||
with Button(onclick=lambda: set_tab(0)):
|
|
||||||
yield "🏠 Home"
|
|
||||||
|
|
||||||
if tab_index == 1:
|
with Li(class_='tab active' if tab_index == 1 else 'tab'):
|
||||||
with Li(class_="tab active"):
|
with Button(onclick=lambda: set_tab(1)):
|
||||||
with Button(onclick=lambda: set_tab(1)):
|
yield "👤 Profile"
|
||||||
yield "👤 Profile"
|
|
||||||
else:
|
|
||||||
with Li(class_="tab"):
|
|
||||||
with Button(onclick=lambda: set_tab(1)):
|
|
||||||
yield "👤 Profile"
|
|
||||||
|
|
||||||
if tab_index == 2:
|
with Li(class_='tab active' if tab_index == 2 else 'tab'):
|
||||||
with Li(class_="tab active"):
|
with Button(onclick=lambda: set_tab(2)):
|
||||||
with Button(onclick=lambda: set_tab(2)):
|
yield "⚙️ Settings"
|
||||||
yield "⚙️ Settings"
|
|
||||||
else:
|
|
||||||
with Li(class_="tab"):
|
|
||||||
with Button(onclick=lambda: set_tab(2)):
|
|
||||||
yield "⚙️ Settings"
|
|
||||||
|
|
||||||
# Tab panes - match/case for clean switching
|
# Tab panes - match/case for clean switching
|
||||||
with Div(class_="tab-content"):
|
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
|
; Generated by Ritz Framework with Signals
|
||||||
; Component: Toggle
|
; Components: Toggle
|
||||||
|
|
||||||
; String constants
|
; String constants
|
||||||
@.str.0 = private unnamed_addr constant [4 x i8] c"div\00"
|
@.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.18 = private unnamed_addr constant [18 x i8] c"Increment Counter\00"
|
||||||
@.str.19 = private unnamed_addr constant [8 x i8] c"display\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
|
; JavaScript bridge function declarations
|
||||||
declare i32 @js_create_element(i8*)
|
declare i32 @js_create_element(i8*)
|
||||||
declare i32 @js_create_text(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 i32 @js_create_marker()
|
||||||
declare void @js_replace_at_marker(i32, i32, i32)
|
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
|
; Signal helper functions
|
||||||
define i32 @get_count() {
|
define i32 @get_count() {
|
||||||
entry:
|
entry:
|
||||||
%val = load i32, i32* @signal_count
|
%val = load i32, i32* @signal_Toggle_count
|
||||||
ret i32 %val
|
ret i32 %val
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @set_count(i32 %newval) {
|
define void @set_count(i32 %newval) {
|
||||||
entry:
|
entry:
|
||||||
store i32 %newval, i32* @signal_count
|
store i32 %newval, i32* @signal_Toggle_count
|
||||||
; TODO: Trigger DOM update callback
|
; TODO: Trigger DOM update callback
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -61,65 +60,33 @@ entry:
|
|||||||
; Event handler: increment
|
; Event handler: increment
|
||||||
define void @increment() {
|
define void @increment() {
|
||||||
entry:
|
entry:
|
||||||
%var0 = load i32, i32* @signal_count
|
%var0 = load i32, i32* @signal_Toggle_count
|
||||||
%var1 = add i32 %var0, 1
|
%var1 = add i32 %var0, 1
|
||||||
store i32 %var1, i32* @signal_count
|
store i32 %var1, i32* @signal_Toggle_count
|
||||||
call void @reevaluate_conditional_0()
|
call void @reevaluate_conditional_0()
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Conditional 0 - then branch
|
; Initialize conditional 0
|
||||||
define i32 @_render_cond_0_then() {
|
define void @_init_conditional_0() {
|
||||||
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) {
|
|
||||||
entry:
|
entry:
|
||||||
; Render both branches upfront
|
; Render both branches upfront
|
||||||
%then_root = call i32 @_render_cond_0_then()
|
%var2 = call i32 @_render_cond_0_then()
|
||||||
%else_root = call i32 @_render_cond_0_else()
|
%var3 = call i32 @_render_cond_0_else()
|
||||||
store i32 %then_root, i32* @cond_0_then_root
|
store i32 %var2, i32* @cond_0_then_root
|
||||||
store i32 %else_root, i32* @cond_0_else_root
|
store i32 %var3, i32* @cond_0_else_root
|
||||||
%marker = load i32, i32* @cond_0_marker
|
%var4 = load i32, i32* @signal_Toggle_count
|
||||||
br i1 %cond, label %insert_then, label %insert_else
|
%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:
|
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
|
store i32 1, i32* @cond_0_current
|
||||||
ret void
|
ret void
|
||||||
insert_else:
|
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
|
store i32 0, i32* @cond_0_current
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -127,66 +94,110 @@ insert_else:
|
|||||||
; Re-evaluate conditional 0
|
; Re-evaluate conditional 0
|
||||||
define void @reevaluate_conditional_0() {
|
define void @reevaluate_conditional_0() {
|
||||||
entry:
|
entry:
|
||||||
%var12 = load i32, i32* @signal_count
|
%var9 = load i32, i32* @signal_Toggle_count
|
||||||
%var13 = icmp sgt i32 %var12, 5
|
%var10 = icmp sgt i32 %var9, 5
|
||||||
%var15 = load i32, i32* @cond_0_current
|
%var11 = zext i1 %var10 to i32
|
||||||
%var16 = zext i1 %var13 to i32
|
%var12 = icmp ne i32 %var11, 0
|
||||||
%var17 = icmp ne i32 %var15, %var16
|
%var13 = zext i1 %var12 to i32
|
||||||
br i1 %var17, label %swap, label %done
|
%var14 = load i32, i32* @cond_0_current
|
||||||
|
%var15 = icmp ne i32 %var14, %var13
|
||||||
|
br i1 %var15, label %swap, label %done
|
||||||
swap:
|
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:
|
swap_to_then:
|
||||||
%var18 = load i32, i32* @cond_0_else_root
|
%var16 = load i32, i32* @cond_0_else_root
|
||||||
%var19 = load i32, i32* @cond_0_then_root
|
%var17 = load i32, i32* @cond_0_then_root
|
||||||
%var20 = load i32, i32* @cond_0_marker
|
%var18 = load i32, i32* @cond_0_marker
|
||||||
call void @js_replace_at_marker(i32 %var20, i32 %var18, i32 %var19)
|
call void @js_replace_at_marker(i32 %var18, i32 %var16, i32 %var17)
|
||||||
store i32 1, i32* @cond_0_current
|
store i32 1, i32* @cond_0_current
|
||||||
br label %done
|
br label %done
|
||||||
swap_to_else:
|
swap_to_else:
|
||||||
%var21 = load i32, i32* @cond_0_then_root
|
%var19 = load i32, i32* @cond_0_then_root
|
||||||
%var22 = load i32, i32* @cond_0_else_root
|
%var20 = load i32, i32* @cond_0_else_root
|
||||||
%var23 = load i32, i32* @cond_0_marker
|
%var21 = load i32, i32* @cond_0_marker
|
||||||
call void @js_replace_at_marker(i32 %var23, i32 %var21, i32 %var22)
|
call void @js_replace_at_marker(i32 %var21, i32 %var19, i32 %var20)
|
||||||
store i32 0, i32* @cond_0_current
|
store i32 0, i32* @cond_0_current
|
||||||
br label %done
|
br label %done
|
||||||
done:
|
done:
|
||||||
ret void
|
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
|
; Component render function
|
||||||
define void @render_Toggle() {
|
define void @render_Toggle() {
|
||||||
entry:
|
entry:
|
||||||
%var24 = 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_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))
|
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))
|
||||||
%var25 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.10, 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))
|
||||||
%var26 = call i32 @js_create_text(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.11, 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 %var25, i32 %var26)
|
call void @js_append_child(i32 %var35, i32 %var36)
|
||||||
call void @js_append_child(i32 %var24, i32 %var25)
|
call void @js_append_child(i32 %var34, i32 %var35)
|
||||||
%var27 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0))
|
call void @js_append_child(i32 %var34, i32 %var35)
|
||||||
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))
|
%var37 = call i32 @js_create_element(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, 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_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))
|
||||||
call void @js_append_child(i32 %var27, i32 %var28)
|
%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 %var24, i32 %var27)
|
call void @js_append_child(i32 %var37, i32 %var38)
|
||||||
%var29 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
call void @js_append_child(i32 %var34, i32 %var37)
|
||||||
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))
|
call void @js_append_child(i32 %var34, i32 %var37)
|
||||||
%var30 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.15, i32 0, i32 0))
|
%var39 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, 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))
|
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))
|
||||||
%var31 = call i32 @js_create_text(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.18, 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_append_child(i32 %var30, i32 %var31)
|
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))
|
||||||
call void @js_append_child(i32 %var29, i32 %var30)
|
%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 %var24, i32 %var29)
|
call void @js_append_child(i32 %var40, i32 %var41)
|
||||||
%var32 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
call void @js_append_child(i32 %var39, i32 %var40)
|
||||||
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))
|
call void @js_append_child(i32 %var39, i32 %var40)
|
||||||
%var33 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
call void @js_append_child(i32 %var34, i32 %var39)
|
||||||
%var34 = call i32 @js_create_marker()
|
call void @js_append_child(i32 %var34, i32 %var39)
|
||||||
call void @js_append_child(i32 %var33, i32 %var34)
|
%var42 = call i32 @js_create_element(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.0, i32 0, i32 0))
|
||||||
store i32 %var34, i32* @cond_0_marker
|
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))
|
||||||
store i32 %var33, i32* @cond_0_parent
|
%var43 = call i32 @js_create_marker()
|
||||||
%var35 = load i32, i32* @signal_count
|
call void @js_append_child(i32 %var42, i32 %var43)
|
||||||
%var36 = icmp sgt i32 %var35, 5
|
store i32 %var43, i32* @cond_0_marker
|
||||||
call void @_init_conditional_0(i1 %var36)
|
call void @_init_conditional_0()
|
||||||
call void @js_append_child(i32 %var32, i32 %var33)
|
call void @js_append_child(i32 %var34, i32 %var42)
|
||||||
call void @js_append_child(i32 %var24, i32 %var32)
|
call void @js_append_child(i32 %var34, i32 %var42)
|
||||||
call void @js_set_root(i32 %var24)
|
call void @js_set_root(i32 %var34)
|
||||||
ret void
|
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_conditional_functions()
|
||||||
self._emit_component(component)
|
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
|
# Prepend string constants
|
||||||
return self._finalize_with_strings()
|
return self._finalize_with_strings()
|
||||||
|
|
||||||
@@ -641,6 +645,17 @@ class SignalLLVMIRGenerator:
|
|||||||
self.lines.append("}")
|
self.lines.append("}")
|
||||||
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:
|
def _emit_component(self, ir: dict[str, Any]) -> None:
|
||||||
"""Emit component render function."""
|
"""Emit component render function."""
|
||||||
component_name = ir["name"]
|
component_name = ir["name"]
|
||||||
@@ -654,7 +669,7 @@ class SignalLLVMIRGenerator:
|
|||||||
param_str = ", ".join(param_list) if param_list else ""
|
param_str = ", ".join(param_list) if param_list else ""
|
||||||
|
|
||||||
self.lines.append("; Component render function")
|
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:")
|
self.lines.append("entry:")
|
||||||
|
|
||||||
# Process component body (skip signals and functions, already handled)
|
# Process component body (skip signals and functions, already handled)
|
||||||
@@ -666,11 +681,13 @@ class SignalLLVMIRGenerator:
|
|||||||
if root_var is None and var:
|
if root_var is None and var:
|
||||||
root_var = var
|
root_var = var
|
||||||
|
|
||||||
# Set root element
|
# Return root element (caller decides whether to set as root or append)
|
||||||
if root_var:
|
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("}")
|
||||||
self.lines.append("")
|
self.lines.append("")
|
||||||
|
|
||||||
@@ -767,14 +784,20 @@ class SignalLLVMIRGenerator:
|
|||||||
arg_var = self._emit_expr(arg)
|
arg_var = self._emit_expr(arg)
|
||||||
arg_values.append(f"i32 {arg_var}")
|
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:
|
if arg_values:
|
||||||
arg_list = ", ".join(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:
|
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:
|
def _emit_match(self, stmt: dict[str, Any]) -> str | None:
|
||||||
"""Emit a match/case statement with reactive rendering."""
|
"""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)
|
llvm_ir = generate_llvm_ir(ir)
|
||||||
|
|
||||||
# Should generate render function with parameter
|
# 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():
|
def test_parse_yield_component_with_args():
|
||||||
@@ -111,8 +111,8 @@ def Parent():
|
|||||||
components = parse_component(source)
|
components = parse_component(source)
|
||||||
llvm_ir = generate_llvm_ir(components)
|
llvm_ir = generate_llvm_ir(components)
|
||||||
|
|
||||||
# Should call render_Child with argument
|
# Should call render_Child with argument and capture return value
|
||||||
assert "call void @render_Child(i32 42)" in llvm_ir
|
assert "call i32 @render_Child(i32 42)" in llvm_ir
|
||||||
|
|
||||||
|
|
||||||
def test_component_with_default_param():
|
def test_component_with_default_param():
|
||||||
@@ -180,7 +180,7 @@ def Counter(initial_count):
|
|||||||
llvm_ir = generate_llvm_ir(ir)
|
llvm_ir = generate_llvm_ir(ir)
|
||||||
|
|
||||||
# Should accept parameter
|
# 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
|
# Signal should be initialized with parameter value
|
||||||
# This will require storing the param value to the signal global
|
# 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)
|
llvm_ir = generate_llvm_ir(ir_dict)
|
||||||
|
|
||||||
# Check basic LLVM IR structure
|
# 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
|
assert "ret void" in llvm_ir
|
||||||
|
|
||||||
# Should have string constants
|
# Should have string constants
|
||||||
@@ -115,10 +115,12 @@ def test_llvm_ir_syntax_valid():
|
|||||||
llvm_ir = generate_llvm_ir(ir_dict)
|
llvm_ir = generate_llvm_ir(ir_dict)
|
||||||
|
|
||||||
# Basic syntax checks
|
# 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 "%" in llvm_ir # Has SSA variables
|
||||||
assert "call" in llvm_ir # Has function calls
|
assert "call" in llvm_ir # Has function calls
|
||||||
assert "@" in llvm_ir # Has global symbols
|
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():
|
def test_llvm_ir_compiles_with_llc():
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ def SimpleTabs():
|
|||||||
llvm_ir = generate_llvm_ir(ir)
|
llvm_ir = generate_llvm_ir(ir)
|
||||||
|
|
||||||
# Should generate render function for TabButton with parameters
|
# 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
|
# 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