diff --git a/lang/dist/platform/elc b/lang/dist/platform/elc index c972eb6..cb517e2 100755 Binary files a/lang/dist/platform/elc and b/lang/dist/platform/elc differ diff --git a/lang/el-compiler/src/compiler.el b/lang/el-compiler/src/compiler.el index fe35471..ab7fded 100644 --- a/lang/el-compiler/src/compiler.el +++ b/lang/el-compiler/src/compiler.el @@ -23,12 +23,22 @@ import "codegen-js.el" // Uses JIT function-at-a-time streaming: parse one decl → emit C → discard AST. // Peak memory is O(one function's AST) instead of O(whole program AST). fn compile(source: String) -> String { + // Top-level arena scope: activates the string arena before lex() so that + // ALL strdup allocations (token strings, sig strings, codegen fragments) + // are tracked and freed on pop. Without this, lex() and scan_fn_sigs() + // run before any push, leaving _tl_arena_active=0 and leaking every + // token string. Also prevents inner pop(mark=0) calls from deactivating + // the arena between per-function scopes. + let top_mark: Any = el_arena_push() let tokens: [Any] = lex(source) // Fast pre-scan: collect fn signatures + program kind without building // full expression ASTs. O(tokens) time, minimal allocation. let sigs: [Map] = scan_fn_sigs(tokens) // Stream parse-emit: parse one decl at a time, emit C, discard. + // All output written to stdout via println before pop. codegen_streaming(tokens, sigs, source) + el_arena_pop(top_mark) + "" } // compile_js — full pipeline (JS target, module mode): source string -> JS source string