code wiki / (root) / nx_main.nx

nx_main.nx source

↩ module page · 90 lines · 3403 B

1// main.nx -- NishiLang-side compiler driver. 2// 3// Pipeline: source text -> lex -> parse -> opt -> regalloc -> riscv 4// -> write-to-stdout. Stands in for main.c. Real source-file reading 5// (openat + read + grow buffer) is a follow-up; this turn drives the 6// pipeline from an in-memory source string so the whole stack of 7// nx-side modules links cleanly through a single entry point. 8// 9// Once file I/O is in syscalls.nx and string concatenation lands, this 10// driver becomes the authoritative NishiLang compiler -- the C nxc2 11// retires behind it. 12 13// nx_safety_envelope: 14// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 15// sil_target: SIL1 16// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 17// verdict: NOT_YET_EVALUATED 18 19import "nx_syscalls.nx" 20import "nx_types.nx" 21import "nx_lex_kinds.nx" 22import "nx_ir.nx" 23import "nx_tokenizer.nx" 24import "nx_parse.nx" 25import "nx_opt.nx" 26import "nx_regalloc.nx" 27import "nx_riscv.nx" 28 29// Compile one source string end-to-end, emit asm to stdout. Each 30// function gets opt_run + regalloc + emit_function. Output format 31// matches the C-side backend's .s output closely enough that a nxasm 32// pass can assemble it to ELF. 33func compile(src: *u8) -> i64 { 34 let toks: *Tok = lex_source(src, 4096) 35 if toks == (0 as *Tok) { return 1 } 36 37 let m: *Module = parse_module(toks, 0 as *Module) 38 if m == (0 as *Module) { return 2 } 39 40 let o: *OutBuf = out_new(65536) 41 out_str(o, "# Auto-generated by nxc2.nx (NishiLang-side driver).\n") 42 43 var fi: i64 = 0 44 while fi < m.n_functions { 45 let fn_base: i64 = m.functions as i64 46 let f: *Function = (fn_base + fi * 176) as *Function 47 48 opt_run(f) 49 50 let locs_raw: *u8 = sys_mmap(f.n_values * 24 + 64) 51 let locs: *ValueLoc = locs_raw as *ValueLoc 52 53 let cs_raw: *u8 = sys_mmap(16) 54 let cs: *i64 = cs_raw as *i64 55 *cs = 0 56 let cs_fpr_raw: *u8 = sys_mmap(16) 57 let cs_fpr: *i64 = cs_fpr_raw as *i64 58 *cs_fpr = 0 59 60 let sb_raw: *u8 = sys_mmap(16) 61 let sb: *i64 = sb_raw as *i64 62 *sb = 0 63 64 regalloc_function(f, locs, cs, cs_fpr, sb) 65 66 // Real function name: ir_function_new stashed the *u8 name 67 // pointer in f.name_start so the driver can emit `name:` as 68 // the label instead of the hardcoded "main". Frame size + 69 // ra slot are still stubbed (16/8); per-function layout is 70 // a follow-up that threads the regalloc result through. 71 let fn_name_addr: i64 = f.name_start 72 let fn_name: *u8 = fn_name_addr as *u8 73 emit_function(f, locs, o, fn_name, 16, 8, *cs, *cs_fpr) 74 fi = fi + 1 75 } 76 77 sys_write(1, o.buf, o.pos) 78 return 0 79} 80 81func main() -> i64 { 82 // Real NishiLang source covering the breadth of what the 83 // nx-side front-end handles: syscall intrinsic, const folding, 84 // for-loop, function call. The resulting IR exercises every 85 // critical path (lex → parse_module → parse_primary w/ __syscall 86 // → ir_emit_syscall → opt_run → regalloc_function → rv emit w/ 87 // OP_SYSCALL → ecall). 88 let src: *u8 = "const N: i64 = 5\nfunc add(a: i64, b: i64) -> i64 { return a + b }\nfunc main() -> i64 { var acc: i64 = 0\nfor i in 0..N { acc = add(acc, i) }\nreturn __syscall(93, acc, 0, 0, 0, 0, 0) }" 89 return compile(src) 90}