2025-09-25 01:09:48 +09:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
impl MirInterpreter {
|
|
|
|
|
pub(super) fn handle_const(&mut self, dst: ValueId, value: &ConstValue) -> Result<(), VMError> {
|
|
|
|
|
let v = match value {
|
|
|
|
|
ConstValue::Integer(i) => VMValue::Integer(*i),
|
|
|
|
|
ConstValue::Float(f) => VMValue::Float(*f),
|
|
|
|
|
ConstValue::Bool(b) => VMValue::Bool(*b),
|
|
|
|
|
ConstValue::String(s) => VMValue::String(s.clone()),
|
|
|
|
|
ConstValue::Null | ConstValue::Void => VMValue::Void,
|
|
|
|
|
};
|
|
|
|
|
self.regs.insert(dst, v);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn handle_binop(
|
|
|
|
|
&mut self,
|
|
|
|
|
dst: ValueId,
|
|
|
|
|
op: BinaryOp,
|
|
|
|
|
lhs: ValueId,
|
|
|
|
|
rhs: ValueId,
|
|
|
|
|
) -> Result<(), VMError> {
|
|
|
|
|
let a = self.reg_load(lhs)?;
|
|
|
|
|
let b = self.reg_load(rhs)?;
|
2025-09-27 08:45:25 +09:00
|
|
|
// Operator Box (Add) — observe always; adopt gated
|
|
|
|
|
if let BinaryOp::Add = op {
|
|
|
|
|
let in_guard = self
|
|
|
|
|
.cur_fn
|
|
|
|
|
.as_deref()
|
|
|
|
|
.map(|n| n.starts_with("AddOperator.apply/"))
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
if let Some(op_fn) = self.functions.get("AddOperator.apply/2").cloned() {
|
|
|
|
|
if !in_guard {
|
|
|
|
|
if crate::config::env::operator_box_add_adopt() {
|
|
|
|
|
let out = self.exec_function_inner(&op_fn, Some(&[a.clone(), b.clone()]))?;
|
|
|
|
|
self.regs.insert(dst, out);
|
|
|
|
|
return Ok(());
|
|
|
|
|
} else {
|
|
|
|
|
let _ = self.exec_function_inner(&op_fn, Some(&[a.clone(), b.clone()]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-25 01:09:48 +09:00
|
|
|
let v = self.eval_binop(op, a, b)?;
|
|
|
|
|
self.regs.insert(dst, v);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn handle_unary_op(
|
|
|
|
|
&mut self,
|
|
|
|
|
dst: ValueId,
|
|
|
|
|
op: crate::mir::UnaryOp,
|
|
|
|
|
operand: ValueId,
|
|
|
|
|
) -> Result<(), VMError> {
|
|
|
|
|
let x = self.reg_load(operand)?;
|
|
|
|
|
let v = match op {
|
|
|
|
|
crate::mir::UnaryOp::Neg => match x {
|
|
|
|
|
VMValue::Integer(i) => VMValue::Integer(-i),
|
|
|
|
|
VMValue::Float(f) => VMValue::Float(-f),
|
|
|
|
|
_ => {
|
|
|
|
|
return Err(VMError::TypeError(format!(
|
|
|
|
|
"neg expects number, got {:?}",
|
|
|
|
|
x
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
crate::mir::UnaryOp::Not => VMValue::Bool(!to_bool_vm(&x).map_err(VMError::TypeError)?),
|
|
|
|
|
crate::mir::UnaryOp::BitNot => match x {
|
|
|
|
|
VMValue::Integer(i) => VMValue::Integer(!i),
|
|
|
|
|
_ => {
|
|
|
|
|
return Err(VMError::TypeError(format!(
|
|
|
|
|
"bitnot expects integer, got {:?}",
|
|
|
|
|
x
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
self.regs.insert(dst, v);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn handle_compare(
|
|
|
|
|
&mut self,
|
|
|
|
|
dst: ValueId,
|
|
|
|
|
op: CompareOp,
|
|
|
|
|
lhs: ValueId,
|
|
|
|
|
rhs: ValueId,
|
|
|
|
|
) -> Result<(), VMError> {
|
|
|
|
|
let a = self.reg_load(lhs)?;
|
|
|
|
|
let b = self.reg_load(rhs)?;
|
2025-09-27 08:45:25 +09:00
|
|
|
// Operator Box (Compare) — observe always; adopt gated
|
|
|
|
|
if let Some(op_fn) = self.functions.get("CompareOperator.apply/3").cloned() {
|
|
|
|
|
let in_guard = self
|
|
|
|
|
.cur_fn
|
|
|
|
|
.as_deref()
|
|
|
|
|
.map(|n| n.starts_with("CompareOperator.apply/"))
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
let opname = match op {
|
|
|
|
|
CompareOp::Eq => "Eq",
|
|
|
|
|
CompareOp::Ne => "Ne",
|
|
|
|
|
CompareOp::Lt => "Lt",
|
|
|
|
|
CompareOp::Le => "Le",
|
|
|
|
|
CompareOp::Gt => "Gt",
|
|
|
|
|
CompareOp::Ge => "Ge",
|
|
|
|
|
};
|
|
|
|
|
if !in_guard {
|
|
|
|
|
if crate::config::env::operator_box_compare_adopt() {
|
|
|
|
|
let out = self.exec_function_inner(
|
|
|
|
|
&op_fn,
|
|
|
|
|
Some(&[VMValue::String(opname.to_string()), a.clone(), b.clone()]),
|
|
|
|
|
)?;
|
|
|
|
|
let res = match out {
|
|
|
|
|
VMValue::Bool(b) => b,
|
|
|
|
|
_ => self.eval_cmp(op, a.clone(), b.clone())?,
|
|
|
|
|
};
|
|
|
|
|
self.regs.insert(dst, VMValue::Bool(res));
|
|
|
|
|
return Ok(());
|
|
|
|
|
} else {
|
|
|
|
|
let _ = self.exec_function_inner(
|
|
|
|
|
&op_fn,
|
|
|
|
|
Some(&[VMValue::String(opname.to_string()), a.clone(), b.clone()]),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-25 01:09:48 +09:00
|
|
|
let res = self.eval_cmp(op, a, b)?;
|
|
|
|
|
self.regs.insert(dst, VMValue::Bool(res));
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn handle_copy(&mut self, dst: ValueId, src: ValueId) -> Result<(), VMError> {
|
|
|
|
|
let v = self.reg_load(src)?;
|
|
|
|
|
self.regs.insert(dst, v);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|