diff --git a/el-compiler/src/codegen.el b/el-compiler/src/codegen.el index f253533..c72dc85 100644 --- a/el-compiler/src/codegen.el +++ b/el-compiler/src/codegen.el @@ -175,6 +175,47 @@ fn duration_unit_nanos(unit: String) -> String { "1LL" } +// c_safe_name mangles El variable names that are C reserved keywords. +// El allows any identifier; C does not. Append _el to avoid clashes with +// keywords like `short`, `int`, `long`, `char`, `auto`, `register`, etc. +fn c_safe_name(name: String) -> String { + if str_eq(name, "auto") { return "auto_el" } + if str_eq(name, "break") { return "break_el" } + if str_eq(name, "case") { return "case_el" } + if str_eq(name, "char") { return "char_el" } + if str_eq(name, "const") { return "const_el" } + if str_eq(name, "continue") { return "continue_el" } + if str_eq(name, "default") { return "default_el" } + if str_eq(name, "do") { return "do_el" } + if str_eq(name, "double") { return "double_el" } + if str_eq(name, "else") { return "else_el" } + if str_eq(name, "enum") { return "enum_el" } + if str_eq(name, "extern") { return "extern_el" } + if str_eq(name, "float") { return "float_el" } + if str_eq(name, "for") { return "for_el" } + if str_eq(name, "goto") { return "goto_el" } + if str_eq(name, "if") { return "if_el" } + if str_eq(name, "inline") { return "inline_el" } + if str_eq(name, "int") { return "int_el" } + if str_eq(name, "long") { return "long_el" } + if str_eq(name, "register") { return "register_el" } + if str_eq(name, "restrict") { return "restrict_el" } + if str_eq(name, "return") { return "return_el" } + if str_eq(name, "short") { return "short_el" } + if str_eq(name, "signed") { return "signed_el" } + if str_eq(name, "sizeof") { return "sizeof_el" } + if str_eq(name, "static") { return "static_el" } + if str_eq(name, "struct") { return "struct_el" } + if str_eq(name, "switch") { return "switch_el" } + if str_eq(name, "typedef") { return "typedef_el" } + if str_eq(name, "union") { return "union_el" } + if str_eq(name, "unsigned") { return "unsigned_el" } + if str_eq(name, "void") { return "void_el" } + if str_eq(name, "volatile") { return "volatile_el" } + if str_eq(name, "while") { return "while_el" } + return name +} + fn cg_expr(expr: Map) -> String { let kind: String = expr["expr"] @@ -220,7 +261,7 @@ fn cg_expr(expr: Map) -> String { if kind == "Ident" { let name: String = expr["name"] - return name + return c_safe_name(name) } if kind == "Not" { @@ -690,10 +731,18 @@ fn cg_expr(expr: Map) -> String { } } } - // http_serve(port): backward-compat 1-arg form — auto-inject handle_request + // http_serve: handler must be cast (el_val_t)(uintptr_t)fn_ptr because + // the runtime stores function pointers as tagged el_val_t integers. + // 1-arg backward-compat form auto-injects the conventional handle_request name. if str_eq(fn_name, "http_serve") { if arity == 1 { - return "http_serve(" + args_c + ", handle_request)" + let port_c: String = cg_expr(native_list_get(args, 0)) + return "http_serve(" + port_c + ", (el_val_t)(uintptr_t)handle_request)" + } + if arity == 2 { + let port_c: String = cg_expr(native_list_get(args, 0)) + let handler_c: String = cg_expr(native_list_get(args, 1)) + return "http_serve(" + port_c + ", (el_val_t)(uintptr_t)" + handler_c + ")" } } return fn_name + "(" + args_c + ")" @@ -1063,11 +1112,14 @@ fn cg_stmt(stmt: Map, indent: String, declared: [String]) -> [Strin if str_eq(vk, "Int") { add_int_name(name) } + // Mangle C reserved keywords (e.g. `short`, `int`) so the emitted + // variable name is valid C. `declared` tracking uses the El name. + let cname: String = c_safe_name(name) if list_contains(declared, name) { - emit_line(indent + name + " = " + val_c + ";") + emit_line(indent + cname + " = " + val_c + ";") return declared } else { - emit_line(indent + "el_val_t " + name + " = " + val_c + ";") + emit_line(indent + "el_val_t " + cname + " = " + val_c + ";") return native_list_append(declared, name) } }