fix: C backend String functions, record type aliases, docs cleanup
- Add String.fromChar, chars, substring, toUpper, toLower, replace, startsWith, endsWith, join to C backend - Fix record type alias unification by adding expand_type_alias and unify_with_env functions - Update docs to reflect current implementation status - Clean up outdated roadmap items and fix inconsistencies - Add comprehensive language comparison document Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1247,6 +1247,125 @@ impl CBackend {
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxString lux_string_from_char(char c) {");
|
||||
self.writeln(" LuxString result = (LuxString)lux_rc_alloc(2, LUX_TAG_STRING);");
|
||||
self.writeln(" if (!result) return \"\";");
|
||||
self.writeln(" result[0] = c;");
|
||||
self.writeln(" result[1] = '\\0';");
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxList* lux_string_chars(LuxString s) {");
|
||||
self.writeln(" size_t len = s ? strlen(s) : 0;");
|
||||
self.writeln(" LuxList* list = lux_list_new(len);");
|
||||
self.writeln(" for (size_t i = 0; i < len; i++) {");
|
||||
self.writeln(" LuxString ch = lux_string_from_char(s[i]);");
|
||||
self.writeln(" lux_list_push(list, (void*)ch);");
|
||||
self.writeln(" }");
|
||||
self.writeln(" return list;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxString lux_string_substring(LuxString s, LuxInt start, LuxInt len) {");
|
||||
self.writeln(" if (!s) return \"\";");
|
||||
self.writeln(" size_t slen = strlen(s);");
|
||||
self.writeln(" if (start < 0) start = 0;");
|
||||
self.writeln(" if ((size_t)start >= slen) return \"\";");
|
||||
self.writeln(" if (len < 0) len = 0;");
|
||||
self.writeln(" if ((size_t)(start + len) > slen) len = slen - start;");
|
||||
self.writeln(" LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
|
||||
self.writeln(" if (!result) return \"\";");
|
||||
self.writeln(" strncpy(result, s + start, len);");
|
||||
self.writeln(" result[len] = '\\0';");
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxString lux_string_to_upper(LuxString s) {");
|
||||
self.writeln(" if (!s) return \"\";");
|
||||
self.writeln(" size_t len = strlen(s);");
|
||||
self.writeln(" LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
|
||||
self.writeln(" if (!result) return \"\";");
|
||||
self.writeln(" for (size_t i = 0; i < len; i++) {");
|
||||
self.writeln(" result[i] = (s[i] >= 'a' && s[i] <= 'z') ? s[i] - 32 : s[i];");
|
||||
self.writeln(" }");
|
||||
self.writeln(" result[len] = '\\0';");
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxString lux_string_to_lower(LuxString s) {");
|
||||
self.writeln(" if (!s) return \"\";");
|
||||
self.writeln(" size_t len = strlen(s);");
|
||||
self.writeln(" LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);");
|
||||
self.writeln(" if (!result) return \"\";");
|
||||
self.writeln(" for (size_t i = 0; i < len; i++) {");
|
||||
self.writeln(" result[i] = (s[i] >= 'A' && s[i] <= 'Z') ? s[i] + 32 : s[i];");
|
||||
self.writeln(" }");
|
||||
self.writeln(" result[len] = '\\0';");
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxString lux_string_replace(LuxString s, LuxString from, LuxString to) {");
|
||||
self.writeln(" if (!s || !from || !*from) return s ? lux_string_dup(s) : \"\";");
|
||||
self.writeln(" if (!to) to = \"\";");
|
||||
self.writeln(" size_t from_len = strlen(from);");
|
||||
self.writeln(" size_t to_len = strlen(to);");
|
||||
self.writeln(" size_t count = 0;");
|
||||
self.writeln(" const char* p = s;");
|
||||
self.writeln(" while ((p = strstr(p, from)) != NULL) { count++; p += from_len; }");
|
||||
self.writeln(" size_t new_len = strlen(s) + count * (to_len - from_len);");
|
||||
self.writeln(" LuxString result = (LuxString)lux_rc_alloc(new_len + 1, LUX_TAG_STRING);");
|
||||
self.writeln(" if (!result) return \"\";");
|
||||
self.writeln(" char* out = result;");
|
||||
self.writeln(" p = s;");
|
||||
self.writeln(" const char* found;");
|
||||
self.writeln(" while ((found = strstr(p, from)) != NULL) {");
|
||||
self.writeln(" size_t prefix_len = found - p;");
|
||||
self.writeln(" memcpy(out, p, prefix_len);");
|
||||
self.writeln(" out += prefix_len;");
|
||||
self.writeln(" memcpy(out, to, to_len);");
|
||||
self.writeln(" out += to_len;");
|
||||
self.writeln(" p = found + from_len;");
|
||||
self.writeln(" }");
|
||||
self.writeln(" strcpy(out, p);");
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxBool lux_string_starts_with(LuxString s, LuxString prefix) {");
|
||||
self.writeln(" if (!s || !prefix) return 0;");
|
||||
self.writeln(" size_t prefix_len = strlen(prefix);");
|
||||
self.writeln(" if (strlen(s) < prefix_len) return 0;");
|
||||
self.writeln(" return strncmp(s, prefix, prefix_len) == 0;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxBool lux_string_ends_with(LuxString s, LuxString suffix) {");
|
||||
self.writeln(" if (!s || !suffix) return 0;");
|
||||
self.writeln(" size_t s_len = strlen(s);");
|
||||
self.writeln(" size_t suffix_len = strlen(suffix);");
|
||||
self.writeln(" if (s_len < suffix_len) return 0;");
|
||||
self.writeln(" return strcmp(s + s_len - suffix_len, suffix) == 0;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxString lux_string_join(LuxList* list, LuxString sep) {");
|
||||
self.writeln(" if (!list || list->length == 0) return \"\";");
|
||||
self.writeln(" if (!sep) sep = \"\";");
|
||||
self.writeln(" size_t sep_len = strlen(sep);");
|
||||
self.writeln(" size_t total_len = 0;");
|
||||
self.writeln(" for (int64_t i = 0; i < list->length; i++) {");
|
||||
self.writeln(" LuxString elem = (LuxString)list->elements[i];");
|
||||
self.writeln(" if (elem) total_len += strlen(elem);");
|
||||
self.writeln(" if (i > 0) total_len += sep_len;");
|
||||
self.writeln(" }");
|
||||
self.writeln(" LuxString result = (LuxString)lux_rc_alloc(total_len + 1, LUX_TAG_STRING);");
|
||||
self.writeln(" if (!result) return \"\";");
|
||||
self.writeln(" char* out = result;");
|
||||
self.writeln(" for (int64_t i = 0; i < list->length; i++) {");
|
||||
self.writeln(" if (i > 0) { strcpy(out, sep); out += sep_len; }");
|
||||
self.writeln(" LuxString elem = (LuxString)list->elements[i];");
|
||||
self.writeln(" if (elem) { strcpy(out, elem); out += strlen(elem); }");
|
||||
self.writeln(" }");
|
||||
self.writeln(" *out = '\\0';");
|
||||
self.writeln(" return result;");
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("// Default evidence with built-in handlers");
|
||||
self.writeln("static LuxEvidence default_evidence = {");
|
||||
self.writeln(" .console = &default_console_handler,");
|
||||
@@ -2863,6 +2982,72 @@ impl CBackend {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
return Ok(format!("lux_string_parseFloat({})", s));
|
||||
}
|
||||
"fromChar" => {
|
||||
let c = self.emit_expr(&args[0])?;
|
||||
// Create temp variable and track for cleanup (returns RC-managed string)
|
||||
let temp = format!("_fromchar_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxString {} = lux_string_from_char({});", temp, c));
|
||||
self.register_rc_var(&temp, "LuxString");
|
||||
return Ok(temp);
|
||||
}
|
||||
"chars" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
// Create temp variable and track for cleanup (returns RC-managed list)
|
||||
let temp = format!("_chars_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxList* {} = lux_string_chars({});", temp, s));
|
||||
self.register_rc_var(&temp, "LuxList*");
|
||||
return Ok(temp);
|
||||
}
|
||||
"substring" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
let start = self.emit_expr(&args[1])?;
|
||||
let len = self.emit_expr(&args[2])?;
|
||||
let temp = format!("_substr_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxString {} = lux_string_substring({}, {}, {});", temp, s, start, len));
|
||||
self.register_rc_var(&temp, "LuxString");
|
||||
return Ok(temp);
|
||||
}
|
||||
"toUpper" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
let temp = format!("_upper_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxString {} = lux_string_to_upper({});", temp, s));
|
||||
self.register_rc_var(&temp, "LuxString");
|
||||
return Ok(temp);
|
||||
}
|
||||
"toLower" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
let temp = format!("_lower_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxString {} = lux_string_to_lower({});", temp, s));
|
||||
self.register_rc_var(&temp, "LuxString");
|
||||
return Ok(temp);
|
||||
}
|
||||
"replace" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
let from = self.emit_expr(&args[1])?;
|
||||
let to = self.emit_expr(&args[2])?;
|
||||
let temp = format!("_replace_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxString {} = lux_string_replace({}, {}, {});", temp, s, from, to));
|
||||
self.register_rc_var(&temp, "LuxString");
|
||||
return Ok(temp);
|
||||
}
|
||||
"startsWith" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
let prefix = self.emit_expr(&args[1])?;
|
||||
return Ok(format!("lux_string_starts_with({}, {})", s, prefix));
|
||||
}
|
||||
"endsWith" => {
|
||||
let s = self.emit_expr(&args[0])?;
|
||||
let suffix = self.emit_expr(&args[1])?;
|
||||
return Ok(format!("lux_string_ends_with({}, {})", s, suffix));
|
||||
}
|
||||
"join" => {
|
||||
let list = self.emit_expr(&args[0])?;
|
||||
let sep = self.emit_expr(&args[1])?;
|
||||
let temp = format!("_join_{}", self.fresh_name());
|
||||
self.writeln(&format!("LuxString {} = lux_string_join({}, {});", temp, list, sep));
|
||||
self.register_rc_var(&temp, "LuxString");
|
||||
return Ok(temp);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -3876,6 +4061,8 @@ impl CBackend {
|
||||
self.writeln("");
|
||||
|
||||
// Execute top-level let bindings with run expressions
|
||||
// Track if main was already called via a run expression
|
||||
let mut main_called_via_run = false;
|
||||
for decl in &program.declarations {
|
||||
if let Declaration::Let(let_decl) = decl {
|
||||
if matches!(&let_decl.value, Expr::Run { .. }) {
|
||||
@@ -3883,6 +4070,10 @@ impl CBackend {
|
||||
if let Expr::Call { func, .. } = expr.as_ref() {
|
||||
if let Expr::Var(fn_name) = func.as_ref() {
|
||||
let mangled = self.mangle_name(&fn_name.name);
|
||||
// Track if this is a call to main
|
||||
if fn_name.name == "main" {
|
||||
main_called_via_run = true;
|
||||
}
|
||||
// Pass default evidence if function uses effects
|
||||
if self.effectful_functions.contains(&fn_name.name) {
|
||||
self.writeln(&format!("{}(&default_evidence);", mangled));
|
||||
@@ -3896,8 +4087,8 @@ impl CBackend {
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a main function, call it
|
||||
if has_main {
|
||||
// If there's a main function and it wasn't already called via run, call it
|
||||
if has_main && !main_called_via_run {
|
||||
// Check if main uses effects (Console typically)
|
||||
if self.effectful_functions.contains("main") {
|
||||
self.writeln("main_lux(&default_evidence);");
|
||||
|
||||
Reference in New Issue
Block a user