code wiki / _hdl_build / nx_xlsx_formula_gate.nx
nx_xlsx_formula_gate.nx source
↩ module page · 167 lines · 9097 B
1// nx_xlsx_formula_gate.nx -- gate for SPREADSHEET FORMULAS (office census OF-S3, "THE core spreadsheet
2// feature"). fromtsv turns '='-cells into real SpreadsheetML <f> cells with a computed cached <v> (Q4
3// fixed-point): SUM/AVERAGE/MIN/MAX/COUNT, + - * / ( ) unary-, refs, ranges, formula->formula chains.
4// Rows: 1 write+raw <f>/<v> pins 2 read shows computed values 3 dispatcher html shows totals
5// 4 NEG cycle LOUD 5 NEG div-0 LOUD 6 NEG bad-ref LOUD 7 determinism
6// Q4 pins: SUM=1030.25 · *0.1=103.025 · chain=1133.275 · AVERAGE floors to 343.4166 · COUNT=3 ·
7// (MAX-MIN)/2=140.125. license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_gate_verdict.nx"
10
11func fg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8) { n=n+1 } return n }
12func fg_p(s: *u8) -> i64 { sys_write(1, s, fg_slen(s)); return 0 }
13func fg_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8) { dst[off+i]=s[i]; i=i+1 } return off+i }
14func fg_catn(dst: *u8, off: i64, v: i64) -> i64 {
15 var o: i64=off; var m: i64=v; if m<0 { dst[o]=45 as u8; o=o+1; m=0-m }
16 let t: *u8=sys_mmap(28); var k: i64=0; if m==0 { t[0]=48 as u8; k=1 }
17 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
18 var i: i64=0; while i<k { dst[o+i]=t[k-1-i]; i=i+1 } return o+k
19}
20func fg_write(path: *u8, content: *u8) -> i64 {
21 let fd: i64=sys_openat_wr(path, 0x1a4); if fd<0 { return 0-1 }
22 sys_write(fd, content, fg_slen(content)); sys_close(fd); return 0
23}
24func fg_readall(path: *u8, szout: *i64) -> *u8 {
25 let fd: i64=sys_openat_rd(path); if fd<0 { szout[0]=0-1; return 0 as *u8 }
26 let buf: *u8=sys_mmap(4194304); var got: i64=0; var n: i64=1
27 while n>0 { n=sys_read(fd,(buf as i64+got) as *u8,131072); if n>0 { got=got+n } }
28 sys_close(fd); szout[0]=got; return buf
29}
30func fg_runv(elf: *u8, args: *i64, outpath: *u8) -> i64 {
31 let pid: i64=sys_fork()
32 if pid==0 {
33 if (outpath as i64)!=0 { let ofd: i64=sys_openat_wr(outpath,0x1a4); if ofd>=0 { sys_dup3(ofd,1,0); sys_dup3(ofd,2,0) } }
34 let argv: *i64=sys_mmap(128) as *i64
35 argv[0]=elf as i64; var i: i64=0; var go: i64=1
36 while go==1 { if args[i]==0 { go=0 } else { argv[i+1]=args[i]; i=i+1 } }
37 argv[i+1]=0
38 let envp: *i64=sys_mmap(16) as *i64; envp[0]=0
39 sys_execve(elf, argv, envp); sys_exit(127)
40 }
41 let st: *i64=sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
42 let sig: i64=st[0]&0x7f; if sig!=0 { return 128+sig }
43 return (st[0]>>8)&0xff
44}
45func fg_has(path: *u8, needle: *u8) -> i64 {
46 let szp: *i64=sys_mmap(16) as *i64; let b: *u8=fg_readall(path, szp); let sz: i64=szp[0]
47 let n: i64=fg_slen(needle); if sz<n { return 0 }
48 var i: i64=0
49 while i+n<=sz { var ok: i64=1; var j: i64=0; while j<n { if b[i+j]!=needle[j] { ok=0; j=n } else { j=j+1 } } if ok==1 { return 1 } i=i+1 }
50 return 0
51}
52func fg_fileeq(p1: *u8, p2: *u8) -> i64 {
53 let s1: *i64=sys_mmap(16) as *i64
54 let s2: *i64=sys_mmap(16) as *i64
55 let b1: *u8=fg_readall(p1, s1)
56 let b2: *u8=fg_readall(p2, s2)
57 if s1[0] != s2[0] { return 0 }
58 if s1[0]<=0 { return 0 }
59 var i: i64=0
60 while i<s1[0] { if b1[i] != b2[i] { return 0 } i=i+1 }
61 return 1
62}
63func fg_args4(a1: *u8, a2: *u8, a3: *u8, a4: *u8) -> *i64 {
64 let a: *i64=sys_mmap(64) as *i64; a[0]=a1 as i64; a[1]=a2 as i64; a[2]=a3 as i64; a[3]=a4 as i64; a[4]=0; return a
65}
66func fg_row(name: *u8, pass: i64) -> i64 {
67 fg_p("ROW " as *u8); fg_p(name); if pass==1 { fg_p(" PASS\n" as *u8) } else { fg_p(" FAIL\n" as *u8) } return pass
68}
69
70func main(argc: i64, argv: *i64) -> i64 {
71 fg_p("=== XLSX FORMULA GATE: '='-cells -> real <f> + computed <v> (Q4); chains; LOUD cycle/div0/badref ===\n" as *u8)
72 let xl: *u8="buildroot/_build/nx_xlsx.sov.elf" as *u8
73 let pr: i64=sys_openat_rd(xl)
74 if pr>=0 { sys_close(pr) } else {
75 fg_p(" instrument missing -> rebuilding\n" as *u8)
76 fg_runv("_offc/nx_sov_build_run.elf" as *u8, fg_args4("nx_xlsx" as *u8, "--build-only" as *u8, 0 as *u8, 0 as *u8), "/tmp/fg_rebuild.out" as *u8)
77 }
78
79 fg_write("/tmp/fg_budget.tsv" as *u8, "Item\x09Cost\nVenue\x09350\nCatering\x09480.25\nMusic\x09200\nSubtotal\x09=SUM(B2:B4)\nFee\x09=B5*0.1\nTotal\x09=B5+B6\nAvg\x09=AVERAGE(B2:B4)\nCnt\x09=COUNT(B2:B4)\nSpread\x09=(MAX(B2:B4)-MIN(B2:B4))/2\n" as *u8)
80
81 var pass: i64=0
82 var r: i64=0
83
84 // row 1: write + the raw STORED xlsx carries real <f> cells with the pinned computed <v>
85 let rc1: i64=fg_runv(xl, fg_args4("fromtsv" as *u8, "/tmp/fg_budget.tsv" as *u8, "/tmp/fg_budget.xlsx" as *u8, 0 as *u8), "/tmp/fg_r1.txt" as *u8)
86 r=0
87 if rc1==0 { if fg_has("/tmp/fg_r1.txt" as *u8, "XLSX-WRITE-OK" as *u8)==1 {
88 if fg_has("/tmp/fg_budget.xlsx" as *u8, "<f>SUM(B2:B4)</f><v>1030.25</v>" as *u8)==1 {
89 if fg_has("/tmp/fg_budget.xlsx" as *u8, "<f>B5+B6</f><v>1133.275</v>" as *u8)==1 {
90 if fg_has("/tmp/fg_budget.xlsx" as *u8, "<f>AVERAGE(B2:B4)</f><v>343.4166</v>" as *u8)==1 {
91 if fg_has("/tmp/fg_budget.xlsx" as *u8, "<v>140.125</v>" as *u8)==1 { r=1 }
92 }
93 }
94 }
95 } }
96 pass=pass+fg_row("write-formula-cells" as *u8, r)
97
98 // row 2: read resolves formula cells to the computed values
99 let rc2: i64=fg_runv(xl, fg_args4("read" as *u8, "/tmp/fg_budget.xlsx" as *u8, 0 as *u8, 0 as *u8), "/tmp/fg_r2.txt" as *u8)
100 r=0
101 if rc2==0 { if fg_has("/tmp/fg_r2.txt" as *u8, "Subtotal\x091030.25" as *u8)==1 {
102 if fg_has("/tmp/fg_r2.txt" as *u8, "Total\x091133.275" as *u8)==1 {
103 if fg_has("/tmp/fg_r2.txt" as *u8, "Cnt\x093" as *u8)==1 { r=1 }
104 }
105 } }
106 pass=pass+fg_row("read-computed" as *u8, r)
107
108 // row 3: registry dispatch renders the computed values in the html table
109 let rc3: i64=fg_runv("_offc/nx_doc_view.elf" as *u8, fg_args4("/tmp/fg_budget.xlsx" as *u8, "/tmp/fg_view.html" as *u8, "/sample.xlsx" as *u8, 0 as *u8), "/tmp/fg_r3.txt" as *u8)
110 r=0
111 if rc3==0 { if fg_has("/tmp/fg_view.html" as *u8, "<td>1133.275</td>" as *u8)==1 {
112 if fg_has("/tmp/fg_view.html" as *u8, "<td>103.025</td>" as *u8)==1 { r=1 }
113 } }
114 pass=pass+fg_row("html-computed" as *u8, r)
115
116 // row 4 (neg): CYCLE loud-fails
117 fg_write("/tmp/fg_cycle.tsv" as *u8, "A\x09B\n=B2\x09=A2\n" as *u8)
118 let rc4: i64=fg_runv(xl, fg_args4("fromtsv" as *u8, "/tmp/fg_cycle.tsv" as *u8, "/tmp/fg_x1.xlsx" as *u8, 0 as *u8), "/tmp/fg_r4.txt" as *u8)
119 r=0
120 if rc4 != 0 { if fg_has("/tmp/fg_r4.txt" as *u8, "XLSX-FORMULA-FAIL kind=3" as *u8)==1 { r=1 } }
121 pass=pass+fg_row("neg-cycle-loud" as *u8, r)
122
123 // row 5 (neg): div-0 loud-fails
124 fg_write("/tmp/fg_div0.tsv" as *u8, "X\n=1/0\n" as *u8)
125 let rc5: i64=fg_runv(xl, fg_args4("fromtsv" as *u8, "/tmp/fg_div0.tsv" as *u8, "/tmp/fg_x2.xlsx" as *u8, 0 as *u8), "/tmp/fg_r5.txt" as *u8)
126 r=0
127 if rc5 != 0 { if fg_has("/tmp/fg_r5.txt" as *u8, "XLSX-FORMULA-FAIL kind=4" as *u8)==1 { r=1 } }
128 pass=pass+fg_row("neg-div0-loud" as *u8, r)
129
130 // row 6 (neg): ref to an empty/text cell loud-fails (LOUD beats silently-wrong money)
131 fg_write("/tmp/fg_badref.tsv" as *u8, "X\n=Z99\n" as *u8)
132 let rc6: i64=fg_runv(xl, fg_args4("fromtsv" as *u8, "/tmp/fg_badref.tsv" as *u8, "/tmp/fg_x3.xlsx" as *u8, 0 as *u8), "/tmp/fg_r6.txt" as *u8)
133 r=0
134 if rc6 != 0 { if fg_has("/tmp/fg_r6.txt" as *u8, "XLSX-FORMULA-FAIL kind=2" as *u8)==1 { r=1 } }
135 pass=pass+fg_row("neg-badref-loud" as *u8, r)
136
137 // row 7: determinism (formula path included)
138 fg_runv(xl, fg_args4("fromtsv" as *u8, "/tmp/fg_budget.tsv" as *u8, "/tmp/fg_budget2.xlsx" as *u8, 0 as *u8), "/tmp/fg_r7.txt" as *u8)
139 r=fg_fileeq("/tmp/fg_budget.xlsx" as *u8, "/tmp/fg_budget2.xlsx" as *u8)
140 pass=pass+fg_row("determinism" as *u8, r)
141
142 let permil: i64=(pass*1000)/7
143 let logfd: i64=sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4)
144 var fdi: i64=0
145 while fdi<2 {
146 var fd: i64=1; if fdi==1 { fd=logfd }
147 if fd>0 {
148 let line: *u8=sys_mmap(256); var o: i64=0
149 o=fg_cat(line,o,"XLSX-FORMULA-GATE epoch=" as *u8); o=fg_catn(line,o,sys_now_realtime_sec())
150 o=fg_cat(line,o," rows=7 pass=" as *u8); o=fg_catn(line,o,pass)
151 o=fg_cat(line,o," permil=" as *u8); o=fg_catn(line,o,permil)
152 if pass==7 { o=fg_cat(line,o," verdict=GREEN\n" as *u8) } else { o=fg_cat(line,o," verdict=RED\n" as *u8) }
153 sys_write(fd, line, o)
154 }
155 fdi=fdi+1
156 }
157 if logfd>0 { sys_close(logfd) }
158 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
159 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
160 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
161 let ctr__dry: *i64 = gv_ctr()
162 ctr__dry[0] = pass
163 ctr__dry[1] = 7
164 let rc__dry: i64 = gv_verdict("XLSX-FORMULA-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
165 sys_exit(rc__dry)
166 return rc__dry
167}