code wiki / _hdl_build / nx_func_compare.nx
nx_func_compare.nx source
↩ module page · 122 lines · 3955 B
1// nx_func_compare.nx -- pure-NishiLang function-equivalence checker.
2//
3// Usage:
4// nx_func_compare <file1> <file2> [<file3> ...] <function_name>
5//
6// For each file, extract the named function's body, normalize away
7// comments and whitespace, compute FNV-1a 64-bit hash. Emit per-file
8// hash + verdict.
9//
10// Verdict EQUIVALENT if all hashes match exactly.
11// Verdict DIVERGE otherwise -- with first hash + first-diff file flagged.
12//
13// This is the substrate-native answer to "are these N functions
14// actually the same?" before consolidation. No grep, no awk, no diff.
15//
16// genealogy_id: fowler_noll_vo_1991_fnv1a + clone_detection_lit
17// lineage_id: content_hash_equivalence_test
18// axioms: NX_AX_REL_TRANSITIVITY (chain hash equalities)
19
20// nx_safety_envelope:
21// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
22// sil_target: SIL1
23// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
24// verdict: NOT_YET_EVALUATED
25
26import "syscalls.nx"
27import "runtime.nx"
28import "nx_extract.nx"
29
30const NX_CMP_NORM_BUF: i64 = 65536
31
32// Emit JSONL summary for one file's function.
33func compare_emit_file(file: *u8, fname: *u8, h: i64) -> i64 {
34 print("{\"file\":\"" as *u8)
35 print(file)
36 print("\",\"function\":\"" as *u8)
37 print(fname)
38 print("\",\"hash\":" as *u8)
39 print_i64(h)
40 println("}" as *u8)
41 return 0
42}
43
44func main(argc: i64, argv: *i64) -> i64 {
45 // argv form: program file1 fname1 file2 fname2 ... fileN fnameN
46 // argc = 1 + 2*N (must be odd, >= 5).
47 if argc < 5 {
48 println("usage: nx_func_compare <file1> <fname1> <file2> <fname2> [...]" as *u8)
49 return 1
50 }
51 if argc - (argc / 2) * 2 != 1 {
52 println("usage: argc must be odd (alternating file fname pairs)" as *u8)
53 return 1
54 }
55 let n_files: i64 = (argc - 1) / 2
56
57 let norm_buf: *u8 = sys_mmap(NX_CMP_NORM_BUF)
58 let out_len: *i64 = (sys_mmap(8)) as *i64
59
60 var first_hash: i64 = 0
61 var have_first: i64 = 0
62 var all_equal: i64 = 1
63 var first_diff_file: *u8 = 0 as *u8
64
65 var fi: i64 = 0
66 while fi < n_files {
67 let path: *u8 = (argv[1 + 2 * fi]) as *u8
68 let fname: *u8 = (argv[1 + 2 * fi + 1]) as *u8
69 out_len[0] = 0
70 let buf: *u8 = sys_read_file(path, out_len)
71 if (buf as i64) == 0 {
72 print("{\"file\":\"" as *u8)
73 print(path)
74 println("\",\"error\":\"read_failed\"}" as *u8)
75 all_equal = 0
76 }
77 if (buf as i64) != 0 {
78 let h: i64 = nx_extract_func_hash(buf, out_len[0], fname, norm_buf)
79 if h == 0 {
80 print("{\"file\":\"" as *u8)
81 print(path)
82 print("\",\"function\":\"" as *u8)
83 print(fname)
84 println("\",\"error\":\"function_not_found\"}" as *u8)
85 all_equal = 0
86 }
87 if h != 0 {
88 compare_emit_file(path, fname, h)
89 if have_first == 0 {
90 first_hash = h
91 have_first = 1
92 }
93 if have_first == 1 {
94 if h != first_hash {
95 all_equal = 0
96 if (first_diff_file as i64) == 0 {
97 first_diff_file = path
98 }
99 }
100 }
101 }
102 }
103 fi = fi + 1
104 }
105
106 // Verdict.
107 print("{\"summary\":true,\"n_files\":" as *u8)
108 print_i64(n_files)
109 print(",\"verdict\":\"" as *u8)
110 if all_equal == 1 { print("EQUIVALENT" as *u8) }
111 if all_equal == 0 { print("DIVERGE" as *u8) }
112 print("\"" as *u8)
113 if all_equal == 0 {
114 if (first_diff_file as i64) != 0 {
115 print(",\"first_diff\":\"" as *u8)
116 print(first_diff_file)
117 print("\"" as *u8)
118 }
119 }
120 println("}" as *u8)
121 return 0
122}