diff --git a/scripts/validate.sh b/scripts/validate.sh index cb87474..130d555 100755 --- a/scripts/validate.sh +++ b/scripts/validate.sh @@ -30,7 +30,7 @@ fail() { printf "${RED}FAIL${NC} %s\n" "${1:-}"; FAILED=$((FAILED + 1)); } # --- Rust checks --- step "cargo check" -if nix develop --command cargo check 2>&1 | grep -q "Finished"; then ok; else fail; fi +if nix develop --command cargo check 2>/dev/null; then ok; else fail; fi step "cargo test" OUTPUT=$(nix develop --command cargo test 2>&1 || true) @@ -39,7 +39,7 @@ if echo "$RESULT" | grep -q "0 failed"; then ok "$RESULT"; else fail "$RESULT"; # --- Build release binary --- step "cargo build --release" -if nix develop --command cargo build --release 2>&1 | grep -q "Finished"; then ok; else fail; fi +if nix develop --command cargo build --release 2>/dev/null; then ok; else fail; fi # --- Package tests --- for pkg in path frontmatter xml rss markdown; do diff --git a/src/codegen/c_backend.rs b/src/codegen/c_backend.rs index a7a9619..0eb34d4 100644 --- a/src/codegen/c_backend.rs +++ b/src/codegen/c_backend.rs @@ -279,7 +279,7 @@ impl CBackend { Declaration::Let(let_decl) => { // Skip run expressions - they're handled in the main wrapper if !matches!(&let_decl.value, Expr::Run { .. }) { - self.emit_global_let(&let_decl.name, &let_decl.value)?; + self.emit_global_let(&let_decl.name)?; } } _ => {} @@ -5561,9 +5561,9 @@ impl CBackend { } } - fn emit_global_let(&mut self, name: &Ident, value: &Expr) -> Result<(), CGenError> { - let val = self.emit_expr(value)?; - self.writeln(&format!("static LuxInt {} = {};", name.name, val)); + fn emit_global_let(&mut self, name: &Ident) -> Result<(), CGenError> { + // Declare global variable without initializer (initialized in main) + self.writeln(&format!("static LuxInt {} = 0;", name.name)); self.writeln(""); Ok(()) } @@ -5574,12 +5574,16 @@ impl CBackend { matches!(d, Declaration::Function(f) if f.name.name == "main") }); - // Check for top-level run expressions + // Check for top-level run expressions or let bindings let has_run = program.declarations.iter().any(|d| { matches!(d, Declaration::Let(let_decl) if matches!(&let_decl.value, Expr::Run { .. })) }); - if has_main || has_run { + let has_global_lets = program.declarations.iter().any(|d| { + matches!(d, Declaration::Let(let_decl) if !matches!(&let_decl.value, Expr::Run { .. })) + }); + + if has_main || has_run || has_global_lets { self.writeln("int main(int argc, char** argv) {"); self.indent += 1; @@ -5588,6 +5592,16 @@ impl CBackend { self.writeln("lux_argv = argv;"); self.writeln(""); + // Initialize top-level let bindings (non-run) inside main + for decl in &program.declarations { + if let Declaration::Let(let_decl) = decl { + if !matches!(&let_decl.value, Expr::Run { .. }) { + let val = self.emit_expr(&let_decl.value)?; + self.writeln(&format!("{} = {};", let_decl.name.name, val)); + } + } + } + // 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;