Implement reactive text nodes & fix LLVM syntax for clang 20

**Reactive Text Nodes:**
- F-strings with signal dependencies now update automatically
- Added js_create_text_with_int() and js_update_text_with_int() for efficient "prefix{int}" pattern
- Text nodes stored in @reactive_text_N_node globals for updates
- Scan and track f-string dependencies during collection phase

**Binary Operations:**
- Implemented BinOp support in parser and codegen
- Maps Add → add i32, Sub → sub i32, Mult → mul i32, Div → sdiv i32, Mod → srem i32
- count = count + 1 now generates correct arithmetic instead of store i32 0

**LLVM Syntax Fixes (clang 20 compatibility):**
- Fixed getelementptr syntax: removed parentheses around type
- Before: getelementptr inbounds ([N x i8], [N x i8]* @str, ...)
- After:  getelementptr inbounds [N x i8], [N x i8]* @str, ...
- Created _emit_string_ptr() helper for consistent string pointer generation
- Fixed in: element creation, attribute setting, event binding, select instructions

**Runtime (ritz-runtime.js):**
- Added js_create_text_with_int(prefix, intValue) - creates text node with "prefix" + intValue
- Added js_update_text_with_int(node, prefix, intValue) - updates text content

**Result:**
✅ TextInput counter increments/decrements correctly
✅ Tabs example works (reactive attributes, conditionals)
✅ Both examples compile with clang 20

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Aaron SinclairandClaude committed 2025-11-15 15:00:36 -08:00
1 parent d8a2e28fd5
commit 0b77c2ff3c
7 files changed
+999 -594

No files matched your search

