code wiki / _hdl_build / nx_eoe_fn.nx
nx_eoe_fn.nx source
↩ module page · 162 lines · 9436 B
1// nx_eoe_fn.nx -- EMITTER-OF-EMITTERS, GENERALITY RUNG 6: FUNCTIONS + CALL STACK.
2//
3// Rung 5 (006j, nx_eoe_prog) gave the mini-language compositional control flow
4// (nested op/if/while) but a single straight-line main(). This rung gives it a
5// CALL STACK: the spec can DEFINE named functions and CALL them, including functions
6// that call OTHER functions (a real >=2-deep call graph), so emitted programs
7// COMPOSE reusable logic instead of inlining everything. Each function is an
8// acc-transformer `func name(p) -> i64 { var acc = p; <body>; return acc }`; a call
9// is `acc = name(acc)`. Bodies use the full rung-5 grammar (op/if/while) PLUS call,
10// recursively. nx_cc compiles the defs + the call ABI (frames/return) -- delegated
11// to the compiler the team owns.
12//
13// nx_eoe_fn <basename> <start> [def <name> [ <stmt...> ]]... [main] <stmt...>
14// stmt grammar (extends 006j): a<n>|m<n>|s<n> | if <pred> [..] | while <pred> [..]
15// | call <name> (acc = name(acc))
16// top level: zero or more `def <name> [ <body> ]`, then optional `main`, then the
17// main statement list. `[` `]` are their own tokens; everything NESTS.
18// -> emits the func defs (in spec order; a def may call an EARLIER def) + main().
19//
20// no-false-green (X-AUT-006d): a function calling a function (quad=dbl(dbl(p)))
21// exercises a 2-deep stack; tampering the INNER function's body changes the final
22// result THROUGH the nested call -- proving the call ABI really threads values, not
23// a templated constant. Sovereign, no gcc/.sh. HONEST: one i64 param/return per
24// fn (acc-transformer convention), one-armed if, int ops; not yet multi-param/typed
25// /imports. ONE rung -- but the language now has FUNCTIONS. license_tier: ORIGINAL
26import "nx_syscalls.nx"
27const K_MAGIC_262144: i64 = 262144
28
29func efn_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 }
30func efn_catn(dst: *u8, off: i64, v: i64) -> i64 {
31 var o: i64 = off
32 if v < 0 { dst[o] = 45 as u8; o = o + 1; return efn_catn(dst, o, 0 - v) }
33 if v == 0 { dst[o] = 48 as u8; return o + 1 }
34 var m: i64 = v
35 let t: *u8 = sys_mmap(28)
36 var k: i64 = 0
37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
38 var i: i64 = 0
39 while i < k { dst[o+i] = t[k-1-i]; i = i + 1 }
40 return o + k
41}
42func efn_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
43func efn_atoi_from(s: *u8, from: i64) -> i64 {
44 var n: i64 = 0; var i: i64 = from
45 while s[i] != (0 as u8) { if s[i] >= (48 as u8) { if s[i] <= (57 as u8) { n = n * 10 + ((s[i] as i64) - 48) } } i = i + 1 }
46 return n
47}
48func efn_indent(buf: *u8, off: i64, depth: i64) -> i64 {
49 var o: i64 = off; var d: i64 = 0
50 while d < depth { o = efn_cat(buf, o, " " as *u8); d = d + 1 }
51 return o
52}
53func efn_cmp(buf: *u8, off: i64, pred: *u8) -> i64 {
54 var o: i64 = off
55 let pc: i64 = pred[0] as i64
56 if pc == 103 { o = efn_cat(buf, o, "> " as *u8) }
57 if pc == 108 { o = efn_cat(buf, o, "< " as *u8) }
58 if pc == 101 { o = efn_cat(buf, o, "== " as *u8) }
59 o = efn_catn(buf, o, efn_atoi_from(pred, 1))
60 return o
61}
62
63// recursive descent (extends 006j eop_emit_stmts with the `call` statement).
64func efn_emit_stmts(buf: *u8, off: i64, argv: *i64, argc: i64, ti: i64, depth: i64, out_ti: *i64, gid: *i64) -> i64 {
65 var o: i64 = off
66 var i: i64 = ti
67 while i < argc {
68 let tok: *u8 = argv[i] as *u8
69 let c0: i64 = tok[0] as i64
70 if c0 == 93 { i = i + 1; out_ti[0] = i; return o } // ']' end block
71 if c0 == 97 { // 'a' add
72 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = acc + " as *u8); o = efn_catn(buf, o, efn_atoi_from(tok, 1)); o = efn_cat(buf, o, "\n" as *u8); i = i + 1
73 } else { if c0 == 109 { // 'm' mul
74 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = acc * " as *u8); o = efn_catn(buf, o, efn_atoi_from(tok, 1)); o = efn_cat(buf, o, "\n" as *u8); i = i + 1
75 } else { if c0 == 115 { // 's' sub
76 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = acc - " as *u8); o = efn_catn(buf, o, efn_atoi_from(tok, 1)); o = efn_cat(buf, o, "\n" as *u8); i = i + 1
77 } else { if c0 == 99 { // 'c' call <name> -> acc = name(acc)
78 let nm: *u8 = argv[i+1] as *u8
79 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "acc = " as *u8); o = efn_cat(buf, o, nm); o = efn_cat(buf, o, "(acc)\n" as *u8); i = i + 2
80 } else { if c0 == 105 { // 'i' if
81 let pred: *u8 = argv[i+1] as *u8
82 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "if acc " as *u8); o = efn_cmp(buf, o, pred); o = efn_cat(buf, o, " {\n" as *u8)
83 let nti: *i64 = sys_mmap(8) as *i64
84 o = efn_emit_stmts(buf, o, argv, argc, i + 3, depth + 1, nti, gid)
85 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "}\n" as *u8)
86 i = nti[0]
87 } else { if c0 == 119 { // 'w' while
88 let pred: *u8 = argv[i+1] as *u8
89 let myid: i64 = gid[0]; gid[0] = gid[0] + 1
90 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "var g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, ": i64 = 0\n" as *u8)
91 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "while acc " as *u8); o = efn_cmp(buf, o, pred); o = efn_cat(buf, o, " {\n" as *u8)
92 let nti: *i64 = sys_mmap(8) as *i64
93 o = efn_emit_stmts(buf, o, argv, argc, i + 3, depth + 1, nti, gid)
94 o = efn_indent(buf, o, depth + 1); o = efn_cat(buf, o, "g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, " = g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, " + 1\n" as *u8)
95 o = efn_indent(buf, o, depth + 1); o = efn_cat(buf, o, "if g" as *u8); o = efn_catn(buf, o, myid); o = efn_cat(buf, o, " >= 100000 { break }\n" as *u8)
96 o = efn_indent(buf, o, depth); o = efn_cat(buf, o, "}\n" as *u8)
97 i = nti[0]
98 } else { i = i + 1 } } } } } }
99 }
100 out_ti[0] = i
101 return o
102}
103
104func main(argc: i64, argv: *i64) -> i64 {
105 if argc < 3 { efn_p("usage: nx_eoe_fn <basename> <start> [def <name> [ stmts ]]... [main] <stmts>\n" as *u8); return 2 }
106 let base: *u8 = argv[1] as *u8
107 let start: i64 = efn_atoi_from(argv[2] as *u8, 0)
108
109 let path: *u8 = sys_mmap(512)
110 var po: i64 = 0
111 po = efn_cat(path, po, "runtime/_hdl_build/" as *u8)
112 po = efn_cat(path, po, base)
113 po = efn_cat(path, po, ".nx" as *u8)
114 path[po] = 0 as u8
115
116 let buf: *u8 = sys_mmap(K_MAGIC_262144)
117 var o: i64 = 0
118 o = efn_cat(buf, o, "// GENERATED BY nx_eoe_fn (emitter-of-emitters, functions+call-stack) -- defs + calls synthesized from a DATA spec, compiled by nx_cc. license_tier: ORIGINAL\n" as *u8)
119 o = efn_cat(buf, o, "import \"nx_syscalls.nx\"\n" as *u8)
120
121 let gid: *i64 = sys_mmap(8) as *i64; gid[0] = 0
122 let nti: *i64 = sys_mmap(8) as *i64
123
124 // ---- emit function defs (top-level `def <name> [ body ]`, spec order) ----
125 var ti: i64 = 3
126 var more: i64 = 1
127 while more == 1 {
128 if ti >= argc { more = 0 } else {
129 let tok: *u8 = argv[ti] as *u8
130 if (tok[0] as i64) == 100 { // 'd' def
131 let nm: *u8 = argv[ti+1] as *u8
132 o = efn_cat(buf, o, "func " as *u8); o = efn_cat(buf, o, nm); o = efn_cat(buf, o, "(p: i64) -> i64 {\n var acc: i64 = p\n" as *u8)
133 o = efn_emit_stmts(buf, o, argv, argc, ti + 3, 1, nti, gid) // body after 'def' name '['
134 o = efn_cat(buf, o, " return acc\n}\n" as *u8)
135 ti = nti[0]
136 } else { more = 0 }
137 }
138 }
139 // optional `main` separator token
140 if ti < argc { let mt: *u8 = argv[ti] as *u8; if (mt[0] as i64) == 109 { if (mt[1] as i64) == 97 { ti = ti + 1 } } }
141
142 // ---- emit main() ----
143 o = efn_cat(buf, o, "func main() -> i64 {\n var acc: i64 = " as *u8); o = efn_catn(buf, o, start); o = efn_cat(buf, o, "\n" as *u8)
144 o = efn_emit_stmts(buf, o, argv, argc, ti, 1, nti, gid)
145 o = efn_cat(buf, o, " sys_write(1, \"RESULT=\" as *u8, 7)\n" as *u8)
146 o = efn_cat(buf, o, " var mm: i64 = acc\n" as *u8)
147 o = efn_cat(buf, o, " if mm < 0 { sys_write(1, \"-\" as *u8, 1); mm = 0 - mm }\n" as *u8)
148 o = efn_cat(buf, o, " let t: *u8 = sys_mmap(28)\n" as *u8)
149 o = efn_cat(buf, o, " var k: i64 = 0\n" as *u8)
150 o = efn_cat(buf, o, " if mm == 0 { t[0] = 48 as u8; k = 1 }\n" as *u8)
151 o = efn_cat(buf, o, " while mm > 0 { t[k] = (48 + (mm % 10)) as u8; mm = mm / 10; k = k + 1 }\n" as *u8)
152 o = efn_cat(buf, o, " while k > 0 { k = k - 1; sys_write(1, (((t as i64)+k) as *u8), 1) }\n" as *u8)
153 o = efn_cat(buf, o, " sys_write(1, \"\\n\" as *u8, 1)\n" as *u8)
154 o = efn_cat(buf, o, " return 0\n}\n" as *u8)
155
156 let fd: i64 = sys_openat_wr(path, 420)
157 if fd < 0 { efn_p("EOEFN verdict=RED reason=out-unwritable\n" as *u8); return 1 }
158 sys_write(fd, buf, o)
159 sys_close(fd)
160 efn_p("EOEFN name=" as *u8); efn_p(path); efn_p(" verdict=EMITTED\n" as *u8)
161 return 0
162}