Archived
Fix O(n²) string construction in codegen-js, lexer, parser, elb
Replace accumulate-by-concatenation loops with native_list_append + str_join. Eliminates quadratic memory growth when processing large source files. This is the v2 compiler state — what produced /tmp/elc-v2.
This commit is contained in:
@@ -23,26 +23,26 @@
|
||||
fn js_escape(s: String) -> String {
|
||||
let chars: [String] = native_string_chars(s)
|
||||
let total: Int = native_list_len(chars)
|
||||
let out = ""
|
||||
let parts: [String] = native_list_empty()
|
||||
let i = 0
|
||||
while i < total {
|
||||
let ch: String = native_list_get(chars, i)
|
||||
if ch == "\"" {
|
||||
let out = out + "\\\""
|
||||
let parts = native_list_append(parts, "\\\"")
|
||||
} else {
|
||||
if ch == "\\" {
|
||||
let out = out + "\\\\"
|
||||
let parts = native_list_append(parts, "\\\\")
|
||||
} else {
|
||||
if ch == "\n" {
|
||||
let out = out + "\\n"
|
||||
let parts = native_list_append(parts, "\\n")
|
||||
} else {
|
||||
if ch == "\r" {
|
||||
let out = out + "\\r"
|
||||
let parts = native_list_append(parts, "\\r")
|
||||
} else {
|
||||
if ch == "\t" {
|
||||
let out = out + "\\t"
|
||||
let parts = native_list_append(parts, "\\t")
|
||||
} else {
|
||||
let out = out + ch
|
||||
let parts = native_list_append(parts, ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ fn js_escape(s: String) -> String {
|
||||
}
|
||||
let i = i + 1
|
||||
}
|
||||
out
|
||||
str_join(parts, "")
|
||||
}
|
||||
|
||||
fn js_str_lit(s: String) -> String {
|
||||
@@ -365,17 +365,15 @@ fn js_cg_expr(expr: Map<String, Any>) -> String {
|
||||
let arity: Int = native_list_len(args)
|
||||
let func_kind: String = func["expr"]
|
||||
|
||||
let args_c = ""
|
||||
let args_parts: [String] = native_list_empty()
|
||||
let i = 0
|
||||
while i < arity {
|
||||
let arg = native_list_get(args, i)
|
||||
let arg_c: String = js_cg_expr(arg)
|
||||
if i > 0 {
|
||||
let args_c = args_c + ", "
|
||||
}
|
||||
let args_c = args_c + arg_c
|
||||
let args_parts = native_list_append(args_parts, arg_c)
|
||||
let i = i + 1
|
||||
}
|
||||
let args_c: String = str_join(args_parts, ", ")
|
||||
|
||||
if func_kind == "Ident" {
|
||||
let fn_name: String = func["name"]
|
||||
@@ -426,38 +424,32 @@ fn js_cg_expr(expr: Map<String, Any>) -> String {
|
||||
let elems = expr["elems"]
|
||||
let n: Int = native_list_len(elems)
|
||||
if n == 0 { return "[]" }
|
||||
let items = ""
|
||||
let items_parts: [String] = native_list_empty()
|
||||
let i = 0
|
||||
while i < n {
|
||||
let elem = native_list_get(elems, i)
|
||||
let elem_c: String = js_cg_expr(elem)
|
||||
if i > 0 {
|
||||
let items = items + ", "
|
||||
}
|
||||
let items = items + elem_c
|
||||
let items_parts = native_list_append(items_parts, elem_c)
|
||||
let i = i + 1
|
||||
}
|
||||
return "[" + items + "]"
|
||||
return "[" + str_join(items_parts, ", ") + "]"
|
||||
}
|
||||
|
||||
if kind == "Map" {
|
||||
let pairs = expr["pairs"]
|
||||
let n: Int = native_list_len(pairs)
|
||||
if n == 0 { return "{}" }
|
||||
let items = ""
|
||||
let items_parts: [String] = native_list_empty()
|
||||
let i = 0
|
||||
while i < n {
|
||||
let pair = native_list_get(pairs, i)
|
||||
let key: String = pair["key"]
|
||||
let val = pair["value"]
|
||||
let val_c: String = js_cg_expr(val)
|
||||
if i > 0 {
|
||||
let items = items + ", "
|
||||
}
|
||||
let items = items + js_str_lit(key) + ": " + val_c
|
||||
let items_parts = native_list_append(items_parts, js_str_lit(key) + ": " + val_c)
|
||||
let i = i + 1
|
||||
}
|
||||
return "{" + items + "}"
|
||||
return "{" + str_join(items_parts, ", ") + "}"
|
||||
}
|
||||
|
||||
if kind == "Try" {
|
||||
@@ -505,7 +497,8 @@ fn js_cg_match(expr: Map<String, Any>) -> String {
|
||||
let subj_c: String = js_cg_expr(subject)
|
||||
let id: String = js_next_match_id()
|
||||
let subj_var: String = "_match_subj_" + id
|
||||
let out: String = "((" + subj_var + ") => { "
|
||||
let parts: [String] = native_list_empty()
|
||||
let parts = native_list_append(parts, "((" + subj_var + ") => { ")
|
||||
let n: Int = native_list_len(arms)
|
||||
let i = 0
|
||||
while i < n {
|
||||
@@ -515,28 +508,28 @@ fn js_cg_match(expr: Map<String, Any>) -> String {
|
||||
let pkind: String = pat["pattern"]
|
||||
let body_c: String = js_cg_expr(body)
|
||||
if str_eq(pkind, "Wildcard") {
|
||||
let out = out + "return (" + body_c + "); "
|
||||
let parts = native_list_append(parts, "return (" + body_c + "); ")
|
||||
} else {
|
||||
if str_eq(pkind, "Binding") {
|
||||
let bname: String = pat["name"]
|
||||
let out = out + "{ const " + bname + " = " + subj_var + "; return (" + body_c + "); } "
|
||||
let parts = native_list_append(parts, "{ const " + bname + " = " + subj_var + "; return (" + body_c + "); } ")
|
||||
} else {
|
||||
if str_eq(pkind, "LitInt") {
|
||||
let v: String = pat["value"]
|
||||
let out = out + "if (" + subj_var + " === " + v + ") return (" + body_c + "); "
|
||||
let parts = native_list_append(parts, "if (" + subj_var + " === " + v + ") return (" + body_c + "); ")
|
||||
} else {
|
||||
if str_eq(pkind, "LitStr") {
|
||||
let v: String = pat["value"]
|
||||
let out = out + "if (str_eq(" + subj_var + ", " + js_str_lit(v) + ")) return (" + body_c + "); "
|
||||
let parts = native_list_append(parts, "if (str_eq(" + subj_var + ", " + js_str_lit(v) + ")) return (" + body_c + "); ")
|
||||
} else {
|
||||
if str_eq(pkind, "LitBool") {
|
||||
let v: String = pat["value"]
|
||||
let bv = "false"
|
||||
if str_eq(v, "true") { let bv = "true" }
|
||||
let out = out + "if (" + subj_var + " === " + bv + ") return (" + body_c + "); "
|
||||
let parts = native_list_append(parts, "if (" + subj_var + " === " + bv + ") return (" + body_c + "); ")
|
||||
} else {
|
||||
// unknown pattern → wildcard
|
||||
let out = out + "return (" + body_c + "); "
|
||||
let parts = native_list_append(parts, "return (" + body_c + "); ")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -544,8 +537,8 @@ fn js_cg_match(expr: Map<String, Any>) -> String {
|
||||
}
|
||||
let i = i + 1
|
||||
}
|
||||
let out = out + "return null; })(" + subj_c + ")"
|
||||
out
|
||||
let parts = native_list_append(parts, "return null; })(" + subj_c + ")")
|
||||
str_join(parts, "")
|
||||
}
|
||||
|
||||
// ── Variable scope tracking ───────────────────────────────────────────────────
|
||||
@@ -696,14 +689,7 @@ fn js_strip_outer_parens(s: String) -> String {
|
||||
let i = i + 1
|
||||
}
|
||||
if balanced {
|
||||
let inner = ""
|
||||
let j = 1
|
||||
while j < n - 1 {
|
||||
let ch: String = native_list_get(chars, j)
|
||||
let inner = inner + ch
|
||||
let j = j + 1
|
||||
}
|
||||
return inner
|
||||
return str_slice(s, 1, n - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,18 +745,15 @@ fn js_cg_stmts(stmts: [Map<String, Any>], indent: String, declared: [String]) ->
|
||||
fn js_params_str(params: [Map<String, Any>]) -> String {
|
||||
let n: Int = native_list_len(params)
|
||||
if n == 0 { return "" }
|
||||
let out = ""
|
||||
let parts: [String] = native_list_empty()
|
||||
let i = 0
|
||||
while i < n {
|
||||
let param = native_list_get(params, i)
|
||||
let name: String = param["name"]
|
||||
if i > 0 {
|
||||
let out = out + ", "
|
||||
}
|
||||
let out = out + name
|
||||
let parts = native_list_append(parts, name)
|
||||
let i = i + 1
|
||||
}
|
||||
out
|
||||
str_join(parts, ", ")
|
||||
}
|
||||
|
||||
// Same implicit-return transform as the C backend.
|
||||
|
||||
Reference in New Issue
Block a user