code wiki / (root) / nx_compile_wat.nx

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}