code wiki / (root) / nx_macro_v2_test.nx

nx_macro_v2_test.nx source

↩ module page · 112 lines · 3899 B

1// nx_macro_v2_test.nx -- exercise multi-line {} bodies + $$ident gensym. 2 3import "nx_kernel_v2.nx" 4 5// ===== Multi-line body: emits a whole function definition ===== 6// The { ... } block can span as many lines as needed. Body parser 7// is depth-aware -- nested { } / strings / comments don't trip it up. 8@macro DEFINE_RECT_AREA(name, w, h) { 9 func name() -> nx_int { 10 let area: nx_int = w * h 11 return area 12 } 13} 14 15DEFINE_RECT_AREA(rect_2x3, 2, 3) 16DEFINE_RECT_AREA(rect_5x7, 5, 7) 17 18// ===== Hygienic gensym: $$ident gets a unique suffix per invocation 19// Two invocations of SAFE_DOUBLE produce __nx_g_tmp_N1 and __nx_g_tmp_N2, 20// so multiple expansions in the same scope don't collide. 21@macro SAFE_DOUBLE(x) { 22 let $$tmp: nx_int = x + x 23 return $$tmp 24} 25 26func double_three() -> nx_int { SAFE_DOUBLE(3) } 27func double_seven() -> nx_int { SAFE_DOUBLE(7) } 28 29// ===== Multi-line body that uses BOTH gensym AND parameter substitution 30@macro CHECK_EQ(actual_expr, expected) { 31 let $$got: nx_int = actual_expr 32 if $$got != expected { return 99 } 33} 34 35// ===== A more substantial macro: emit a kernel-axiom helper ===== 36@macro EMIT_CONST_AXIOM(fname, ch, sym_id) { 37 func fname() -> nx_int { 38 let $$t: *Term = nx_term_const(sym_id) 39 return nx_k2_axiom(ch, $$t) 40 } 41} 42 43// ===== Tests ===== 44 45func test_multiline_basic() -> nx_int { 46 let a: nx_int = rect_2x3() 47 if a != 6 { return 1 } 48 let b: nx_int = rect_5x7() 49 if b != 35 { return 1 } 50 return 0 51} 52 53func test_gensym_isolation() -> nx_int { 54 let a: nx_int = double_three() 55 if a != 6 { return 2 } 56 let b: nx_int = double_seven() 57 if b != 14 { return 2 } 58 return 0 59} 60 61func test_gensym_within_one_body() -> nx_int { 62 // CHECK_EQ uses $$got twice in the same body. Both must resolve 63 // to the same gensym'd identifier so the function compiles. 64 let three_doubled: nx_int = 6 65 CHECK_EQ(three_doubled, 6) 66 return 0 67} 68 69// ===== Macro that builds + registers an axiom in one call ===== 70// $$t is gensym'd so concurrent uses can't collide with caller-scope. 71@macro REGISTER_CONST(ch, sym_id) { 72 let $$t: *Term = nx_term_const(sym_id) 73 let _idx: nx_int = nx_k2_axiom(ch, $$t) 74} 75 76func test_multiple_axiom_macros() -> nx_int { 77 let ch: *K2Chain = nx_k2_chain_new(8) 78 REGISTER_CONST(ch, 7777) 79 REGISTER_CONST(ch, 8888) 80 if ch.n != 2 { return 4 } 81 return 0 82} 83 84func main() -> nx_exit { 85 println("=== nx_macro_v2 -- multi-line bodies + $$ident gensym ===" as *u8) 86 87 let r1: nx_int = test_multiline_basic() 88 if r1 != 0 { println("T1 multiline_basic FAIL" as *u8); return r1 } 89 println("T1 multiline_basic PASS rect_2x3()=6, rect_5x7()=35 from {} macros" as *u8) 90 91 let r2: nx_int = test_gensym_isolation() 92 if r2 != 0 { println("T2 gensym_isolation FAIL" as *u8); return r2 } 93 println("T2 gensym_isolation PASS two SAFE_DOUBLE invocations get distinct $$tmp" as *u8) 94 95 let r3: nx_int = test_gensym_within_one_body() 96 if r3 != 0 { println("T3 gensym_within_one_body FAIL" as *u8); return r3 } 97 println("T3 gensym_one_body PASS $$got used twice in CHECK_EQ resolves to one ident" as *u8) 98 99 let r4: nx_int = test_multiple_axiom_macros() 100 if r4 != 0 { println("T4 multiple_axiom_macros FAIL" as *u8); return r4 } 101 println("T4 axiom_macro PASS caller-scope $$ident works alongside macro-scope" as *u8) 102 103 println("" as *u8) 104 println("=== Foundational metaprogramming v2 verified ===" as *u8) 105 println(" @macro NAME(args) { multi-line body" as *u8) 106 println(" let $$tmp: nx_int = ... hygienic local" as *u8) 107 println(" return $$tmp" as *u8) 108 println(" }" as *u8) 109 println(" Bodies can declare their own functions, locals, control flow." as *u8) 110 println(" $$ident produces __nx_g_ident_<N> per invocation -- collision-free." as *u8) 111 return 0 112}