diff --git a/src/codegen/js_backend.rs b/src/codegen/js_backend.rs index 7358594..d7718c1 100644 --- a/src/codegen/js_backend.rs +++ b/src/codegen/js_backend.rs @@ -187,6 +187,20 @@ impl JsBackend { } } + // Check for `let main = fn() => ...` pattern (not tracked in self.functions) + let has_let_main = program.declarations.iter().any(|d| { + if let Declaration::Let(l) = d { + l.name.name == "main" && matches!(&l.value, Expr::Lambda { .. }) + } else { + false + } + }); + if has_let_main && !self.functions.contains("main") && !has_main_call { + self.writeln(""); + self.writeln("// Entry point (let main)"); + self.writeln("main();"); + } + Ok(self.output.clone()) } diff --git a/src/main.rs b/src/main.rs index 27e96ba..ab03f0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4286,6 +4286,31 @@ c")"#; assert!(js.contains("Lux.None"), "JS should contain Lux.None for List.get: {}", js); } + #[test] + fn test_let_main_js_codegen() { + use crate::codegen::js_backend::JsBackend; + use crate::parser::Parser; + use crate::lexer::Lexer; + + let source = r#" + let main = fn() => { + print("hello from let main") + } + "#; + + let tokens = Lexer::new(source).tokenize().unwrap(); + let program = Parser::new(tokens).parse_program().unwrap(); + let mut backend = JsBackend::new(); + let js = backend.generate(&program).unwrap(); + + // Should contain the let binding + assert!(js.contains("const main"), "JS should contain 'const main': {}", js); + // Should auto-invoke main() + assert!(js.contains("main();"), "JS should auto-invoke main(): {}", js); + // Should NOT contain main_lux (let bindings aren't mangled) + assert!(!js.contains("main_lux"), "let main should not be mangled: {}", js); + } + #[test] fn test_invalid_escape_sequence() { let result = eval(r#"let x = "\z""#);