code wiki / _hdl_build / nx_eoe_fn.nx
nx_eoe_fn.nx
buildroot/runtime/_hdl_build/nx_eoe_fn.nx
about
nx_eoe_fn.nx -- EMITTER-OF-EMITTERS, GENERALITY RUNG 6: FUNCTIONS + CALL STACK.
Rung 5 (006j, nx_eoe_prog) gave the mini-language compositional control flow
(nested op/if/while) but a single straight-line main(). This rung gives it a
CALL STACK: the spec can DEFINE named functions and CALL them, including functions
that call OTHER functions (a real >=2-deep call graph), so emitted programs
COMPOSE reusable logic instead of inlining everything. Each function is an
acc-transformer `func name(p) -> i64 { var acc = p; <body>; return acc }`; a call
is `acc = name(acc)`. Bodies use the full rung-5 grammar (op/if/while) PLUS call,
recursively. nx_cc compiles the defs + the call ABI (frames/return) -- delegated
to the compiler the team owns.
nx_eoe_fn <basename> <start> [def <name> [ <stmt...> ]]... [main] <stmt...>
stmt grammar (extends 006j): a<n>|m<n>|s<n> | if <pred> [..] | while <pred> [..]
| call <name> (acc = name(acc))
top level: zero or more `def <name> [ <body> ]`, then optional `main`, then the
main statement list. `[` `]` are their own tokens; everything NESTS.
-> emits the func defs (in spec order; a def may call an EARLIER def) + main().
no-false-green (X-AUT-006d): a function calling a function (quad=dbl(dbl(p)))
exercises a 2-deep stack; tampering the INNER function's body changes the final
result THROUGH the nested call -- proving the call ABI really threads values, not
a templated constant. Sovereign, no gcc/.sh. HONEST: one i64 param/return per
fn (acc-transformer convention), one-armed if, int ops; not yet multi-param/typed
/imports. ONE rung -- but the language now has FUNCTIONS. license_tier: ORIGINAL
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 27 | const K_MAGIC_262144: i64 = 262144 |
functions
| 29 | func 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 } |
| 30 | func efn_catn(dst: *u8, off: i64, v: i64) -> i64 |
| 42 | func 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 } |
| 43 | func efn_atoi_from(s: *u8, from: i64) -> i64 |
| 48 | func efn_indent(buf: *u8, off: i64, depth: i64) -> i64 |
| 53 | func efn_cmp(buf: *u8, off: i64, pred: *u8) -> i64 |
| 64 | func efn_emit_stmts(buf: *u8, off: i64, argv: *i64, argc: i64, ti: i64, depth: i64, out_ti: *i64, gid: *i64) -> i64 |
| 104 | func main(argc: i64, argv: *i64) -> i64 |