perf: 81% RSS reduction — el_release, arena scoping, streaming codegen, libcurl stub

Chain of optimizations from swarm rounds 4-7:
- Flat stride-2 token list: eliminate per-token Map allocation (~112B each × N tokens)
- Systematic el_release() in parser.el: eagerly free intermediate parse result maps
- Per-function and per-statement arena scoping in codegen_streaming()
- Streaming codegen pipeline: parse one fn at a time, emit C, discard AST
- HAVE_CURL guard: elc CLI binary drops libcurl, eliminating SSL/TLS init overhead
- HTML codegen parts-list: O(n) instead of O(n²) string growth for nested templates
- Batch c_escape: str_slice clean runs instead of char-at per byte

Result: 33.4MB → 6.5MB RSS on web/src/main.el (-81%). Self-host: PASS.
This commit is contained in:
Will Anderson
2026-05-05 20:39:38 -05:00
parent ee86736eab
commit 3726f69435
5 changed files with 859 additions and 42 deletions
+389
View File
@@ -358,6 +358,8 @@ fn parse_html_attrs(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, p + 1)
let val_node = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let p = expect(tokens, p, "RBrace")
let attrs = native_list_append(attrs, { "name": attr_name, "kind": "dynamic", "value": val_node })
} else {
@@ -426,6 +428,8 @@ fn parse_html_children(tokens: [Any], pos: Int, parent_tag: String) -> Map<Strin
let r = parse_html_element(tokens, p)
let child = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let children = native_list_append(children, child)
}
}
@@ -445,6 +449,8 @@ fn parse_html_children(tokens: [Any], pos: Int, parent_tag: String) -> Map<Strin
state_set("__no_block_expr", prev_no_block)
let list_expr = r_list["node"]
let p = r_list["pos"]
// r_list result map fully consumed release to free peak heap.
el_release(r_list)
// expect "as"
let p = expect(tokens, p, "As")
// item variable name
@@ -456,6 +462,8 @@ fn parse_html_children(tokens: [Any], pos: Int, parent_tag: String) -> Map<Strin
let r_body = parse_html_each_body(tokens, p)
let body_children = r_body["children"]
let p = r_body["pos"]
// r_body result map fully consumed release to free peak heap.
el_release(r_body)
let each_node: Map<String, Any> = { "html": "Each", "list": list_expr, "item": item_name, "body": body_children }
let children = native_list_append(children, each_node)
} else {
@@ -476,6 +484,8 @@ fn parse_html_children(tokens: [Any], pos: Int, parent_tag: String) -> Map<Strin
let r = parse_expr(tokens, p + 1)
let interp_val = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let p = expect(tokens, p, "RBrace")
// Check if the expr is a call to raw()
let is_raw_call = false
@@ -504,6 +514,8 @@ fn parse_html_children(tokens: [Any], pos: Int, parent_tag: String) -> Map<Strin
let r_text = parse_html_text_tokens(tokens, p)
let text_str: String = r_text["text"]
let p = r_text["pos"]
// r_text result map fully consumed release to free peak heap.
el_release(r_text)
let text_trimmed: String = str_trim(text_str)
if !str_eq(text_trimmed, "") {
let children = native_list_append(children, { "html": "Text", "text": text_trimmed })
@@ -535,6 +547,8 @@ fn parse_html_element(tokens: [Any], pos: Int) -> Map<String, Any> {
let r_attrs = parse_html_attrs(tokens, p)
let attrs = r_attrs["attrs"]
let p = r_attrs["pos"]
// r_attrs result map fully consumed release to free peak heap.
el_release(r_attrs)
// check for self-closing /> or void element
let k = tok_kind(tokens, p)
let self_closing = false
@@ -555,6 +569,8 @@ fn parse_html_element(tokens: [Any], pos: Int) -> Map<String, Any> {
let r_children = parse_html_children(tokens, p, tag_name)
let children = r_children["children"]
let p = r_children["pos"]
// r_children result map fully consumed release to free peak heap.
el_release(r_children)
make_result({ "html": "Element", "tag": tag_name, "attrs": attrs, "children": children, "self_closing": false }, p)
}
@@ -592,6 +608,8 @@ fn parse_html_template(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_html_element(tokens, p)
let root = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let root_with_doctype = root
if doctype {
let root_with_doctype = { "html": root["html"], "tag": root["tag"], "attrs": root["attrs"], "children": root["children"], "self_closing": root["self_closing"], "doctype": true }
@@ -649,6 +667,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, pos + 1)
let node = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let p = expect(tokens, p, "RParen")
return make_result(node, p)
}
@@ -669,6 +689,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, p)
let elem = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let elems = native_list_append(elems, elem)
let k3 = tok_kind(tokens, p)
if k3 == "Comma" {
@@ -714,6 +736,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, new_p)
let val_node = r["node"]
let new_p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let pair = { "key": key, "value": val_node }
let pairs = native_list_append(pairs, pair)
let k3 = tok_kind(tokens, new_p)
@@ -760,6 +784,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_params(tokens, p)
let params = r["params"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let ret_type = ""
let k2 = tok_kind(tokens, p)
if k2 == "Arrow" {
@@ -773,6 +799,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_block(tokens, p)
let body = r2["stmts"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
return make_result({ "expr": "Lambda", "params": params, "body": body, "ret_type": ret_type }, p)
}
@@ -781,6 +809,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_primary(tokens, pos + 1)
let inner = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
return make_result({ "expr": "Not", "inner": inner }, p)
}
@@ -789,6 +819,8 @@ fn parse_primary(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_primary(tokens, pos + 1)
let inner = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
return make_result({ "expr": "Neg", "inner": inner }, p)
}
@@ -832,9 +864,13 @@ fn parse_if(tokens: [Any], pos: Int) -> Map<String, Any> {
state_set("__no_block_expr", prev_no_block)
let cond = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let r2 = parse_block(tokens, p)
let then_stmts = r2["stmts"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
let has_else = false
let else_stmts: [Map<String, Any>] = native_list_empty()
let k2 = tok_kind(tokens, p)
@@ -846,12 +882,16 @@ fn parse_if(tokens: [Any], pos: Int) -> Map<String, Any> {
let r3 = parse_if(tokens, p)
let nested = r3["node"]
let p = r3["pos"]
// r3 result map fully consumed release to free peak heap.
el_release(r3)
let else_stmts = native_list_append(else_stmts, { "stmt": "Expr", "value": nested })
let has_else = true
} else {
let r3 = parse_block(tokens, p)
let else_stmts = r3["stmts"]
let p = r3["pos"]
// r3 result map fully consumed release to free peak heap.
el_release(r3)
let has_else = true
}
}
@@ -866,6 +906,8 @@ fn parse_match(tokens: [Any], pos: Int) -> Map<String, Any> {
state_set("__no_block_expr", prev_no_block)
let subject = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let p = expect(tokens, p, "LBrace")
let arms: [Map<String, Any>] = native_list_empty()
let running = true
@@ -881,10 +923,14 @@ fn parse_match(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_pattern(tokens, p)
let pattern = r2["node"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
let p = expect(tokens, p, "FatArrow")
let r3 = parse_expr(tokens, p)
let body = r3["node"]
let p = r3["pos"]
// r3 result map fully consumed release to free peak heap.
el_release(r3)
let arm = { "pattern": pattern, "body": body }
let arms = native_list_append(arms, arm)
let k2 = tok_kind(tokens, p)
@@ -938,9 +984,13 @@ fn parse_for_expr(tokens: [Any], pos: Int) -> Map<String, Any> {
state_set("__no_block_expr", prev_no_block)
let list_expr = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let r2 = parse_block(tokens, p)
let body = r2["stmts"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
make_result({ "expr": "For", "item": item_name, "list": list_expr, "body": body }, p)
}
@@ -959,6 +1009,8 @@ fn parse_block(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_stmt(tokens, p)
let stmt = r["node"]
let new_p: Int = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let stmts = native_list_append(stmts, stmt)
// Non-progress guard: a malformed input (e.g. `||` that
// dragged the parser into Map-literal mode partway through
@@ -1005,6 +1057,8 @@ fn parse_postfix(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_primary(tokens, pos)
let node = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
// Postfix duration literal: `<Int>.<unit>` where <unit> is one of
// nanos | millis | seconds | minutes | hours | days (each with an
@@ -1046,6 +1100,8 @@ fn parse_postfix(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_expr(tokens, p)
let arg = r2["node"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
let args = native_list_append(args, arg)
let k3 = tok_kind(tokens, p)
if k3 == "Comma" {
@@ -1066,6 +1122,8 @@ fn parse_postfix(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_expr(tokens, p + 1)
let idx = r2["node"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
let p = expect(tokens, p, "RBracket")
let node = { "expr": "Index", "object": node, "index": idx }
} else {
@@ -1122,6 +1180,8 @@ fn parse_binop(tokens: [Any], pos: Int, min_prec: Int) -> Map<String, Any> {
let r = parse_postfix(tokens, pos)
let left = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let running = true
while running {
let k = tok_kind(tokens, p)
@@ -1132,6 +1192,8 @@ fn parse_binop(tokens: [Any], pos: Int, min_prec: Int) -> Map<String, Any> {
let r2 = parse_binop(tokens, p + 1, prec + 1)
let right = r2["node"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
let left = { "expr": "BinOp", "op": op, "left": left, "right": right }
} else {
let running = false
@@ -1174,6 +1236,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, p)
let val = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
return make_result({ "stmt": "Let", "name": name, "value": val, "type": ltype }, p)
}
@@ -1190,6 +1254,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, p)
let val = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
return make_result({ "stmt": "Return", "value": val }, p)
}
@@ -1204,6 +1270,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_params(tokens, p)
let params = r["params"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let ret_type = ""
let k3: String = tok_kind(tokens, p)
if str_eq(k3, "Arrow") {
@@ -1224,6 +1292,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_params(tokens, p)
let params = r["params"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
// return type annotation: -> Type. Capture the leading identifier
// so codegen can distinguish Void-returning functions from value-
// returning ones. Anything not "Void" is treated as a value type.
@@ -1240,6 +1310,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_block(tokens, p)
let body = r2["stmts"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
return make_result({ "stmt": "FnDef", "name": name, "params": params, "body": body, "ret_type": ret_type }, p)
}
@@ -1363,9 +1435,13 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
state_set("__no_block_expr", prev_no_block)
let cond = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let r2 = parse_block(tokens, p)
let body = r2["stmts"]
let p = r2["pos"]
// r2 result map fully consumed release to free peak heap.
el_release(r2)
return make_result({ "stmt": "While", "cond": cond, "body": body }, p)
}
@@ -1391,6 +1467,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
state_set("__no_block_expr", prev_no_block)
let start_expr = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
// Check for range operator: .. (exclusive) or ..= (inclusive)
let range_k = tok_kind(tokens, p)
if range_k == "DotDot" {
@@ -1399,9 +1477,11 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_expr(tokens, p)
let end_expr = r2["node"]
let p = r2["pos"]
el_release(r2)
let r3 = parse_block(tokens, p)
let body = r3["stmts"]
let p = r3["pos"]
el_release(r3)
return make_result({ "stmt": "ForRange", "var": item_name, "start": start_expr, "end": end_expr, "inclusive": false, "body": body }, p)
}
if range_k == "DotDotEq" {
@@ -1410,9 +1490,11 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_expr(tokens, p)
let end_expr = r2["node"]
let p = r2["pos"]
el_release(r2)
let r3 = parse_block(tokens, p)
let body = r3["stmts"]
let p = r3["pos"]
el_release(r3)
return make_result({ "stmt": "ForRange", "var": item_name, "start": start_expr, "end": end_expr, "inclusive": true, "body": body }, p)
}
// No range operator: regular for-in (list iteration)
@@ -1420,6 +1502,7 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r2 = parse_block(tokens, p)
let body = r2["stmts"]
let p = r2["pos"]
el_release(r2)
return make_result({ "stmt": "For", "item": item_name, "list": list_expr, "body": body }, p)
}
@@ -1431,6 +1514,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r_try = parse_block(tokens, p)
let try_body = r_try["stmts"]
let p = r_try["pos"]
// r_try result map fully consumed release to free peak heap.
el_release(r_try)
let catch_name = "err"
let k2 = tok_kind(tokens, p)
if str_eq(k2, "Catch") {
@@ -1452,6 +1537,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r_catch = parse_block(tokens, p)
let catch_body = r_catch["stmts"]
let p = r_catch["pos"]
// r_catch result map fully consumed release to free peak heap.
el_release(r_catch)
return make_result({ "stmt": "TryCatch", "try_body": try_body, "catch_name": catch_name, "catch_body": catch_body }, p)
}
return make_result({ "stmt": "TryCatch", "try_body": try_body, "catch_name": catch_name, "catch_body": native_list_empty() }, p)
@@ -1475,6 +1562,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
"ret_type": inner["ret_type"],
"decorator": dec_name
}
// r result map fully consumed release to free peak heap.
el_release(r)
return make_result(with_dec, p2)
}
return r
@@ -1609,6 +1698,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, p)
let val = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
return make_result({ "stmt": "Assign", "name": name, "value": val }, p)
}
}
@@ -1617,6 +1708,8 @@ fn parse_stmt(tokens: [Any], pos: Int) -> Map<String, Any> {
let r = parse_expr(tokens, pos)
let val = r["node"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
make_result({ "stmt": "Expr", "value": val }, p)
}
@@ -1639,6 +1732,8 @@ fn parse(tokens: [Any]) -> [Map<String, Any>] {
let r = parse_stmt(tokens, pos)
let stmt = r["node"]
let new_pos: Int = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let stmts = native_list_append(stmts, stmt)
// Guard against infinite loops - if pos didn't advance, force it
if new_pos <= pos {
@@ -1651,3 +1746,297 @@ fn parse(tokens: [Any]) -> [Map<String, Any>] {
}
stmts
}
// -- Streaming parse helpers ---------------------------------------------------
// parse_one parse exactly one top-level statement at position `pos`.
// Returns { "node": stmt_map, "pos": new_pos }.
// Enables the streaming compiler pipeline (parse one emit C discard).
fn parse_one(tokens: [Any], pos: Int) -> Map<String, Any> {
parse_stmt(tokens, pos)
}
// skip_to_rbrace advance past a balanced { ... } block.
// On entry, pos must point at the LBrace token.
// Returns the position of the token AFTER the matching RBrace.
fn skip_to_rbrace(tokens: [Any], pos: Int) -> Int {
let total: Int = native_list_len(tokens) / 2
let p: Int = pos + 1
let depth: Int = 1
let going: Bool = true
while going {
if p >= total {
let going = false
} else {
let kk: String = tok_kind(tokens, p)
if str_eq(kk, "Eof") {
let going = false
} else {
if str_eq(kk, "LBrace") {
let depth = depth + 1
let p = p + 1
} else {
if str_eq(kk, "RBrace") {
let depth = depth - 1
let p = p + 1
if depth <= 0 {
let going = false
}
} else {
let p = p + 1
}
}
}
}
}
p
}
// is_stmt_start_kind true if `k` is a token kind that can start a new
// top-level statement (used to find safe stopping points during token skips).
fn is_stmt_start_kind(k: String) -> Bool {
if str_eq(k, "Fn") { return true }
if str_eq(k, "Let") { return true }
if str_eq(k, "Extern") { return true }
if str_eq(k, "Cgi") { return true }
if str_eq(k, "Service") { return true }
if str_eq(k, "Type") { return true }
if str_eq(k, "Enum") { return true }
if str_eq(k, "Import") { return true }
if str_eq(k, "From") { return true }
if str_eq(k, "Eof") { return true }
false
}
// skip_expr_to_stmt_boundary skip tokens from `pos` until we reach a
// token that could start a new top-level statement, staying depth-aware
// so that braces inside expressions don't fool us.
fn skip_expr_to_stmt_boundary(tokens: [Any], pos: Int) -> Int {
let total: Int = native_list_len(tokens) / 2
let p: Int = pos
let depth: Int = 0
let going: Bool = true
while going {
if p >= total {
let going = false
} else {
let kk: String = tok_kind(tokens, p)
if str_eq(kk, "Eof") {
let going = false
} else {
if str_eq(kk, "LBrace") {
let depth = depth + 1
let p = p + 1
} else {
if str_eq(kk, "RBrace") {
if depth <= 0 {
let going = false
} else {
let depth = depth - 1
let p = p + 1
}
} else {
if depth == 0 {
if is_stmt_start_kind(kk) {
let going = false
} else {
let p = p + 1
}
} else {
let p = p + 1
}
}
}
}
}
}
p
}
// scan_params_c scan a parameter list `(name: Type, ...)` starting at
// position `pos` (which should point at LParen) and return the C parameter
// declaration string along with the new position.
// Returns { "c": String, "pos": Int }.
// This avoids allocating param-map objects during the pre-scan phase.
fn scan_params_c(tokens: [Any], pos: Int) -> Map<String, Any> {
let p: Int = expect(tokens, pos, "LParen")
let parts: [String] = native_list_empty()
let going: Bool = true
while going {
let kk: String = tok_kind(tokens, p)
if str_eq(kk, "RParen") {
let going = false
} else {
if str_eq(kk, "Eof") {
let going = false
} else {
let pname: String = tok_value(tokens, p)
let p = p + 1
let p = expect(tokens, p, "Colon")
let p = skip_type(tokens, p)
let parts = native_list_append(parts, "el_val_t " + pname)
let k2: String = tok_kind(tokens, p)
if str_eq(k2, "Comma") {
let p = p + 1
}
}
}
}
let p = expect(tokens, p, "RParen")
let c_str: String = str_join(parts, ", ")
// parts list fully consumed release to free peak heap.
el_release(parts)
if str_eq(c_str, "") { let c_str = "void" }
{ "c": c_str, "pos": p }
}
// scan_fn_sigs lightweight token-level pre-scan.
//
// Returns a list of descriptor maps (one per top-level item) without building
// full expression ASTs or param-map objects. Descriptors have these shapes:
//
// fn/extern_fn: { "kind": "fn"|"extern_fn", "name": String,
// "params_c": String, <- C param decl string, e.g. "el_val_t a, el_val_t b"
// "is_main": Bool }
// toplevel_let: { "kind": "toplevel_let", "name": String, "ltype": String }
// cgi_block: { "kind": "cgi_block", "name": String }
// service_block: { "kind": "service_block", "name": String }
//
// Import/TypeDef/EnumDef nodes are skipped (codegen treats them as no-ops).
//
// The scan allocates only small string values per entry, keeping peak RSS low.
fn scan_fn_sigs(tokens: [Any]) -> [Map<String, Any>] {
let total: Int = native_list_len(tokens) / 2
let sigs: [Map<String, Any>] = native_list_empty()
let pos: Int = 0
let going: Bool = true
while going {
if pos >= total {
let going = false
} else {
let k: String = tok_kind(tokens, pos)
if str_eq(k, "Eof") {
let going = false
} else {
// --- fn definition ---
if str_eq(k, "Fn") {
let p: Int = pos + 1
let name: String = tok_value(tokens, p)
let p = p + 1
let r = scan_params_c(tokens, p)
let params_c: String = r["c"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
// skip return type
let k2: String = tok_kind(tokens, p)
if str_eq(k2, "Arrow") {
let p = p + 1
let p = skip_type(tokens, p)
}
// skip body
let k3: String = tok_kind(tokens, p)
if str_eq(k3, "LBrace") {
let p = skip_to_rbrace(tokens, p)
}
let is_main: Bool = str_eq(name, "main")
let sigs = native_list_append(sigs, {
"kind": "fn",
"name": name,
"params_c": params_c,
"is_main": is_main
})
let pos = p
} else {
// --- extern fn ---
if str_eq(k, "Extern") {
let p: Int = pos + 1
let k2: String = tok_kind(tokens, p)
if str_eq(k2, "Fn") {
let p = p + 1
let name: String = tok_value(tokens, p)
let p = p + 1
let r = scan_params_c(tokens, p)
let params_c: String = r["c"]
let p = r["pos"]
// r result map fully consumed release to free peak heap.
el_release(r)
let k3: String = tok_kind(tokens, p)
if str_eq(k3, "Arrow") {
let p = p + 1
let p = skip_type(tokens, p)
}
let sigs = native_list_append(sigs, {
"kind": "extern_fn",
"name": name,
"params_c": params_c,
"is_main": false
})
let pos = p
} else {
let pos = pos + 1
}
} else {
// --- top-level let ---
if str_eq(k, "Let") {
let p: Int = pos + 1
let name: String = tok_value(tokens, p)
let p = p + 1
let ltype: String = ""
let k2: String = tok_kind(tokens, p)
if str_eq(k2, "Colon") {
let p = p + 1
let kt: String = tok_kind(tokens, p)
if str_eq(kt, "Ident") { let ltype = tok_value(tokens, p) }
let p = skip_type(tokens, p)
}
let p = expect(tokens, p, "Eq")
let p = skip_expr_to_stmt_boundary(tokens, p)
let sigs = native_list_append(sigs, {
"kind": "toplevel_let",
"name": name,
"ltype": ltype
})
let pos = p
} else {
// --- cgi block ---
if str_eq(k, "Cgi") {
let p: Int = pos + 1
let name: String = tok_value(tokens, p)
let p = p + 1
let k2: String = tok_kind(tokens, p)
if str_eq(k2, "LBrace") {
let p = skip_to_rbrace(tokens, p)
}
let sigs = native_list_append(sigs, {
"kind": "cgi_block",
"name": name
})
let pos = p
} else {
// --- service block ---
if str_eq(k, "Service") {
let p: Int = pos + 1
let name: String = tok_value(tokens, p)
let p = p + 1
let k2: String = tok_kind(tokens, p)
if str_eq(k2, "LBrace") {
let p = skip_to_rbrace(tokens, p)
}
let sigs = native_list_append(sigs, {
"kind": "service_block",
"name": name
})
let pos = p
} else {
// Import, Type, Enum, From, or any other token.
// Skip ahead to the next statement boundary.
let p: Int = pos + 1
let p = skip_expr_to_stmt_boundary(tokens, p)
let pos = p
}}}}}
}
}
}
sigs
}