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}