+117 -73
View File
@@ -2,21 +2,21 @@
; Components: TextInput
; 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 [10 x i8] c"container\00"
@.str.3 = private unnamed_addr constant [3 x i8] c"h1\00"
@.str.4 = private unnamed_addr constant [17 x i8] c"Reactive Counter\00"
@.str.5 = private unnamed_addr constant [2 x i8] c"p\00"
@.str.6 = private unnamed_addr constant [13 x i8] c"instructions\00"
@.str.7 = private unnamed_addr constant [65 x i8] c"Click buttons to see reactive updates (text input coming soon!):\00"
@.str.8 = private unnamed_addr constant [13 x i8] c"button-group\00"
@.str.9 = private unnamed_addr constant [7 x i8] c"button\00"
@.str.10 = private unnamed_addr constant [6 x i8] c"click\00"
@.str.11 = private unnamed_addr constant [10 x i8] c"decrement\00"
@.str.12 = private unnamed_addr constant [4 x i8] c"−\00"
@.str.13 = private unnamed_addr constant [16 x i8] c"counter-display\00"
@.str.14 = private unnamed_addr constant [2 x i8] c"0\00"
@.str.0 = private unnamed_addr constant [8 x i8] c"Count: \00"
@.str.1 = private unnamed_addr constant [4 x i8] c"div\00"
@.str.2 = private unnamed_addr constant [6 x i8] c"class\00"
@.str.3 = private unnamed_addr constant [10 x i8] c"container\00"
@.str.4 = private unnamed_addr constant [3 x i8] c"h1\00"
@.str.5 = private unnamed_addr constant [17 x i8] c"Reactive Counter\00"
@.str.6 = private unnamed_addr constant [2 x i8] c"p\00"
@.str.7 = private unnamed_addr constant [13 x i8] c"instructions\00"
@.str.8 = private unnamed_addr constant [65 x i8] c"Click buttons to see reactive updates (text input coming soon!):\00"
@.str.9 = private unnamed_addr constant [13 x i8] c"button-group\00"
@.str.10 = private unnamed_addr constant [7 x i8] c"button\00"
@.str.11 = private unnamed_addr constant [6 x i8] c"click\00"
@.str.12 = private unnamed_addr constant [10 x i8] c"decrement\00"
@.str.13 = private unnamed_addr constant [4 x i8] c"−\00"
@.str.14 = private unnamed_addr constant [16 x i8] c"counter-display\00"
@.str.15 = private unnamed_addr constant [10 x i8] c"increment\00"
@.str.16 = private unnamed_addr constant [2 x i8] c"+\00"
@.str.17 = private unnamed_addr constant [5 x i8] c"todo\00"
@@ -32,17 +32,22 @@
; JavaScript bridge function declarations
declare i32 @js_create_element(i8*)
declare i32 @js_create_text(i8*)
declare i32 @js_create_text_with_int(i8*, i32)
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 void @js_update_text_with_int(i32, i8*, i32)
declare i32 @js_create_marker()
declare void @js_replace_at_marker(i32, i32, i32)
; Signal storage for TextInput (reactive state in WASM memory)
@signal_TextInput_count = global i32 0
; Reactive text node storage
@reactive_text_0_node = global i32 0
; Signal helper functions
define i32 @get_count() {
entry:
@@ -63,76 +68,115 @@ entry:
%var0 = load i32, i32* @signal_TextInput_count
%var1 = add i32 %var0, 1
store i32 %var1, i32* @signal_TextInput_count
%var2 = load i32, i32* @reactive_text_0_node
%var3 = getelementptr inbounds [8 x i8], [8 x i8]* @.str.0, i32 0, i32 0
%var4 = load i32, i32* @signal_TextInput_count
call void @js_update_text_with_int(i32 %var2, i8* %var3, i32 %var4)
ret void
}
; Event handler: decrement
define void @decrement() {
entry:
%var2 = load i32, i32* @signal_TextInput_count
%var3 = sub i32 %var2, 1
store i32 %var3, i32* @signal_TextInput_count
%var5 = load i32, i32* @signal_TextInput_count
%var6 = sub i32 %var5, 1
store i32 %var6, i32* @signal_TextInput_count
%var7 = load i32, i32* @reactive_text_0_node
%var8 = getelementptr inbounds [8 x i8], [8 x i8]* @.str.0, i32 0, i32 0
%var9 = load i32, i32* @signal_TextInput_count
call void @js_update_text_with_int(i32 %var7, i8* %var8, i32 %var9)
ret void
}
; Component render function
define i32 @render_TextInput() {
entry:
%var4 = 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 %var4, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0))
%var5 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i32 0, i32 0))
%var6 = call i32 @js_create_text(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.4, i32 0, i32 0))
call void @js_append_child(i32 %var5, i32 %var6)
call void @js_append_child(i32 %var4, i32 %var5)
%var7 = 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 %var7, 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.6, i32 0, i32 0))
%var8 = call i32 @js_create_text(i8* getelementptr inbounds ([65 x i8], [65 x i8]* @.str.7, i32 0, i32 0))
call void @js_append_child(i32 %var7, i32 %var8)
call void @js_append_child(i32 %var4, i32 %var7)
%var9 = 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 %var9, 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.8, i32 0, i32 0))
%var10 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.9, i32 0, i32 0))
call void @js_bind_event(i32 %var10, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.10, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.11, i32 0, i32 0))
%var11 = call i32 @js_create_text(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.12, i32 0, i32 0))
call void @js_append_child(i32 %var10, i32 %var11)
call void @js_append_child(i32 %var9, i32 %var10)
%var12 = 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 %var12, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.13, i32 0, i32 0))
; TODO: Format f-string with signal count
%var13 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.14, i32 0, i32 0))
call void @js_append_child(i32 %var12, i32 %var13)
call void @js_append_child(i32 %var9, i32 %var12)
%var14 = call i32 @js_create_element(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.9, i32 0, i32 0))
call void @js_bind_event(i32 %var14, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.10, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.15, i32 0, i32 0))
%var15 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.16, i32 0, i32 0))
call void @js_append_child(i32 %var14, i32 %var15)
call void @js_append_child(i32 %var9, i32 %var14)
call void @js_append_child(i32 %var4, i32 %var9)
%var16 = 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 %var16, 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.17, i32 0, i32 0))
%var17 = call i32 @js_create_text(i8* getelementptr inbounds ([49 x i8], [49 x i8]* @.str.18, i32 0, i32 0))
call void @js_append_child(i32 %var16, i32 %var17)
call void @js_append_child(i32 %var4, i32 %var16)
%var18 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.19, i32 0, i32 0))
call void @js_set_attribute(i32 %var18, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.20, i32 0, i32 0))
%var19 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.21, i32 0, i32 0))
%var20 = call i32 @js_create_text(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @.str.22, i32 0, i32 0))
call void @js_append_child(i32 %var19, i32 %var20)
call void @js_append_child(i32 %var18, i32 %var19)
%var21 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.21, i32 0, i32 0))
%var22 = call i32 @js_create_text(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.23, i32 0, i32 0))
call void @js_append_child(i32 %var21, i32 %var22)
call void @js_append_child(i32 %var18, i32 %var21)
%var23 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.21, i32 0, i32 0))
%var24 = call i32 @js_create_text(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.24, i32 0, i32 0))
call void @js_append_child(i32 %var23, i32 %var24)
call void @js_append_child(i32 %var18, i32 %var23)
%var25 = call i32 @js_create_element(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.21, i32 0, i32 0))
%var26 = call i32 @js_create_text(i8* getelementptr inbounds ([39 x i8], [39 x i8]* @.str.25, i32 0, i32 0))
call void @js_append_child(i32 %var25, i32 %var26)
call void @js_append_child(i32 %var18, i32 %var25)
call void @js_append_child(i32 %var4, i32 %var18)
ret i32 %var4
%var11 = getelementptr inbounds [4 x i8], [4 x i8]* @.str.1, i32 0, i32 0
%var10 = call i32 @js_create_element(i8* %var11)
%var12 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.2, i32 0, i32 0
%var13 = getelementptr inbounds [10 x i8], [10 x i8]* @.str.3, i32 0, i32 0
call void @js_set_attribute(i32 %var10, i8* %var12, i8* %var13)
%var15 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.4, i32 0, i32 0
%var14 = call i32 @js_create_element(i8* %var15)
%var16 = call i32 @js_create_text(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str.5, i32 0, i32 0))
call void @js_append_child(i32 %var14, i32 %var16)
call void @js_append_child(i32 %var10, i32 %var14)
%var18 = getelementptr inbounds [2 x i8], [2 x i8]* @.str.6, i32 0, i32 0
%var17 = call i32 @js_create_element(i8* %var18)
%var19 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.2, i32 0, i32 0
%var20 = getelementptr inbounds [13 x i8], [13 x i8]* @.str.7, i32 0, i32 0
call void @js_set_attribute(i32 %var17, i8* %var19, i8* %var20)
%var21 = call i32 @js_create_text(i8* getelementptr inbounds ([65 x i8], [65 x i8]* @.str.8, i32 0, i32 0))
call void @js_append_child(i32 %var17, i32 %var21)
call void @js_append_child(i32 %var10, i32 %var17)
%var23 = getelementptr inbounds [4 x i8], [4 x i8]* @.str.1, i32 0, i32 0
%var22 = call i32 @js_create_element(i8* %var23)
%var24 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.2, i32 0, i32 0
%var25 = getelementptr inbounds [13 x i8], [13 x i8]* @.str.9, i32 0, i32 0
call void @js_set_attribute(i32 %var22, i8* %var24, i8* %var25)
%var27 = getelementptr inbounds [7 x i8], [7 x i8]* @.str.10, i32 0, i32 0
%var26 = call i32 @js_create_element(i8* %var27)
%var28 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.11, i32 0, i32 0
%var29 = getelementptr inbounds [10 x i8], [10 x i8]* @.str.12, i32 0, i32 0
call void @js_bind_event(i32 %var26, i8* %var28, i8* %var29)
%var30 = call i32 @js_create_text(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.13, i32 0, i32 0))
call void @js_append_child(i32 %var26, i32 %var30)
call void @js_append_child(i32 %var22, i32 %var26)
%var32 = getelementptr inbounds [2 x i8], [2 x i8]* @.str.6, i32 0, i32 0
%var31 = call i32 @js_create_element(i8* %var32)
%var33 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.2, i32 0, i32 0
%var34 = getelementptr inbounds [16 x i8], [16 x i8]* @.str.14, i32 0, i32 0
call void @js_set_attribute(i32 %var31, i8* %var33, i8* %var34)
%var35 = getelementptr inbounds [8 x i8], [8 x i8]* @.str.0, i32 0, i32 0
%var36 = load i32, i32* @signal_TextInput_count
%var37 = call i32 @js_create_text_with_int(i8* %var35, i32 %var36)
store i32 %var37, i32* @reactive_text_0_node
call void @js_append_child(i32 %var31, i32 %var37)
call void @js_append_child(i32 %var22, i32 %var31)
%var39 = getelementptr inbounds [7 x i8], [7 x i8]* @.str.10, i32 0, i32 0
%var38 = call i32 @js_create_element(i8* %var39)
%var40 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.11, i32 0, i32 0
%var41 = getelementptr inbounds [10 x i8], [10 x i8]* @.str.15, i32 0, i32 0
call void @js_bind_event(i32 %var38, i8* %var40, i8* %var41)
%var42 = call i32 @js_create_text(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.16, i32 0, i32 0))
call void @js_append_child(i32 %var38, i32 %var42)
call void @js_append_child(i32 %var22, i32 %var38)
call void @js_append_child(i32 %var10, i32 %var22)
%var44 = getelementptr inbounds [2 x i8], [2 x i8]* @.str.6, i32 0, i32 0
%var43 = call i32 @js_create_element(i8* %var44)
%var45 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.2, i32 0, i32 0
%var46 = getelementptr inbounds [5 x i8], [5 x i8]* @.str.17, i32 0, i32 0
call void @js_set_attribute(i32 %var43, i8* %var45, i8* %var46)
%var47 = call i32 @js_create_text(i8* getelementptr inbounds ([49 x i8], [49 x i8]* @.str.18, i32 0, i32 0))
call void @js_append_child(i32 %var43, i32 %var47)
call void @js_append_child(i32 %var10, i32 %var43)
%var49 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.19, i32 0, i32 0
%var48 = call i32 @js_create_element(i8* %var49)
%var50 = getelementptr inbounds [6 x i8], [6 x i8]* @.str.2, i32 0, i32 0
%var51 = getelementptr inbounds [10 x i8], [10 x i8]* @.str.20, i32 0, i32 0
call void @js_set_attribute(i32 %var48, i8* %var50, i8* %var51)
%var53 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.21, i32 0, i32 0
%var52 = call i32 @js_create_element(i8* %var53)
%var54 = call i32 @js_create_text(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @.str.22, i32 0, i32 0))
call void @js_append_child(i32 %var52, i32 %var54)
call void @js_append_child(i32 %var48, i32 %var52)
%var56 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.21, i32 0, i32 0
%var55 = call i32 @js_create_element(i8* %var56)
%var57 = call i32 @js_create_text(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str.23, i32 0, i32 0))
call void @js_append_child(i32 %var55, i32 %var57)
call void @js_append_child(i32 %var48, i32 %var55)
%var59 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.21, i32 0, i32 0
%var58 = call i32 @js_create_element(i8* %var59)
%var60 = call i32 @js_create_text(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str.24, i32 0, i32 0))
call void @js_append_child(i32 %var58, i32 %var60)
call void @js_append_child(i32 %var48, i32 %var58)
%var62 = getelementptr inbounds [3 x i8], [3 x i8]* @.str.21, i32 0, i32 0
%var61 = call i32 @js_create_element(i8* %var62)
%var63 = call i32 @js_create_text(i8* getelementptr inbounds ([39 x i8], [39 x i8]* @.str.25, i32 0, i32 0))
call void @js_append_child(i32 %var61, i32 %var63)
call void @js_append_child(i32 %var48, i32 %var61)
call void @js_append_child(i32 %var10, i32 %var48)
ret i32 %var10
}
; Main entry point