diff --git a/src/codegen/c_backend.rs b/src/codegen/c_backend.rs index 47d5e7e..9eea50a 100644 --- a/src/codegen/c_backend.rs +++ b/src/codegen/c_backend.rs @@ -318,6 +318,20 @@ impl CBackend { Expr::BinaryOp { op, left, right, .. } => { let l = self.emit_expr_with_env(left, captured)?; let r = self.emit_expr_with_env(right, captured)?; + + // Check for string comparison - use strcmp instead of pointer comparison + if matches!(op, BinaryOp::Eq | BinaryOp::Ne) { + let left_is_string = self.is_string_expr(left); + let right_is_string = self.is_string_expr(right); + if left_is_string || right_is_string { + if matches!(op, BinaryOp::Eq) { + return Ok(format!("(strcmp({}, {}) == 0)", l, r)); + } else { + return Ok(format!("(strcmp({}, {}) != 0)", l, r)); + } + } + } + let op_str = match op { BinaryOp::Add => "+", BinaryOp::Sub => "-", @@ -2229,6 +2243,19 @@ impl CBackend { } } + // Check for string comparison - use strcmp instead of pointer comparison + if matches!(op, BinaryOp::Eq | BinaryOp::Ne) { + let left_is_string = self.is_string_expr(left); + let right_is_string = self.is_string_expr(right); + if left_is_string || right_is_string { + if matches!(op, BinaryOp::Eq) { + return Ok(format!("(strcmp({}, {}) == 0)", l, r)); + } else { + return Ok(format!("(strcmp({}, {}) != 0)", l, r)); + } + } + } + let op_str = match op { BinaryOp::Add => "+", BinaryOp::Sub => "-", @@ -2341,6 +2368,16 @@ impl CBackend { Expr::Let { name, value, body, .. } => { let val = self.emit_expr(value)?; + + // Handle underscore pattern - just evaluate the expression, discard result + if name.name == "_" { + // Just emit the expression for its side effects + self.writeln(&format!("(void){};", val)); + // Continue with body + let body_result = self.emit_expr(body)?; + return Ok(body_result); + } + let var_name = format!("{}_{}", name.name, self.fresh_name()); // Infer the type from the value expression @@ -2541,6 +2578,16 @@ impl CBackend { for stmt in statements { match stmt { Statement::Let { name, value, .. } => { + // Handle underscore pattern - just evaluate the expression, discard result + if name.name == "_" { + let val = self.emit_expr(value)?; + // Just evaluate for side effects, don't store + if !val.is_empty() && !val.starts_with("(void)") { + self.writeln(&format!("(void){};", val)); + } + continue; + } + // First, infer type from value expression (before emitting) let inferred_type = self.infer_expr_type(value); @@ -3196,7 +3243,18 @@ impl CBackend { } let list = self.emit_expr(&args[0])?; let result_var = format!("_head_{}", self.fresh_name()); - self.writeln(&format!("Option {} = ({}->length > 0) ? lux_option_some({}->elements[0]) : lux_option_none();", result_var, list, list)); + // Need to incref the element since it's being extracted from the list + self.writeln(&format!("Option {};", result_var)); + self.writeln(&format!("if ({0}->length > 0) {{", list)); + self.indent += 1; + self.writeln(&format!("lux_incref({0}->elements[0]);", list)); + self.writeln(&format!("{0} = lux_option_some({1}->elements[0]);", result_var, list)); + self.indent -= 1; + self.writeln("} else {"); + self.indent += 1; + self.writeln(&format!("{} = lux_option_none();", result_var)); + self.indent -= 1; + self.writeln("}"); Ok(result_var) } "tail" => { @@ -3211,6 +3269,8 @@ impl CBackend { self.writeln(&format!("LuxList* _tail_list = lux_list_new({0}->length - 1);", list)); self.writeln(&format!("for (int64_t i = 1; i < {0}->length; i++) {{", list)); self.indent += 1; + // Incref each element being copied to the new list + self.writeln(&format!("lux_incref({0}->elements[i]);", list)); self.writeln(&format!("_tail_list->elements[i-1] = {0}->elements[i];", list)); self.indent -= 1; self.writeln("}"); @@ -3231,7 +3291,18 @@ impl CBackend { let list = self.emit_expr(&args[0])?; let idx = self.emit_expr(&args[1])?; let result_var = format!("_get_{}", self.fresh_name()); - self.writeln(&format!("Option {} = ({} >= 0 && {} < {}->length) ? lux_option_some({}->elements[{}]) : lux_option_none();", result_var, idx, idx, list, list, idx)); + // Need to incref the element since it's being extracted from the list + self.writeln(&format!("Option {};", result_var)); + self.writeln(&format!("if ({0} >= 0 && {0} < {1}->length) {{", idx, list)); + self.indent += 1; + self.writeln(&format!("lux_incref({0}->elements[{1}]);", list, idx)); + self.writeln(&format!("{0} = lux_option_some({1}->elements[{2}]);", result_var, list, idx)); + self.indent -= 1; + self.writeln("} else {"); + self.indent += 1; + self.writeln(&format!("{} = lux_option_none();", result_var)); + self.indent -= 1; + self.writeln("}"); Ok(result_var) } diff --git a/src/parser.rs b/src/parser.rs index 4529940..5604d35 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -532,7 +532,14 @@ impl Parser { let start = self.current_span(); self.expect(TokenKind::Let)?; - let name = self.parse_ident()?; + // Allow underscore as wildcard pattern (discards the value) + let name = if self.check(TokenKind::Underscore) { + let span = self.current_span(); + self.advance(); + Ident::new("_".to_string(), span) + } else { + self.parse_ident()? + }; let typ = if self.check(TokenKind::Colon) { self.advance(); @@ -1962,7 +1969,14 @@ impl Parser { let start = self.current_span(); self.expect(TokenKind::Let)?; - let name = self.parse_ident()?; + // Allow underscore as wildcard pattern (discards the value) + let name = if self.check(TokenKind::Underscore) { + let span = self.current_span(); + self.advance(); + Ident::new("_".to_string(), span) + } else { + self.parse_ident()? + }; let typ = if self.check(TokenKind::Colon) { self.advance(); @@ -2207,7 +2221,15 @@ impl Parser { // Let statement let let_start = self.current_span(); self.advance(); - let name = self.parse_ident()?; + + // Allow underscore as wildcard pattern (discards the value) + let name = if self.check(TokenKind::Underscore) { + let span = self.current_span(); + self.advance(); + Ident::new("_".to_string(), span) + } else { + self.parse_ident()? + }; let typ = if self.check(TokenKind::Colon) { self.advance();