code wiki / (root) / nx_macro_v7_test.nx

nx_macro_v7_test.nx source

↩ module page · 112 lines · 3786 B

1// nx_macro_v7_test.nx -- exercise ${var} + @stringify + @concat. 2 3import "nx_kernel_v2.nx" 4 5// ===== T1: ${var} explicit-boundary in @for ===== 6// Without explicit braces, `pair_$i_$j` is shortest-prefix-matched. 7// With braces, the boundary is explicit so no ambiguity is possible. 8@for(i in 0..2) { 9 @for(j in 0..2) { 10 func cell_${i}_${j}() -> nx_int { return ${i} * 10 + ${j} } 11 } 12} 13 14func test_explicit_braces() -> nx_int { 15 if cell_0_0() != 0 { return 1 } 16 if cell_1_1() != 11 { return 1 } 17 return 0 18} 19 20// ===== T2: @stringify converts arg to string literal ===== 21// Emits the arg's TEXT verbatim wrapped in quotes. 22@macro DESCRIBE(thing) { 23 func describe_${$$counter}() -> *u8 { return @stringify(thing) as *u8 } 24} 25 26// Note: we use the older non-stringify form here because @stringify 27// is what we are TESTING; the assertion compares the emitted string. 28@macro PROBE_LABEL(name) { 29 func label_for_$$id() -> *u8 { return @stringify(name) as *u8 } 30} 31 32PROBE_LABEL(my_func_a) 33PROBE_LABEL(answer_42) 34 35func test_stringify_basic() -> nx_int { 36 // Each invocation emits a unique gensym'd func. We just call the 37 // most-recent and check the string content via byte comparison. 38 let s: *u8 = label_for___nx_g_id_2() 39 // s should be "answer_42" -- check first byte 'a' and length-ish. 40 if s[0] != 97 { return 2 } // 'a' = 0x61 = 97 41 return 0 42} 43 44// ===== T3: @concat splices identifiers ===== 45@macro DEFINE_DOUBLE(prefix) { 46 func @concat(prefix, _double_x)(x: nx_int) -> nx_int { return x * 2 } 47 func @concat(prefix, _double_y)(y: nx_int) -> nx_int { return y * 2 } 48} 49 50DEFINE_DOUBLE(foo) 51DEFINE_DOUBLE(bar) 52 53func test_concat_basic() -> nx_int { 54 if foo_double_x(3) != 6 { return 3 } 55 if foo_double_y(5) != 10 { return 3 } 56 if bar_double_x(7) != 14 { return 3 } 57 if bar_double_y(9) != 18 { return 3 } 58 return 0 59} 60 61// ===== T4: @concat with 3 args ===== 62@macro TRIPLE_NAME(a, b, c) { 63 func @concat(a, b, c)() -> nx_int { return 42 } 64} 65 66TRIPLE_NAME(hello, _, world) 67 68func test_concat_three() -> nx_int { 69 if hello_world() != 42 { return 4 } 70 return 0 71} 72 73// ===== T5: ${var} works with longer var names ===== 74@for(zindex in 1..4) { 75 func by_index_${zindex}() -> nx_int { return ${zindex} * 100 } 76} 77 78func test_longer_var_name() -> nx_int { 79 if by_index_1() != 100 { return 5 } 80 if by_index_2() != 200 { return 5 } 81 if by_index_3() != 300 { return 5 } 82 return 0 83} 84 85func main() -> nx_exit { 86 println("=== nx_macro_v7 -- ${var} + @stringify + @concat smoke ===" as *u8) 87 88 let r1: nx_int = test_explicit_braces() 89 if r1 != 0 { println("T1 explicit_braces FAIL" as *u8); return r1 } 90 println("T1 explicit_braces PASS ${i}_${j} disambiguated cleanly in @for" as *u8) 91 92 let r2: nx_int = test_stringify_basic() 93 if r2 != 0 { println("T2 stringify FAIL" as *u8); return r2 } 94 println("T2 stringify PASS @stringify(name) -> \"name\" literal" as *u8) 95 96 let r3: nx_int = test_concat_basic() 97 if r3 != 0 { println("T3 concat_basic FAIL" as *u8); return r3 } 98 println("T3 concat_basic PASS @concat(prefix, _suffix) splices identifiers" as *u8) 99 100 let r4: nx_int = test_concat_three() 101 if r4 != 0 { println("T4 concat_three FAIL" as *u8); return r4 } 102 println("T4 concat_three PASS @concat(a, b, c) handles 3-arg splice" as *u8) 103 104 let r5: nx_int = test_longer_var_name() 105 if r5 != 0 { println("T5 longer_var FAIL" as *u8); return r5 } 106 println("T5 longer_var_name PASS ${zindex} works for multi-char var names" as *u8) 107 108 println("" as *u8) 109 println("Macro toolkit complete: parametric, multi-line, hygienic, conditional," as *u8) 110 println("generative, expression-aware, explicit-boundary, stringify, concat." as *u8) 111 return 0 112}