nx_compile_wat.nx source
↩ module page · 186 lines · 8093 B
1// nx_compile_wat.nx -- SOVEREIGN source-file driver for the NishiLang WAT (WebAssembly) backend.
2// The NishiLang counterpart of nxc2.exe's --target wat path: reads a .nx (import-expanded), runs
3// lex_source -> parse_module -> opt_run -> wat_emit_module (nx_wasm.nx, now f32-capable), writes WAT to stdout.
4// This WIRES the sovereign wat emitter into a usable driver so the wat path is no longer C-only. The wat is then
5// fed to nx_wat_compiler (.wat -> .wasm, sovereign) for the browser. usage: nx_compile_wat <src.nx> > out.wat
6// license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_types.nx"
9import "nx_lex_kinds.nx"
10import "nx_outbuf.nx"
11import "nx_ir.nx"
12import "nx_tokenizer.nx"
13import "nx_parse.nx"
14import "nx_opt.nx"
15import "nx_ir_dump.nx"
16import "nx_ir_validate.nx"
17import "nx_import.nx"
18import "nx_wasm.nx"
19import "nx_wasm_layout_wat_lib.nx"
20const WAT_MAGIC_4096: i64 = 4096
21const WAT_MAGIC_262144: i64 = 262144
22
23const WAT_SRC_CAP: i64 = 2097152
24const WAT_OUT_CAP: i64 = 16777216
25const WAT_EXPAND_CAP: i64 = 4194304
26
27func watd_log(msg: *u8, n: i64) -> i64 { return sys_write(2, msg, n) }
28// ★DERIVE THE LENGTH, NEVER HAND-COUNT IT BESIDE THE LITERAL. The first cut of the --shared refusals passed
29// counted lengths (58, 55, 69) that were each a character or two short, so every message was TRUNCATED and
30// the gate teeth searching for the refusal text failed while the refusal itself was working perfectly -- a
31// hand-counted length is a second copy of the literal's shape and the two drift the moment either changes.
32func watd_logs(msg: *u8) -> i64 {
33 var n: i64 = 0
34 while msg[n] != (0 as u8) { n = n + 1 }
35 return sys_write(2, msg, n)
36}
37// decimal argv -> i64; stops at the first non-digit, so a malformed value reads as the prefix it did parse
38// and the caller's range checks refuse it by name rather than silently taking a wrong size.
39func watd_atoi(s: *u8) -> i64 {
40 var v: i64 = 0
41 var i: i64 = 0
42 while s[i] != (0 as u8) {
43 let c: i64 = s[i] as i64
44 if c < 48 { return v }
45 if c > 57 { return v }
46 v = v * 10 + (c - 48)
47 i = i + 1
48 }
49 return v
50}
51func watd_equal(a: *u8,b: *u8) -> i64 {
52 var i: i64=0
53 while a[i]==b[i] {
54 if a[i]==(0 as u8) { return 1 }
55 i=i+1
56 }
57 return 0
58}
59func watd_read_stdin(buf: *u8, cap: i64) -> i64 {
60 var total: i64 = 0
61 let BUDGET: i64 = (cap / WAT_MAGIC_4096) + 16
62 var iter: i64 = 0
63 var done: i64 = 0
64 while done == 0 {
65 if iter >= BUDGET { done = 1 }
66 if done == 0 {
67 if total >= cap { done = 1 }
68 if done == 0 {
69 let dst: *u8 = ((buf as i64) + total) as *u8
70 let got: i64 = sys_read(0, dst, cap - total)
71 if got < 0 { done = 1 }
72 if got == 0 { done = 1 }
73 if got > 0 { total = total + got }
74 }
75 }
76 iter = iter + 1
77 }
78 return total
79}
80
81func main(argc: i64, argv: *i64) -> i64 {
82 var in_buf: *u8 = 0 as *u8
83 var in_n: i64 = 0
84 var path_addr: i64 = 0
85 var out_addr: i64 = 0
86 var layout_record: i64 = 0
87 var i: i64 = 1
88 while i < argc {
89 let arg: *u8 = argv[i] as *u8
90 if watd_equal(arg,"--layout-record" as *u8)==1 {
91 layout_record=1;i=i+1;continue
92 }
93 let arena_flag: i64=watd_equal(arg,"--arena-pages" as *u8)
94 let limit_flag: i64=watd_equal(arg,"--static-limit-pages" as *u8)
95 if arena_flag==1 || limit_flag==1 {
96 if i+1>=argc { watd_logs("nx_compile_wat: --arena-pages/--static-limit-pages requires one positive decimal page count\n" as *u8); return 11 }
97 let value: i64=wd_parse_pages(argv[i+1] as *u8)
98 if value<1 { watd_logs("nx_compile_wat: arena/static-limit pages must be complete positive decimal integers within wasm32\n" as *u8); return 11 }
99 if arena_flag==1 { wd_arena_pages_flag=value } else { wd_static_limit_pages_flag=value }
100 i=i+2;continue
101 }
102 if arg[0] == 0x2D {
103 if arg[1] == 0x2D { if arg[2] == 0x74 { i = i + 2; continue } }
104 // LN33 scale-down: --nothreads emits the UNSHARED twin of a shared-declaring module (ordinary
105 // memory, atomic calls left as calls to their reference bodies) so one source ships both modules
106 // and the page picks by measured capability. Any other --flag is ignored as before.
107 if arg[1] == 0x2D { if arg[2] == 0x6E { wat_threads_off = 1 } }
108 // GE30 --shared <pages_req> <pages_max>: declare the wasm memory ON THE BUILD LANE rather than in
109 // the source. A DUAL-TARGET module (nx_wasm_craft compiles natively AND to wasm) cannot carry the
110 // LN33 statics at all -- the native lane refuses a non-zero static initializer -- and it should not
111 // have to: one source must build at a sensor's memory and at a supercomputer's, so the size is a
112 // door on a ladder, not a constant. Absent, the module-global path is unchanged.
113 if arg[1] == 0x2D { if arg[2] == 0x73 {
114 if i + 2 < argc {
115 wat_pages_req_flag = watd_atoi(argv[i + 1] as *u8)
116 wat_pages_max_flag = watd_atoi(argv[i + 2] as *u8)
117 wat_shared_req = 1
118 let source_layout: i64=watd_equal(argv[i+1] as *u8,"source" as *u8)
119 if source_layout==1 { wat_pages_req_flag=0 }
120 if wat_pages_req_flag < 1 && source_layout!=1 { watd_logs("nx_compile_wat: --shared <req|source> <max>: req must be >= 1 page or source-derived
121" as *u8); return 11 }
122 if wat_pages_max_flag < wat_pages_req_flag { watd_logs("nx_compile_wat: --shared <req> <max>: max must be >= req
123" as *u8); return 11 }
124 i = i + 2
125 } else {
126 watd_logs("nx_compile_wat: --shared needs two arguments: <pages_req> <pages_max>
127" as *u8)
128 return 11
129 }
130 } }
131 i = i + 1
132 continue
133 }
134 if path_addr == 0 { path_addr = arg as i64 } else { out_addr = arg as i64 }
135 i = i + 1
136 }
137 if path_addr != 0 {
138 let path: *u8 = path_addr as *u8
139 let expand_buf: *u8 = sys_mmap(WAT_EXPAND_CAP)
140 let ctx: *ExpandCtx = expand_ctx_new(expand_buf, WAT_EXPAND_CAP)
141 let rc: i64 = expand_imports(ctx, path)
142 if rc < 0 { watd_log("nx_compile_wat: expand_imports failed\n" as *u8, 38); return 10 }
143 let op: *i64 = ctx.out_pos
144 let end: i64 = *op
145 expand_buf[end] = 0 as u8
146 in_buf = expand_buf
147 in_n = end
148 }
149 if path_addr == 0 {
150 watd_log("nx_compile_wat: usage: nx_compile_wat <src.nx> > out.wat\n" as *u8, 52)
151 return 9
152 }
153 if in_n <= 0 { watd_log("nx_compile_wat: empty input\n" as *u8, 28); return 1 }
154
155 let toks: *Tok = lex_source(in_buf, WAT_MAGIC_262144)
156 if toks == (0 as *Tok) { watd_log("nx_compile_wat: lex_source failed\n" as *u8, 34); return 2 }
157 let m: *Module = parse_module(toks, 0 as *Module)
158 if m == (0 as *Module) { watd_log("nx_compile_wat: parse_module failed\n" as *u8, 36); return 3 }
159 if m.n_functions <= 0 { watd_log("nx_compile_wat: no functions\n" as *u8, 29); return 4 }
160
161 var fi: i64 = 0
162 while fi < m.n_functions {
163 let fn_base: i64 = m.functions as i64
164 let f: *Function = (fn_base + fi * 176) as *Function
165 opt_run(f)
166 fi = fi + 1
167 }
168
169 let o: *OutBuf = out_new(WAT_OUT_CAP)
170 wat_emit_module(m, o)
171 if layout_record==1 {
172 if wl_wat_record(m,wat_mem_pages(m),wat_mem_shared(m),o)==0 {
173 watd_logs("nx_compile_wat: layout record emission refused\n" as *u8)
174 return 12
175 }
176 }
177 if out_addr != 0 {
178 let fd: i64 = sys_openat_wr(out_addr as *u8, 0x1a4)
179 if fd < 0 { watd_log("nx_compile_wat: open out failed\n" as *u8, 32); return 7 }
180 sys_write(fd, o.buf, o.pos)
181 sys_close(fd)
182 } else {
183 sys_write(1, o.buf, o.pos)
184 }
185 return 0
186}