2025-09-17 07:43:07 +09:00
|
|
|
|
use super::{MirInstruction, MirType, ValueId};
|
2025-09-03 05:04:56 +09:00
|
|
|
|
use crate::ast::{ASTNode, BinaryOperator};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
use crate::mir::{BinaryOp, CompareOp, TypeOpKind, UnaryOp};
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
|
|
// Internal classification for binary operations
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
enum BinaryOpType {
|
|
|
|
|
|
Arithmetic(BinaryOp),
|
|
|
|
|
|
Comparison(CompareOp),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl super::MirBuilder {
|
|
|
|
|
|
// Build a binary operation
|
|
|
|
|
|
pub(super) fn build_binary_op(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
left: ASTNode,
|
|
|
|
|
|
operator: BinaryOperator,
|
|
|
|
|
|
right: ASTNode,
|
|
|
|
|
|
) -> Result<ValueId, String> {
|
|
|
|
|
|
let lhs = self.build_expression(left)?;
|
|
|
|
|
|
let rhs = self.build_expression(right)?;
|
|
|
|
|
|
let dst = self.value_gen.next();
|
|
|
|
|
|
|
|
|
|
|
|
let mir_op = self.convert_binary_operator(operator)?;
|
|
|
|
|
|
|
|
|
|
|
|
match mir_op {
|
|
|
|
|
|
// Arithmetic operations
|
|
|
|
|
|
BinaryOpType::Arithmetic(op) => {
|
|
|
|
|
|
self.emit_instruction(MirInstruction::BinOp { dst, op, lhs, rhs })?;
|
2025-09-14 19:16:32 +09:00
|
|
|
|
// '+' は文字列連結の可能性がある。オペランドが String/StringBox なら結果を String と注釈。
|
|
|
|
|
|
if matches!(op, crate::mir::BinaryOp::Add) {
|
|
|
|
|
|
let lhs_is_str = match self.value_types.get(&lhs) {
|
|
|
|
|
|
Some(MirType::String) => true,
|
|
|
|
|
|
Some(MirType::Box(bt)) if bt == "StringBox" => true,
|
|
|
|
|
|
_ => false,
|
|
|
|
|
|
};
|
|
|
|
|
|
let rhs_is_str = match self.value_types.get(&rhs) {
|
|
|
|
|
|
Some(MirType::String) => true,
|
|
|
|
|
|
Some(MirType::Box(bt)) if bt == "StringBox" => true,
|
|
|
|
|
|
_ => false,
|
|
|
|
|
|
};
|
|
|
|
|
|
if lhs_is_str || rhs_is_str {
|
|
|
|
|
|
self.value_types.insert(dst, MirType::String);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.value_types.insert(dst, MirType::Integer);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// その他の算術は整数
|
|
|
|
|
|
self.value_types.insert(dst, MirType::Integer);
|
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
}
|
|
|
|
|
|
// Comparison operations
|
|
|
|
|
|
BinaryOpType::Comparison(op) => {
|
|
|
|
|
|
// 80/20: If both operands originate from IntegerBox, cast to integer first
|
|
|
|
|
|
let (lhs2, rhs2) = if self
|
|
|
|
|
|
.value_origin_newbox
|
|
|
|
|
|
.get(&lhs)
|
|
|
|
|
|
.map(|s| s == "IntegerBox")
|
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
|
&& self
|
|
|
|
|
|
.value_origin_newbox
|
|
|
|
|
|
.get(&rhs)
|
|
|
|
|
|
.map(|s| s == "IntegerBox")
|
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
|
{
|
|
|
|
|
|
let li = self.value_gen.next();
|
|
|
|
|
|
let ri = self.value_gen.next();
|
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
|
dst: li,
|
|
|
|
|
|
op: TypeOpKind::Cast,
|
|
|
|
|
|
value: lhs,
|
|
|
|
|
|
ty: MirType::Integer,
|
|
|
|
|
|
})?;
|
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
|
dst: ri,
|
|
|
|
|
|
op: TypeOpKind::Cast,
|
|
|
|
|
|
value: rhs,
|
|
|
|
|
|
ty: MirType::Integer,
|
|
|
|
|
|
})?;
|
|
|
|
|
|
(li, ri)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
(lhs, rhs)
|
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::Compare {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op,
|
|
|
|
|
|
lhs: lhs2,
|
|
|
|
|
|
rhs: rhs2,
|
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
|
self.value_types.insert(dst, MirType::Bool);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build a unary operation
|
2025-09-17 07:43:07 +09:00
|
|
|
|
pub(super) fn build_unary_op(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
operator: String,
|
|
|
|
|
|
operand: ASTNode,
|
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
|
let operand_val = self.build_expression(operand)?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
// Core-13 純化: UnaryOp を直接 展開(Neg/Not/BitNot)
|
|
|
|
|
|
if crate::config::env::mir_core13_pure() {
|
|
|
|
|
|
match operator.as_str() {
|
|
|
|
|
|
"-" => {
|
|
|
|
|
|
let zero = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
|
dst: zero,
|
|
|
|
|
|
value: crate::mir::ConstValue::Integer(0),
|
|
|
|
|
|
})?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
let dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::BinOp {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: crate::mir::BinaryOp::Sub,
|
|
|
|
|
|
lhs: zero,
|
|
|
|
|
|
rhs: operand_val,
|
|
|
|
|
|
})?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
return Ok(dst);
|
|
|
|
|
|
}
|
|
|
|
|
|
"!" | "not" => {
|
|
|
|
|
|
let f = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
|
dst: f,
|
|
|
|
|
|
value: crate::mir::ConstValue::Bool(false),
|
|
|
|
|
|
})?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
let dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::Compare {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: crate::mir::CompareOp::Eq,
|
|
|
|
|
|
lhs: operand_val,
|
|
|
|
|
|
rhs: f,
|
|
|
|
|
|
})?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
return Ok(dst);
|
|
|
|
|
|
}
|
|
|
|
|
|
"~" => {
|
|
|
|
|
|
let all1 = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
|
dst: all1,
|
|
|
|
|
|
value: crate::mir::ConstValue::Integer(-1),
|
|
|
|
|
|
})?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
let dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::BinOp {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: crate::mir::BinaryOp::BitXor,
|
|
|
|
|
|
lhs: operand_val,
|
|
|
|
|
|
rhs: all1,
|
|
|
|
|
|
})?;
|
2025-09-07 07:28:53 +09:00
|
|
|
|
return Ok(dst);
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
let dst = self.value_gen.next();
|
|
|
|
|
|
let mir_op = self.convert_unary_operator(operator)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
|
self.emit_instruction(MirInstruction::UnaryOp {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
op: mir_op,
|
|
|
|
|
|
operand: operand_val,
|
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
|
Ok(dst)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Convert AST binary operator to MIR enum or compare
|
|
|
|
|
|
fn convert_binary_operator(&self, op: BinaryOperator) -> Result<BinaryOpType, String> {
|
|
|
|
|
|
match op {
|
|
|
|
|
|
BinaryOperator::Add => Ok(BinaryOpType::Arithmetic(BinaryOp::Add)),
|
|
|
|
|
|
BinaryOperator::Subtract => Ok(BinaryOpType::Arithmetic(BinaryOp::Sub)),
|
|
|
|
|
|
BinaryOperator::Multiply => Ok(BinaryOpType::Arithmetic(BinaryOp::Mul)),
|
|
|
|
|
|
BinaryOperator::Divide => Ok(BinaryOpType::Arithmetic(BinaryOp::Div)),
|
|
|
|
|
|
BinaryOperator::Modulo => Ok(BinaryOpType::Arithmetic(BinaryOp::Mod)),
|
2025-09-08 03:44:55 +09:00
|
|
|
|
BinaryOperator::Shl => Ok(BinaryOpType::Arithmetic(BinaryOp::Shl)),
|
2025-09-08 03:54:34 +09:00
|
|
|
|
BinaryOperator::Shr => Ok(BinaryOpType::Arithmetic(BinaryOp::Shr)),
|
|
|
|
|
|
BinaryOperator::BitAnd => Ok(BinaryOpType::Arithmetic(BinaryOp::BitAnd)),
|
|
|
|
|
|
BinaryOperator::BitOr => Ok(BinaryOpType::Arithmetic(BinaryOp::BitOr)),
|
|
|
|
|
|
BinaryOperator::BitXor => Ok(BinaryOpType::Arithmetic(BinaryOp::BitXor)),
|
2025-09-03 05:04:56 +09:00
|
|
|
|
BinaryOperator::Equal => Ok(BinaryOpType::Comparison(CompareOp::Eq)),
|
|
|
|
|
|
BinaryOperator::NotEqual => Ok(BinaryOpType::Comparison(CompareOp::Ne)),
|
|
|
|
|
|
BinaryOperator::Less => Ok(BinaryOpType::Comparison(CompareOp::Lt)),
|
|
|
|
|
|
BinaryOperator::LessEqual => Ok(BinaryOpType::Comparison(CompareOp::Le)),
|
|
|
|
|
|
BinaryOperator::Greater => Ok(BinaryOpType::Comparison(CompareOp::Gt)),
|
|
|
|
|
|
BinaryOperator::GreaterEqual => Ok(BinaryOpType::Comparison(CompareOp::Ge)),
|
|
|
|
|
|
BinaryOperator::And => Ok(BinaryOpType::Arithmetic(BinaryOp::And)),
|
|
|
|
|
|
BinaryOperator::Or => Ok(BinaryOpType::Arithmetic(BinaryOp::Or)),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Convert AST unary operator to MIR operator
|
|
|
|
|
|
fn convert_unary_operator(&self, op: String) -> Result<UnaryOp, String> {
|
|
|
|
|
|
match op.as_str() {
|
|
|
|
|
|
"-" => Ok(UnaryOp::Neg),
|
|
|
|
|
|
"!" | "not" => Ok(UnaryOp::Not),
|
|
|
|
|
|
"~" => Ok(UnaryOp::BitNot),
|
|
|
|
|
|
_ => Err(format!("Unsupported unary operator: {}", op)),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|