use inkwell::values::{BasicValueEnum, IntValue, PointerValue};
use crate::ast::{BinaryOp, ExpressionKind, ExpressionNode, LiteralNode, PrimitiveType};
use crate::semantics::Type;
use super::CodeGenerator;
impl<'a> CodeGenerator<'a> {
fn infer_method_return_type(&self, receiver_type: &Type, method_name: &str) -> Option<Type> {
self.analyzer
.get_method_sig(receiver_type, method_name)
.map(|sig| sig.return_type)
}
fn ensure_pointer(&mut self, val: BasicValueEnum<'a>) -> PointerValue<'a> {
if val.is_pointer_value() {
val.into_pointer_value()
} else {
self.box_value(val)
}
}
fn generate_numeric_compare(
&mut self,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
int_pred: inkwell::IntPredicate,
float_pred: inkwell::FloatPredicate,
label: &str,
) -> Result<BasicValueEnum<'a>, String> {
if let (Ok(left_int), Ok(right_int)) =
(self.get_raw_int_value(left), self.get_raw_int_value(right))
{
self.builder
.build_int_compare(int_pred, left_int, right_int, label)
.map_err(|e| e.to_string())
.map(|v| v.into())
} else if let (Ok(left_float), Ok(right_float)) = (
self.get_raw_float_value(left),
self.get_raw_float_value(right),
) {
let flabel = format!("f{}", label);
self.builder
.build_float_compare(float_pred, left_float, right_float, &flabel)
.map_err(|e| e.to_string())
.map(|v| v.into())
} else {
Err(format!("Unsupported {} operands", label))
}
}
fn call_comparison_runtime(
&mut self,
left: PointerValue<'a>,
right: PointerValue<'a>,
func_name: &str,
label: &str,
) -> Result<BasicValueEnum<'a>, String> {
let func = self
.runtime_function(func_name)
.ok_or_else(|| format!("{} not found", func_name))?;
let result = self
.builder
.build_call(func, &[left.into(), right.into()], label)
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?;
let result_i32 = result.into_int_value();
self.i32_to_bool(result_i32)
}
fn i32_to_bool(&self, int_val: IntValue<'a>) -> Result<BasicValueEnum<'a>, String> {
let zero = self.context.i32_type().const_zero();
self.builder
.build_int_compare(inkwell::IntPredicate::NE, int_val, zero, "to_bool")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
pub(super) fn resolve_expression_type_with_fallback(
&mut self,
expr: &ExpressionNode,
) -> Result<Type, String> {
match &expr.kind {
ExpressionKind::Identifier(_) => self.resolve_identifier_type(expr),
ExpressionKind::ListAccess { .. } => self.resolve_list_access_type(expr),
ExpressionKind::Call { .. } => self.resolve_call_type(expr),
ExpressionKind::Binary { .. } => self.resolve_binary_type(expr),
_ => self
.analyzer
.get_expression_type(expr)
.map_err(|e| e.to_string()),
}
}
fn resolve_identifier_type(&mut self, expr: &ExpressionNode) -> Result<Type, String> {
let name = match &expr.kind {
ExpressionKind::Identifier(name) => name,
_ => return Err("Expected identifier expression".to_string()),
};
if let Some((_, _, ty)) = self
.variables
.get(name)
.or_else(|| self.global_variables.get(name))
{
return Ok(ty.clone());
}
if let Ok(ty) = self.analyzer.get_expression_type(expr) {
return Ok(ty);
}
if let Some(func_node) = self.function_nodes.get(name) {
let mut param_types = Vec::with_capacity(func_node.params.len());
for param in &func_node.params {
let param_type = self
.analyzer
.resolve_type(¶m.type_)
.map_err(|e| e.to_string())?;
param_types.push(param_type);
}
let return_type = self
.analyzer
.resolve_type(&func_node.return_type)
.map_err(|e| e.to_string())?;
return Ok(Type::Function {
params: param_types,
returns: Box::new(return_type),
default_count: 0,
});
}
if let Some(symbol) = self.analyzer.symbol_table().lookup(name)
&& let Some(ty) = &symbol.type_
{
return Ok(ty.clone());
}
Err(format!("Undefined variable '{}'", name))
}
fn resolve_list_access_type(&mut self, expr: &ExpressionNode) -> Result<Type, String> {
match &expr.kind {
ExpressionKind::ListAccess {
expr: container,
index,
} => {
let container_type = self.resolve_expression_type_with_fallback(container)?;
match container_type {
Type::List(inner) => Ok(*inner),
Type::Map(_, value) => Ok(*value),
Type::Tuple(left, right) => match &index.kind {
ExpressionKind::Literal(LiteralNode::Integer(0)) => Ok(*left),
ExpressionKind::Literal(LiteralNode::Integer(1)) => Ok(*right),
_ => Err("Tuple index must be a literal 0 or 1".to_string()),
},
_ => Err(format!("Cannot index into type: {:?}", container_type)),
}
}
_ => Err("Expected list access expression".to_string()),
}
}
fn resolve_call_type(&mut self, expr: &ExpressionNode) -> Result<Type, String> {
match &expr.kind {
ExpressionKind::Call { func, .. } => {
if let Ok(ty) = self.analyzer.get_expression_type(expr) {
return Ok(ty);
}
if let ExpressionKind::FieldAccess {
expr: receiver_expr,
field,
} = &func.kind
{
let receiver_type =
self.resolve_expression_type_with_fallback(receiver_expr)?;
if let Some(return_type) = self.infer_method_return_type(&receiver_type, field)
{
return Ok(return_type);
}
}
let func_type = self.resolve_expression_type_with_fallback(func)?;
match func_type {
Type::Function { returns, .. } => Ok(*returns),
other => Err(format!("Cannot call non-function type: {:?}", other)),
}
}
_ => Err("Expected call expression".to_string()),
}
}
fn resolve_binary_type(&mut self, expr: &ExpressionNode) -> Result<Type, String> {
match &expr.kind {
ExpressionKind::Binary {
left, op, right, ..
} => {
let left_type = self.resolve_expression_type_with_fallback(left)?;
let right_type = self.resolve_expression_type_with_fallback(right)?;
match op {
BinaryOp::Add
| BinaryOp::Subtract
| BinaryOp::Multiply
| BinaryOp::Divide
| BinaryOp::Modulo
| BinaryOp::Exponent => {
if left_type == Type::Primitive(PrimitiveType::Float)
|| right_type == Type::Primitive(PrimitiveType::Float)
{
Ok(Type::Primitive(PrimitiveType::Float))
} else {
Ok(left_type)
}
}
BinaryOp::Less
| BinaryOp::Greater
| BinaryOp::LessEqual
| BinaryOp::GreaterEqual
| BinaryOp::Equal
| BinaryOp::NotEqual
| BinaryOp::LogicalAnd
| BinaryOp::LogicalOr
| BinaryOp::In => Ok(Type::Primitive(PrimitiveType::Bool)),
BinaryOp::Assign
| BinaryOp::AddAssign
| BinaryOp::SubtractAssign
| BinaryOp::MultiplyAssign
| BinaryOp::DivideAssign
| BinaryOp::ModuloAssign => Ok(left_type),
}
}
_ => Err("Expected binary expression".to_string()),
}
}
pub(super) fn generate_short_circuit_logical_op(
&mut self,
left_expr: &ExpressionNode,
op: &BinaryOp,
right_expr: &ExpressionNode,
) -> Result<BasicValueEnum<'a>, String> {
let current_bb = self
.builder
.get_insert_block()
.ok_or("No current basic block for short-circuit logical operation")?;
let current_fn = current_bb
.get_parent()
.ok_or("No current function for short-circuit logical operation")?;
match op {
BinaryOp::LogicalAnd => {
let eval_right_bb = self
.context
.append_basic_block(current_fn, "and_eval_right");
let merge_bb = self.context.append_basic_block(current_fn, "and_merge");
let left_val = self.generate_expression(left_expr)?;
let left_bool = self.get_raw_bool_value(left_val)?;
let left_bb = self
.builder
.get_insert_block()
.ok_or("No insert block after evaluating left operand")?;
self.builder
.build_conditional_branch(left_bool, eval_right_bb, merge_bb)
.map_err(|e| e.to_string())?;
self.builder.position_at_end(eval_right_bb);
let right_val = self.generate_expression(right_expr)?;
let right_bool = self.get_raw_bool_value(right_val)?;
let right_bb = self
.builder
.get_insert_block()
.ok_or("No insert block after evaluating right operand")?;
self.builder
.build_unconditional_branch(merge_bb)
.map_err(|e| e.to_string())?;
self.builder.position_at_end(merge_bb);
let phi = self
.builder
.build_phi(self.context.bool_type(), "and_result")
.map_err(|e| e.to_string())?;
let false_val = self.context.bool_type().const_zero();
phi.add_incoming(&[
(&false_val, left_bb), (&right_bool, right_bb), ]);
Ok(phi.as_basic_value())
}
BinaryOp::LogicalOr => {
let eval_right_bb = self.context.append_basic_block(current_fn, "or_eval_right");
let merge_bb = self.context.append_basic_block(current_fn, "or_merge");
let left_val = self.generate_expression(left_expr)?;
let left_bool = self.get_raw_bool_value(left_val)?;
let left_bb = self
.builder
.get_insert_block()
.ok_or("No insert block after evaluating left operand")?;
self.builder
.build_conditional_branch(left_bool, merge_bb, eval_right_bb)
.map_err(|e| e.to_string())?;
self.builder.position_at_end(eval_right_bb);
let right_val = self.generate_expression(right_expr)?;
let right_bool = self.get_raw_bool_value(right_val)?;
let right_bb = self
.builder
.get_insert_block()
.ok_or("No insert block after evaluating right operand")?;
self.builder
.build_unconditional_branch(merge_bb)
.map_err(|e| e.to_string())?;
self.builder.position_at_end(merge_bb);
let phi = self
.builder
.build_phi(self.context.bool_type(), "or_result")
.map_err(|e| e.to_string())?;
let true_val = self.context.bool_type().const_int(1, false);
phi.add_incoming(&[
(&true_val, left_bb), (&right_bool, right_bb), ]);
Ok(phi.as_basic_value())
}
_ => Err(
"generate_short_circuit_logical_op called with non-logical operator".to_string(),
),
}
}
fn generate_add_op(
&mut self,
left_expr: &ExpressionNode,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
let left_type = self
.resolve_expression_type_with_fallback(left_expr)
.map_err(|e| format!("Failed to get left operand type for '+': {}", e))?;
match &left_type {
Type::Primitive(PrimitiveType::Str) => {
let left_ptr = self.ensure_pointer(left);
let right_ptr = self.ensure_pointer(right);
let left_cstr = self.extract_c_string_from_value(left_ptr)?;
let right_cstr = self.extract_c_string_from_value(right_ptr)?;
let concat_fn = self
.runtime_function("mux_string_concat")
.ok_or("mux_string_concat not found")?;
let result = self
.builder
.build_call(
concat_fn,
&[left_cstr.into(), right_cstr.into()],
"string_concat",
)
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?
.into_pointer_value();
self.box_string_value(result)
}
Type::List(_) => {
let left_list = self.extract_list_from_value(left.into_pointer_value())?;
let right_list = self.extract_list_from_value(right.into_pointer_value())?;
let concat_fn = self
.runtime_function("mux_list_concat")
.ok_or("mux_list_concat not found")?;
let result_list = self
.builder
.build_call(
concat_fn,
&[left_list.into(), right_list.into()],
"list_concat",
)
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?
.into_pointer_value();
let free_list_fn = self
.runtime_function("mux_free_list")
.ok_or("mux_free_list not found")?;
self.builder
.build_call(free_list_fn, &[left_list.into()], "free_list")
.map_err(|e| e.to_string())?;
self.builder
.build_call(free_list_fn, &[right_list.into()], "free_list")
.map_err(|e| e.to_string())?;
let list_value_fn = self
.runtime_function("mux_list_value")
.ok_or("mux_list_value not found")?;
let result = self
.builder
.build_call(list_value_fn, &[result_list.into()], "list_value")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?;
Ok(result)
}
Type::Map(_, _) => {
let left_map = self.extract_map_from_value(left.into_pointer_value())?;
let right_map = self.extract_map_from_value(right.into_pointer_value())?;
let merge_fn = self
.runtime_function("mux_map_merge")
.ok_or("mux_map_merge not found")?;
let result_map = self
.builder
.build_call(merge_fn, &[left_map.into(), right_map.into()], "map_merge")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?
.into_pointer_value();
let free_map_fn = self
.runtime_function("mux_free_map")
.ok_or("mux_free_map not found")?;
self.builder
.build_call(free_map_fn, &[left_map.into()], "free_map")
.map_err(|e| e.to_string())?;
self.builder
.build_call(free_map_fn, &[right_map.into()], "free_map")
.map_err(|e| e.to_string())?;
let map_value_fn = self
.runtime_function("mux_map_value")
.ok_or("mux_map_value not found")?;
let result = self
.builder
.build_call(map_value_fn, &[result_map.into()], "map_value")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?;
Ok(result)
}
Type::Set(_) => {
let left_set = self.extract_set_from_value(left.into_pointer_value())?;
let right_set = self.extract_set_from_value(right.into_pointer_value())?;
let union_fn = self
.runtime_function("mux_set_union")
.ok_or("mux_set_union not found")?;
let result_set = self
.builder
.build_call(union_fn, &[left_set.into(), right_set.into()], "set_union")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?
.into_pointer_value();
let free_set_fn = self
.runtime_function("mux_free_set")
.ok_or("mux_free_set not found")?;
self.builder
.build_call(free_set_fn, &[left_set.into()], "free_set")
.map_err(|e| e.to_string())?;
self.builder
.build_call(free_set_fn, &[right_set.into()], "free_set")
.map_err(|e| e.to_string())?;
let set_value_fn = self
.runtime_function("mux_set_value")
.ok_or("mux_set_value not found")?;
let result = self
.builder
.build_call(set_value_fn, &[result_set.into()], "set_value")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?;
Ok(result)
}
Type::Primitive(PrimitiveType::Int) => {
let left_int = self.get_raw_int_value(left)?;
let right_int = self.get_raw_int_value(right)?;
self.builder
.build_int_add(left_int, right_int, "add")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::Primitive(PrimitiveType::Float) => {
let left_float = self.get_raw_float_value(left)?;
let right_float = self.get_raw_float_value(right)?;
self.builder
.build_float_add(left_float, right_float, "fadd")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
_ => Err(format!(
"Add operation not supported for type: {:?}",
left_type
)),
}
}
fn generate_subtract_op(
&mut self,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
if let (Ok(left_int), Ok(right_int)) =
(self.get_raw_int_value(left), self.get_raw_int_value(right))
{
self.builder
.build_int_sub(left_int, right_int, "sub")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else if let (Ok(left_float), Ok(right_float)) = (
self.get_raw_float_value(left),
self.get_raw_float_value(right),
) {
self.builder
.build_float_sub(left_float, right_float, "fsub")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else {
Err("Unsupported sub operands".to_string())
}
}
fn generate_multiply_op(
&mut self,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
if let (Ok(left_int), Ok(right_int)) =
(self.get_raw_int_value(left), self.get_raw_int_value(right))
{
self.builder
.build_int_mul(left_int, right_int, "mul")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else if let (Ok(left_float), Ok(right_float)) = (
self.get_raw_float_value(left),
self.get_raw_float_value(right),
) {
self.builder
.build_float_mul(left_float, right_float, "fmul")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else {
Err("Unsupported mul operands".to_string())
}
}
fn generate_divide_op(
&mut self,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
if let (Ok(left_int), Ok(right_int)) =
(self.get_raw_int_value(left), self.get_raw_int_value(right))
{
self.builder
.build_int_signed_div(left_int, right_int, "div")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else if let (Ok(left_float), Ok(right_float)) = (
self.get_raw_float_value(left),
self.get_raw_float_value(right),
) {
self.builder
.build_float_div(left_float, right_float, "fdiv")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else {
Err("Unsupported div operands".to_string())
}
}
fn generate_exponent_op(
&mut self,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
if let (Ok(left_int), Ok(right_int)) =
(self.get_raw_int_value(left), self.get_raw_int_value(right))
{
let pow_fn = self
.runtime_function("mux_int_pow")
.ok_or("mux_int_pow not found")?;
let result = self
.builder
.build_call(pow_fn, &[left_int.into(), right_int.into()], "pow")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?;
Ok(result)
} else if let (Ok(left_float), Ok(right_float)) = (
self.get_raw_float_value(left),
self.get_raw_float_value(right),
) {
let pow_fn = self
.runtime_function("mux_math_pow")
.ok_or("mux_math_pow not found")?;
let result = self
.builder
.build_call(pow_fn, &[left_float.into(), right_float.into()], "pow")
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.ok_or("Call returned no value")?;
Ok(result)
} else {
Err("Unsupported pow operands".to_string())
}
}
fn generate_modulo_op(
&mut self,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
if let (Ok(left_int), Ok(right_int)) =
(self.get_raw_int_value(left), self.get_raw_int_value(right))
{
self.builder
.build_int_signed_rem(left_int, right_int, "mod")
.map_err(|e| e.to_string())
.map(|v| v.into())
} else {
Err("Unsupported mod operands".to_string())
}
}
fn generate_equal_op(
&mut self,
left_expr: &ExpressionNode,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
let left_type = self
.resolve_expression_type_with_fallback(left_expr)
.map_err(|e| format!("Failed to get left operand type for '==': {}", e))?;
match &left_type {
Type::Primitive(PrimitiveType::Str) => {
let left_ptr = self.ensure_pointer(left);
let right_ptr = self.ensure_pointer(right);
let left_cstr = self.extract_c_string_from_value(left_ptr)?;
let right_cstr = self.extract_c_string_from_value(right_ptr)?;
self.call_comparison_runtime(
left_cstr,
right_cstr,
"mux_string_equal",
"string_equal",
)
}
Type::Primitive(PrimitiveType::Int) | Type::Primitive(PrimitiveType::Char) => {
let left_int = self.get_raw_int_value(left)?;
let right_int = self.get_raw_int_value(right)?;
self.builder
.build_int_compare(inkwell::IntPredicate::EQ, left_int, right_int, "eq")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::Primitive(PrimitiveType::Bool) => {
let left_bool = self.get_raw_bool_value(left)?;
let right_bool = self.get_raw_bool_value(right)?;
self.builder
.build_int_compare(inkwell::IntPredicate::EQ, left_bool, right_bool, "eq")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::Primitive(PrimitiveType::Float) => {
let left_float = self.get_raw_float_value(left)?;
let right_float = self.get_raw_float_value(right)?;
self.builder
.build_float_compare(
inkwell::FloatPredicate::OEQ,
left_float,
right_float,
"feq",
)
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::List(_)
| Type::Map(_, _)
| Type::Set(_)
| Type::Tuple(_, _)
| Type::EmptyList
| Type::EmptyMap
| Type::EmptySet => {
let left_ptr = self.ensure_pointer(left);
let right_ptr = self.ensure_pointer(right);
self.call_comparison_runtime(left_ptr, right_ptr, "mux_value_equal", "value_equal")
}
_ => Err(format!(
"Equality comparison not supported for type: {:?}",
left_type
)),
}
}
fn generate_not_equal_op(
&mut self,
left_expr: &ExpressionNode,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
let left_type = self
.resolve_expression_type_with_fallback(left_expr)
.map_err(|e| format!("Failed to get left operand type for '!=': {}", e))?;
match &left_type {
Type::Primitive(PrimitiveType::Str) => {
let left_ptr = self.ensure_pointer(left);
let right_ptr = self.ensure_pointer(right);
let left_cstr = self.extract_c_string_from_value(left_ptr)?;
let right_cstr = self.extract_c_string_from_value(right_ptr)?;
self.call_comparison_runtime(
left_cstr,
right_cstr,
"mux_string_not_equal",
"string_not_equal",
)
}
Type::Primitive(PrimitiveType::Int) | Type::Primitive(PrimitiveType::Char) => {
let left_int = self.get_raw_int_value(left)?;
let right_int = self.get_raw_int_value(right)?;
self.builder
.build_int_compare(inkwell::IntPredicate::NE, left_int, right_int, "ne")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::Primitive(PrimitiveType::Bool) => {
let left_bool = self.get_raw_bool_value(left)?;
let right_bool = self.get_raw_bool_value(right)?;
self.builder
.build_int_compare(inkwell::IntPredicate::NE, left_bool, right_bool, "ne")
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::Primitive(PrimitiveType::Float) => {
let left_float = self.get_raw_float_value(left)?;
let right_float = self.get_raw_float_value(right)?;
self.builder
.build_float_compare(
inkwell::FloatPredicate::ONE,
left_float,
right_float,
"fne",
)
.map_err(|e| e.to_string())
.map(|v| v.into())
}
Type::List(_)
| Type::Map(_, _)
| Type::Set(_)
| Type::EmptyList
| Type::EmptyMap
| Type::EmptySet => {
let left_ptr = self.ensure_pointer(left);
let right_ptr = self.ensure_pointer(right);
self.call_comparison_runtime(
left_ptr,
right_ptr,
"mux_value_not_equal",
"value_not_equal",
)
}
_ => Err(format!(
"Inequality comparison not supported for type: {:?}",
left_type
)),
}
}
fn generate_in_op(
&mut self,
left_expr: &ExpressionNode,
right_expr: &ExpressionNode,
left: BasicValueEnum<'a>,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
let right_type = self
.resolve_expression_type_with_fallback(right_expr)
.map_err(|e| format!("Failed to get right operand type for 'in': {}", e))?;
match right_type {
Type::List(_) | Type::EmptyList => {
let raw_list = self.extract_list_from_value(right.into_pointer_value())?;
let item_ptr = self.ensure_pointer(left);
let result = self
.generate_runtime_call("mux_list_contains", &[raw_list.into(), item_ptr.into()])
.ok_or("mux_list_contains returned no value")?;
let free_fn = self
.runtime_function("mux_free_list")
.ok_or("mux_free_list not found")?;
self.builder
.build_call(free_fn, &[raw_list.into()], "free_list")
.map_err(|e| e.to_string())?;
Ok(result)
}
Type::Set(_) | Type::EmptySet => {
let raw_set = self.extract_set_from_value(right.into_pointer_value())?;
let item_ptr = self.ensure_pointer(left);
let result = self
.generate_runtime_call("mux_set_contains", &[raw_set.into(), item_ptr.into()])
.ok_or("mux_set_contains returned no value")?;
let free_fn = self
.runtime_function("mux_free_set")
.ok_or("mux_free_set not found")?;
self.builder
.build_call(free_fn, &[raw_set.into()], "free_set")
.map_err(|e| e.to_string())?;
Ok(result)
}
Type::Primitive(PrimitiveType::Str) => {
let left_type = self
.resolve_expression_type_with_fallback(left_expr)
.map_err(|e| format!("Failed to get left operand type for 'in': {}", e))?;
let string_ptr = right.into_pointer_value();
match left_type {
Type::Primitive(PrimitiveType::Char) => {
let char_i64 = left.into_int_value();
let contains_fn = self
.runtime_function("mux_string_contains_char")
.ok_or("mux_string_contains_char not found")?;
let result = self
.builder
.build_call(
contains_fn,
&[string_ptr.into(), char_i64.into()],
"string_contains_char",
)
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.expect("mux_string_contains_char should return a basic value");
Ok(result)
}
Type::Primitive(PrimitiveType::Str) => {
let substring_ptr = left.into_pointer_value();
let contains_fn = self
.runtime_function("mux_string_contains")
.ok_or("mux_string_contains not found")?;
let result = self
.builder
.build_call(
contains_fn,
&[string_ptr.into(), substring_ptr.into()],
"string_contains",
)
.map_err(|e| e.to_string())?
.try_as_basic_value()
.left()
.expect("mux_string_contains should return a basic value");
Ok(result)
}
_ => Err(format!(
"Invalid left operand type for 'in' operator with string: {:?}",
left_type
)),
}
}
_ => Err(format!(
"'in' operator not supported for type: {:?}",
right_type
)),
}
}
pub(super) fn generate_binary_op(
&mut self,
left_expr: &ExpressionNode,
left: BasicValueEnum<'a>,
op: &BinaryOp,
right_expr: &ExpressionNode,
right: BasicValueEnum<'a>,
) -> Result<BasicValueEnum<'a>, String> {
match op {
BinaryOp::Add => self.generate_add_op(left_expr, left, right),
BinaryOp::Subtract => self.generate_subtract_op(left, right),
BinaryOp::Multiply => self.generate_multiply_op(left, right),
BinaryOp::Divide => self.generate_divide_op(left, right),
BinaryOp::Exponent => self.generate_exponent_op(left, right),
BinaryOp::Equal => self.generate_equal_op(left_expr, left, right),
BinaryOp::Less => self.generate_numeric_compare(
left,
right,
inkwell::IntPredicate::SLT,
inkwell::FloatPredicate::OLT,
"lt",
),
BinaryOp::Greater => self.generate_numeric_compare(
left,
right,
inkwell::IntPredicate::SGT,
inkwell::FloatPredicate::OGT,
"gt",
),
BinaryOp::LessEqual => self.generate_numeric_compare(
left,
right,
inkwell::IntPredicate::SLE,
inkwell::FloatPredicate::OLE,
"le",
),
BinaryOp::GreaterEqual => self.generate_numeric_compare(
left,
right,
inkwell::IntPredicate::SGE,
inkwell::FloatPredicate::OGE,
"ge",
),
BinaryOp::NotEqual => self.generate_not_equal_op(left_expr, left, right),
BinaryOp::LogicalAnd | BinaryOp::LogicalOr => {
Err("Logical AND/OR should use short-circuit evaluation".to_string())
}
BinaryOp::Modulo => self.generate_modulo_op(left, right),
BinaryOp::In => self.generate_in_op(left_expr, right_expr, left, right),
_ => Err("Binary op not implemented".to_string()),
}
}
}