use decy_codegen::CodeGenerator;
use decy_hir::{BinaryOperator, HirExpression, HirFunction, HirParameter, HirStatement, HirType};
fn void_ptr_param(name: &str) -> HirParameter {
HirParameter::new(name.to_string(), HirType::Pointer(Box::new(HirType::Void)))
}
fn create_void_ptr_function(
name: &str,
params: Vec<HirParameter>,
return_type: HirType,
body: Vec<HirStatement>,
) -> HirFunction {
HirFunction::new_with_body(name.to_string(), return_type, params, body)
}
#[test]
fn test_compare_infers_partial_ord() {
let func = create_void_ptr_function(
"compare",
vec![void_ptr_param("a"), void_ptr_param("b")],
HirType::Int,
vec![HirStatement::Return(Some(HirExpression::BinaryOp {
op: BinaryOperator::LessThan,
left: Box::new(HirExpression::Dereference(Box::new(HirExpression::Variable(
"a".to_string(),
)))),
right: Box::new(HirExpression::Dereference(Box::new(HirExpression::Variable(
"b".to_string(),
)))),
}))],
);
let generator = CodeGenerator::new();
let code = generator.generate_function(&func);
assert!(
code.contains("PartialOrd") || code.contains("Ord"),
"Should infer PartialOrd from < comparison:\n{}",
code
);
}
#[test]
fn test_equality_infers_partial_eq() {
let func = create_void_ptr_function(
"equal",
vec![void_ptr_param("a"), void_ptr_param("b")],
HirType::Int,
vec![HirStatement::Return(Some(HirExpression::BinaryOp {
op: BinaryOperator::Equal,
left: Box::new(HirExpression::Dereference(Box::new(HirExpression::Variable(
"a".to_string(),
)))),
right: Box::new(HirExpression::Dereference(Box::new(HirExpression::Variable(
"b".to_string(),
)))),
}))],
);
let generator = CodeGenerator::new();
let code = generator.generate_function(&func);
assert!(
code.contains("PartialEq") || code.contains("Eq"),
"Should infer PartialEq from == comparison:\n{}",
code
);
}
#[test]
fn test_copy_infers_clone() {
let func = create_void_ptr_function(
"copy_value",
vec![void_ptr_param("dest"), void_ptr_param("src")],
HirType::Void,
vec![HirStatement::DerefAssignment {
target: HirExpression::Variable("dest".to_string()),
value: HirExpression::Dereference(Box::new(HirExpression::Variable("src".to_string()))),
}],
);
let generator = CodeGenerator::new();
let code = generator.generate_function(&func);
assert!(
code.contains("Clone") || code.contains("Copy"),
"Should infer Clone from value copy:\n{}",
code
);
}
#[test]
#[ignore = "DECY-096: Generic fn<T> generation not fully implemented"]
fn test_no_ops_no_bounds() {
let func =
create_void_ptr_function("process", vec![void_ptr_param("data")], HirType::Void, vec![]);
let generator = CodeGenerator::new();
let code = generator.generate_function(&func);
assert!(code.contains("<T>"), "Should have generic T:\n{}", code);
let has_bounds = code.contains("T:") || code.contains("where T");
assert!(!has_bounds, "Should NOT have trait bounds for no-op function:\n{}", code);
}
#[test]
fn test_multiple_ops_multiple_bounds() {
let func = create_void_ptr_function(
"sort_swap",
vec![void_ptr_param("a"), void_ptr_param("b")],
HirType::Void,
vec![
HirStatement::If {
condition: HirExpression::BinaryOp {
op: BinaryOperator::GreaterThan,
left: Box::new(HirExpression::Dereference(Box::new(HirExpression::Variable(
"a".to_string(),
)))),
right: Box::new(HirExpression::Dereference(Box::new(HirExpression::Variable(
"b".to_string(),
)))),
},
then_block: vec![
HirStatement::DerefAssignment {
target: HirExpression::Variable("a".to_string()),
value: HirExpression::Dereference(Box::new(HirExpression::Variable(
"b".to_string(),
))),
},
],
else_block: None,
},
],
);
let generator = CodeGenerator::new();
let code = generator.generate_function(&func);
let has_ord = code.contains("PartialOrd") || code.contains("Ord");
let has_clone = code.contains("Clone") || code.contains("Copy");
assert!(
has_ord || has_clone,
"Should have at least one trait bound for complex function:\n{}",
code
);
}
#[test]
fn test_non_void_ptr_no_trait_analysis() {
let func = HirFunction::new_with_body(
"add".to_string(),
HirType::Int,
vec![
HirParameter::new("a".to_string(), HirType::Int),
HirParameter::new("b".to_string(), HirType::Int),
],
vec![],
);
let generator = CodeGenerator::new();
let code = generator.generate_function(&func);
assert!(
!code.contains("<T>") && !code.contains("where"),
"Should NOT have generics for non-void* function:\n{}",
code
);
}