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:
+27
-26
@@ -146,6 +146,7 @@ fn keyword_kind(word: String) -> String {
|
||||
if word == "engine" { return "Engine" }
|
||||
if word == "accessor" { return "Accessor" }
|
||||
if word == "vessel" { return "Vessel" }
|
||||
if word == "extern" { return "Extern" }
|
||||
""
|
||||
}
|
||||
|
||||
@@ -156,7 +157,7 @@ fn keyword_kind(word: String) -> String {
|
||||
// Returns { "text": ..., "pos": i }
|
||||
fn scan_digits(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
let i = start
|
||||
let text = ""
|
||||
let parts: [String] = native_list_empty()
|
||||
let running = true
|
||||
while running {
|
||||
if i >= total {
|
||||
@@ -164,20 +165,20 @@ fn scan_digits(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
} else {
|
||||
let ch: String = native_list_get(chars, i)
|
||||
if lex_is_digit(ch) {
|
||||
let text = text + ch
|
||||
let parts = native_list_append(parts, ch)
|
||||
let i = i + 1
|
||||
} else {
|
||||
let running = false
|
||||
}
|
||||
}
|
||||
}
|
||||
{ "text": text, "pos": i }
|
||||
{ "text": str_join(parts, ""), "pos": i }
|
||||
}
|
||||
|
||||
// scan_ident — advance i while chars[i] is alphanumeric or underscore
|
||||
fn scan_ident(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
let i = start
|
||||
let text = ""
|
||||
let parts: [String] = native_list_empty()
|
||||
let running = true
|
||||
while running {
|
||||
if i >= total {
|
||||
@@ -185,14 +186,14 @@ fn scan_ident(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
} else {
|
||||
let ch: String = native_list_get(chars, i)
|
||||
if is_alnum_or_underscore(ch) {
|
||||
let text = text + ch
|
||||
let parts = native_list_append(parts, ch)
|
||||
let i = i + 1
|
||||
} else {
|
||||
let running = false
|
||||
}
|
||||
}
|
||||
}
|
||||
{ "text": text, "pos": i }
|
||||
{ "text": str_join(parts, ""), "pos": i }
|
||||
}
|
||||
|
||||
// ── Code-bearing string detection + comment strip ────────────────────────────
|
||||
@@ -253,7 +254,7 @@ fn looks_like_code(s: String) -> Bool {
|
||||
fn strip_code_comments(s: String) -> String {
|
||||
let chars: [String] = native_string_chars(s)
|
||||
let total: Int = native_list_len(chars)
|
||||
let out = ""
|
||||
let out_parts: [String] = native_list_empty()
|
||||
let i = 0
|
||||
let in_squote = false
|
||||
let in_dquote = false
|
||||
@@ -269,11 +270,11 @@ fn strip_code_comments(s: String) -> String {
|
||||
if in_js_string {
|
||||
// Backslash escape: consume next char verbatim regardless of which.
|
||||
if ch == "\\" {
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let next_i = i + 1
|
||||
if next_i < total {
|
||||
let nc: String = native_list_get(chars, next_i)
|
||||
let out = out + nc
|
||||
let out_parts = native_list_append(out_parts, nc)
|
||||
let prev = nc
|
||||
let i = next_i + 1
|
||||
} else {
|
||||
@@ -292,7 +293,7 @@ fn strip_code_comments(s: String) -> String {
|
||||
}
|
||||
}
|
||||
}
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
}
|
||||
@@ -308,7 +309,7 @@ fn strip_code_comments(s: String) -> String {
|
||||
if next_ch == "/" {
|
||||
// URL guard: prev char ':' means this is "://", not a comment.
|
||||
if prev == ":" {
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
} else {
|
||||
@@ -360,7 +361,7 @@ fn strip_code_comments(s: String) -> String {
|
||||
}
|
||||
let prev = ""
|
||||
} else {
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
}
|
||||
@@ -369,23 +370,23 @@ fn strip_code_comments(s: String) -> String {
|
||||
// Open a JS string?
|
||||
if ch == "'" {
|
||||
let in_squote = true
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
} else {
|
||||
if ch == "\"" {
|
||||
let in_dquote = true
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
} else {
|
||||
if ch == "`" {
|
||||
let in_btick = true
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
} else {
|
||||
let out = out + ch
|
||||
let out_parts = native_list_append(out_parts, ch)
|
||||
let prev = ch
|
||||
let i = i + 1
|
||||
}
|
||||
@@ -394,14 +395,14 @@ fn strip_code_comments(s: String) -> String {
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
str_join(out_parts, "")
|
||||
}
|
||||
|
||||
// scan_string — scan a quoted string literal, handling \" escapes.
|
||||
// Starts AFTER the opening quote. Returns { "text": content, "pos": i_after_close }
|
||||
fn scan_string(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
let i = start
|
||||
let text = ""
|
||||
let parts: [String] = native_list_empty()
|
||||
let running = true
|
||||
while running {
|
||||
if i >= total {
|
||||
@@ -414,26 +415,26 @@ fn scan_string(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
if next_i < total {
|
||||
let next_ch: String = native_list_get(chars, next_i)
|
||||
if next_ch == "\"" {
|
||||
let text = text + "\""
|
||||
let parts = native_list_append(parts, "\"")
|
||||
let i = next_i + 1
|
||||
} else {
|
||||
if next_ch == "n" {
|
||||
let text = text + "\n"
|
||||
let parts = native_list_append(parts, "\n")
|
||||
let i = next_i + 1
|
||||
} else {
|
||||
if next_ch == "t" {
|
||||
let text = text + "\t"
|
||||
let parts = native_list_append(parts, "\t")
|
||||
let i = next_i + 1
|
||||
} else {
|
||||
if next_ch == "r" {
|
||||
let text = text + "\r"
|
||||
let parts = native_list_append(parts, "\r")
|
||||
let i = next_i + 1
|
||||
} else {
|
||||
if next_ch == "\\" {
|
||||
let text = text + "\\"
|
||||
let parts = native_list_append(parts, "\\")
|
||||
let i = next_i + 1
|
||||
} else {
|
||||
let text = text + next_ch
|
||||
let parts = native_list_append(parts, next_ch)
|
||||
let i = next_i + 1
|
||||
}
|
||||
}
|
||||
@@ -448,13 +449,13 @@ fn scan_string(chars: [String], start: Int, total: Int) -> Map<String, Any> {
|
||||
let i = i + 1
|
||||
let running = false
|
||||
} else {
|
||||
let text = text + ch
|
||||
let parts = native_list_append(parts, ch)
|
||||
let i = i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ "text": text, "pos": i }
|
||||
{ "text": str_join(parts, ""), "pos": i }
|
||||
}
|
||||
|
||||
// ── Main lexer ────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user