Skip to main content

vm/
binary.rs

1use super::{JITRunTime, context::BuildContext};
2use cranelift::prelude::*;
3use dynamic::{Dynamic, Type};
4use parser::{BinaryOp, Expr};
5
6use anyhow::{Result, anyhow};
7
8impl JITRunTime {
9    fn strcat(&mut self, ctx: &mut BuildContext, left: Value, right: Value) -> Result<Value> {
10        let fn_id = self.strcat_fn.ok_or_else(|| anyhow!("VM strcat runtime is not registered"))?;
11        let fn_ref = self.get_fn_ref(ctx, fn_id);
12        let call_inst = ctx.builder.ins().call(fn_ref, &[left, right]);
13        Ok(ctx.builder.inst_results(call_inst)[0])
14    }
15
16    fn strcat_i64(&mut self, ctx: &mut BuildContext, left: Value, right: Value) -> Result<Value> {
17        let fn_id = self.strcat_i64_fn.ok_or_else(|| anyhow!("VM strcat i64 runtime is not registered"))?;
18        let fn_ref = self.get_fn_ref(ctx, fn_id);
19        let call_inst = ctx.builder.ins().call(fn_ref, &[left, right]);
20        Ok(ctx.builder.inst_results(call_inst)[0])
21    }
22
23    fn strcat_assign(&mut self, ctx: &mut BuildContext, left: Value, right: Value) -> Result<Value> {
24        let fn_id = self.strcat_assign_fn.ok_or_else(|| anyhow!("VM strcat assign runtime is not registered"))?;
25        let fn_ref = self.get_fn_ref(ctx, fn_id);
26        let call_inst = ctx.builder.ins().call(fn_ref, &[left, right]);
27        Ok(ctx.builder.inst_results(call_inst)[0])
28    }
29
30    fn any_to_string(&mut self, ctx: &mut BuildContext, vt: (Value, Type)) -> Result<Value> {
31        let value = self.convert(ctx, vt, Type::Any)?;
32        self.call(ctx, self.get_method(&Type::Any, "to_string")?, vec![value]).map(|(v, _)| v)
33    }
34
35    fn any_logic(&mut self, ctx: &mut BuildContext, left: Value, op: BinaryOp, right: Value) -> Result<(Value, Type)> {
36        let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
37        self.call(ctx, self.get_method(&Type::Any, "logic")?, vec![left, op, right])
38    }
39
40    fn any_binary(&mut self, ctx: &mut BuildContext, left: Value, op: BinaryOp, right: Value) -> Result<(Value, Type)> {
41        let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
42        self.call(ctx, self.get_method(&Type::Any, "binary")?, vec![left, op, right])
43    }
44
45    fn struct_to_dynamic(&mut self, ctx: &mut BuildContext, base: Value, ty: &Type) -> Result<Value> {
46        let Type::Struct { params: _, fields: _ } = ty else {
47            return Err(anyhow!("不是结构体 {:?}", ty));
48        };
49        let ty_ptr = Self::type_ptr_const(ctx, ty);
50        let fn_id = self.struct_from_ptr_fn.ok_or_else(|| anyhow!("VM struct Dynamic runtime is not registered"))?;
51        let fn_ref = self.get_fn_ref(ctx, fn_id);
52        let call_inst = ctx.builder.ins().call(fn_ref, &[base, ty_ptr]);
53        Ok(ctx.builder.inst_results(call_inst)[0])
54    }
55
56    fn array_to_dynamic(&mut self, ctx: &mut BuildContext, base: Value, ty: &Type) -> Result<Value> {
57        let Type::Array(_, _) = ty else {
58            return Err(anyhow!("不是数组 {:?}", ty));
59        };
60        let ty_ptr = Self::type_ptr_const(ctx, ty);
61        let fn_id = self.array_from_ptr_fn.ok_or_else(|| anyhow!("VM array Dynamic runtime is not registered"))?;
62        let fn_ref = self.get_fn_ref(ctx, fn_id);
63        let call_inst = ctx.builder.ins().call(fn_ref, &[base, ty_ptr]);
64        Ok(ctx.builder.inst_results(call_inst)[0])
65    }
66
67    pub(crate) fn bool_value(&mut self, ctx: &mut BuildContext, vt: (Value, Type)) -> Result<Value> {
68        if vt.1.is_bool() {
69            Ok(vt.0)
70        } else if vt.1.is_void() {
71            Ok(ctx.builder.ins().iconst(types::I8, 0))
72        } else if vt.1.is_any() {
73            self.call(ctx, self.get_method(&Type::Any, "to_bool")?, vec![vt.0]).map(|(v, _)| v)
74        } else if vt.1.is_int() || vt.1.is_uint() {
75            Ok(ctx.builder.ins().icmp_imm(IntCC::NotEqual, vt.0, 0))
76        } else if vt.1.is_f32() {
77            let zero = ctx.builder.ins().f32const(0.0);
78            Ok(ctx.builder.ins().fcmp(FloatCC::NotEqual, vt.0, zero))
79        } else if vt.1.is_f64() {
80            let zero = ctx.builder.ins().f64const(0.0);
81            Ok(ctx.builder.ins().fcmp(FloatCC::NotEqual, vt.0, zero))
82        } else {
83            Err(anyhow!("cannot convert {:?} to bool", vt.1))
84        }
85    }
86
87    pub fn convert(&mut self, ctx: &mut BuildContext, vt: (Value, Type), ty: Type) -> Result<Value> {
88        let vt = if matches!(vt.1, Type::Symbol { .. }) {
89            let resolved = self.compiler.symbols.get_type(&vt.1).unwrap_or_else(|_| vt.1.clone());
90            (vt.0, resolved)
91        } else {
92            vt
93        };
94        if vt.1 != ty {
95            if ty.is_any() {
96                if self.is_opaque_custom_ty(&vt.1) {
97                    return Ok(vt.0);
98                } else if vt.1.is_array() {
99                    return self.array_to_dynamic(ctx, vt.0, &vt.1);
100                } else if vt.1.is_struct() {
101                    return self.struct_to_dynamic(ctx, vt.0, &vt.1);
102                } else if vt.1.is_bool() {
103                    return self.call(ctx, self.get_method(&Type::Any, "from_bool")?, vec![vt.0]).map(|(v, _)| v);
104                } else if vt.1.is_uint() {
105                    if vt.1.width() == 8 {
106                        // u64 → Any:必须用 from_u64 保留无符号语义,from_i64 会在 >i64::MAX 时产生负数
107                        return self.call(ctx, self.get_method(&Type::Any, "from_u64")?, vec![vt.0]).map(|(v, _)| v);
108                    }
109                    let v = ctx.builder.ins().uextend(types::I64, vt.0);
110                    return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
111                } else if vt.1.is_int() {
112                    let v = if vt.1.width() < 8 { ctx.builder.ins().sextend(types::I64, vt.0) } else { vt.0 };
113                    return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
114                } else if vt.1.is_f32() {
115                    let v = ctx.builder.ins().fpromote(types::F64, vt.0);
116                    return self.call(ctx, self.get_method(&Type::Any, "from_f64")?, vec![v]).map(|(v, _)| v);
117                } else if vt.1.is_f64() {
118                    return self.call(ctx, self.get_method(&Type::Any, "from_f64")?, vec![vt.0]).map(|(v, _)| v);
119                } else if vt.1.is_str() {
120                    return Ok(vt.0);
121                } else if matches!(vt.1, Type::Map | Type::List(_) | Type::Iter) {
122                    return Ok(vt.0);
123                } else if matches!(vt.1, Type::Symbol { .. }) {
124                    return Ok(vt.0);
125                }
126            } else if vt.1.is_any() {
127                if ty.is_bool() {
128                    return self.call(ctx, self.get_method(&Type::Any, "to_bool")?, vec![vt.0]).map(|(v, _)| v);
129                } else if ty.is_array() {
130                    return self.any_to_array(ctx, vt.0, &ty);
131                } else if ty.is_str() {
132                    return self.call(ctx, self.get_method(&Type::Any, "to_string")?, vec![vt.0]).map(|(v, _)| v);
133                } else if ty.is_int() | ty.is_uint() {
134                    let (v, _) = self.call(ctx, self.get_method(&Type::Any, "to_i64")?, vec![vt.0])?;
135                    return Ok(match ty.width() {
136                        1 => ctx.builder.ins().ireduce(types::I8, v),
137                        2 => ctx.builder.ins().ireduce(types::I16, v),
138                        4 => ctx.builder.ins().ireduce(types::I32, v),
139                        _ => v,
140                    });
141                } else if ty.is_f32() {
142                    let v = self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v)?;
143                    return Ok(ctx.builder.ins().fdemote(types::F32, v));
144                } else if ty.is_f64() {
145                    return self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v);
146                } else {
147                    return Ok(vt.0);
148                }
149            } else if ty.is_str() {
150                return self.any_to_string(ctx, vt);
151            } else if ty.is_int() || ty.is_uint() {
152                if vt.1.is_f32() || vt.1.is_f64() {
153                    let target = crate::get_type(&ty)?;
154                    if ty.is_uint() {
155                        return Ok(ctx.builder.ins().fcvt_to_uint(target, vt.0));
156                    } else if ty.is_int() {
157                        return Ok(ctx.builder.ins().fcvt_to_sint(target, vt.0));
158                    }
159                }
160                if vt.1.is_int() || vt.1.is_uint() || vt.1.is_bool() {
161                    let target = crate::get_type(&ty)?;
162                    let actual = ctx.builder.func.dfg.value_type(vt.0);
163                    if actual == target {
164                        return Ok(vt.0);
165                    }
166                    if actual.is_int() && target.is_int() {
167                        if actual.bits() > target.bits() {
168                            return Ok(ctx.builder.ins().ireduce(target, vt.0));
169                        }
170                        if actual.bits() < target.bits() {
171                            return if vt.1.is_int() { Ok(ctx.builder.ins().sextend(target, vt.0)) } else { Ok(ctx.builder.ins().uextend(target, vt.0)) };
172                        }
173                    }
174                }
175                if vt.1.is_str() {
176                    let (v, _) = self.call(ctx, self.get_method(&Type::Any, "to_i64")?, vec![vt.0])?;
177                    return Ok(match ty.width() {
178                        1 => ctx.builder.ins().ireduce(types::I8, v),
179                        2 => ctx.builder.ins().ireduce(types::I16, v),
180                        4 => ctx.builder.ins().ireduce(types::I32, v),
181                        _ => v,
182                    });
183                }
184            } else if ty.is_f32() {
185                if vt.1.is_int() {
186                    return Ok(ctx.builder.ins().fcvt_from_sint(types::F32, vt.0));
187                } else if vt.1.is_uint() {
188                    return Ok(ctx.builder.ins().fcvt_from_uint(types::F32, vt.0));
189                } else if vt.1.is_f64() {
190                    return Ok(ctx.builder.ins().fdemote(types::F32, vt.0));
191                } else if vt.1.is_str() {
192                    let v = self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v)?;
193                    return Ok(ctx.builder.ins().fdemote(types::F32, v));
194                }
195            } else if ty.is_f64() {
196                if vt.1.is_int() {
197                    return Ok(ctx.builder.ins().fcvt_from_sint(types::F64, vt.0));
198                } else if vt.1.is_uint() {
199                    return Ok(ctx.builder.ins().fcvt_from_uint(types::F64, vt.0));
200                } else if vt.1.is_f32() {
201                    return Ok(ctx.builder.ins().fpromote(types::F64, vt.0));
202                } else if vt.1.is_str() {
203                    return self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v);
204                }
205            } else if let Type::Symbol { id: _, params: _ } = ty {
206                log::debug!("convert {:?} -> {:?}", vt, ty);
207                return Ok(vt.0); //结构类型 可以看作 External 类型
208            }
209            if vt.1.is_bool() {
210                let v = ctx.builder.ins().sextend(types::I64, vt.0);
211                return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
212            }
213            log::error!("未实现 {:?} {:?}", vt, ty); //暂时还没有实现 struct 的 初始化
214            Ok(vt.0)
215        } else {
216            Ok(vt.0)
217        }
218    }
219
220    /// 整数除法 / 取余的运行期守卫。
221    ///
222    /// Cranelift 的 `sdiv/udiv/srem/urem` 在除数为 0(有符号还有 `INT_MIN/-1`)时
223    /// 发出硬件 trap,会直接杀掉进程且无法被 `catch_unwind` 捕获。这里在除法前
224    /// 分支:除数非法时调用 `__vm_arith_fault` 记录运行期错误并返回 0,合法时才
225    /// 进入真正的除法块(此时除数可证非 0,trap 永不触发)。
226    fn guarded_idiv(&mut self, ctx: &mut BuildContext, left: Value, right: Value, signed: bool, is_rem: bool) -> Result<Value> {
227        use cranelift::codegen::ir::BlockArg;
228        let int_ty = ctx.builder.func.dfg.value_type(left);
229        let is_zero = ctx.builder.ins().icmp_imm(IntCC::Equal, right, 0);
230        let is_bad = if signed {
231            let min = match int_ty.bits() {
232                8 => i8::MIN as i64,
233                16 => i16::MIN as i64,
234                32 => i32::MIN as i64,
235                _ => i64::MIN,
236            };
237            let is_min = ctx.builder.ins().icmp_imm(IntCC::Equal, left, min);
238            let is_neg_one = ctx.builder.ins().icmp_imm(IntCC::Equal, right, -1);
239            let is_overflow = ctx.builder.ins().band(is_min, is_neg_one);
240            ctx.builder.ins().bor(is_zero, is_overflow)
241        } else {
242            is_zero
243        };
244
245        let ok_block = ctx.builder.create_block();
246        let bad_block = ctx.builder.create_block();
247        let merge_block = ctx.builder.create_block();
248        ctx.builder.append_block_param(merge_block, int_ty);
249        ctx.builder.ins().brif(is_bad, bad_block, &[], ok_block, &[]);
250
251        ctx.builder.switch_to_block(ok_block);
252        let raw = match (signed, is_rem) {
253            (true, false) => ctx.builder.ins().sdiv(left, right),
254            (false, false) => ctx.builder.ins().udiv(left, right),
255            (true, true) => ctx.builder.ins().srem(left, right),
256            (false, true) => ctx.builder.ins().urem(left, right),
257        };
258        ctx.builder.ins().jump(merge_block, &[BlockArg::Value(raw)]);
259        ctx.builder.seal_block(ok_block);
260
261        ctx.builder.switch_to_block(bad_block);
262        let fault_fn = self.arith_fault_fn.ok_or_else(|| anyhow!("VM arith fault runtime is not registered"))?;
263        let fault_ref = self.get_fn_ref(ctx, fault_fn);
264        ctx.builder.ins().call(fault_ref, &[]);
265        let zero = ctx.builder.ins().iconst(int_ty, 0);
266        ctx.builder.ins().jump(merge_block, &[BlockArg::Value(zero)]);
267        ctx.builder.seal_block(bad_block);
268
269        ctx.builder.switch_to_block(merge_block);
270        ctx.builder.seal_block(merge_block);
271        Ok(ctx.builder.block_params(merge_block)[0])
272    }
273
274    /// 立即数除法/取余:除数在编译期已知,据此选最省的代码:
275    /// - 非零常量(无符号任意非零;有符号且非 -1):不可能 trap,直接 `*_imm`,无守卫;
276    /// - 除数为 0:编译期已知会出错,记 fault 并返回 0,不发 trap;
277    /// - 有符号 `/ -1` 或 `% -1`:可能 `INT_MIN/-1` 溢出 trap,回退到运行期守卫。
278    ///
279    /// 这避免了对 `x / 2`、`x % 1000000007` 这类常量除法附加无谓的判零分支
280    /// (除零守卫只在真正可能 trap 时才生成)。
281    fn idiv_imm(&mut self, ctx: &mut BuildContext, left: Value, divisor: i64, signed: bool, is_rem: bool) -> Result<Value> {
282        let int_ty = ctx.builder.func.dfg.value_type(left);
283        if divisor == 0 {
284            let fault_fn = self.arith_fault_fn.ok_or_else(|| anyhow!("VM arith fault runtime is not registered"))?;
285            let fault_ref = self.get_fn_ref(ctx, fault_fn);
286            ctx.builder.ins().call(fault_ref, &[]);
287            return Ok(ctx.builder.ins().iconst(int_ty, 0));
288        }
289        if signed && divisor == -1 {
290            let rv = ctx.builder.ins().iconst(int_ty, -1);
291            return self.guarded_idiv(ctx, left, rv, true, is_rem);
292        }
293        Ok(match (signed, is_rem) {
294            (true, false) => ctx.builder.ins().sdiv_imm(left, divisor),
295            (false, false) => ctx.builder.ins().udiv_imm(left, divisor),
296            (true, true) => ctx.builder.ins().srem_imm(left, divisor),
297            (false, true) => ctx.builder.ins().urem_imm(left, divisor),
298        })
299    }
300
301    pub(crate) fn binary_with_expected(&mut self, ctx: &mut BuildContext, left: (Value, Type), op: BinaryOp, right: &Expr, expected: Option<&Type>) -> Result<(Value, Type)> {
302        //处理可以计算的简单情形
303        if matches!(op, BinaryOp::And | BinaryOp::Or) {
304            return self.short_circuit_logic(ctx, left, op, right);
305        }
306        let right_ty_hint = if right.is_value() { right.clone().value().ok().map(|v| v.get_type()) } else { self.get_dynamic(right).map(|v| v.get_type()) };
307        let right = if right.is_value() {
308            let right = right.clone().value()?;
309            if right.is_f32() {
310                (ctx.builder.ins().f32const(right.as_float().unwrap() as f32), Type::F32)
311            } else if right.is_f64() {
312                (ctx.builder.ins().f64const(right.as_float().unwrap() as f64), Type::F64)
313            } else if left.1.is_any() {
314                if right.is_int() {
315                    (ctx.builder.ins().iconst(types::I64, right.as_int().unwrap()), Type::I64)
316                } else if right.is_null() {
317                    self.call(ctx, self.get_method(&Type::Any, "null")?, vec![])?
318                } else {
319                    ctx.get_const(&right)?
320                }
321            } else {
322                return self.binary_imm(ctx, left, op, right);
323            }
324        } else {
325            self.eval(ctx, right)?.get(ctx).ok_or_else(|| anyhow!("没有返回值: {:?}", right))?
326        };
327        let right_ty = right_ty_hint.as_ref().unwrap_or(&right.1);
328        let numeric_expected = expected.filter(|ty| (ty.is_int() || ty.is_uint() || ty.is_float()) && (left.1.is_any() || right.1.is_any()));
329        let ty = if (op.is_add() || op.is_logic()) && (left.1.is_str() || right.1.is_str() || right_ty.is_str()) {
330            Type::Str
331        } else if !op.is_logic()
332            && let Some(expected) = numeric_expected
333        {
334            expected.clone()
335        } else if (op.is_add() || op.is_logic()) && (left.1.is_any() || right.1.is_any()) {
336            Type::Any
337        } else {
338            left.1.clone() + right.1.clone()
339        }; //为了支持字符串的加法需要单独处理
340        if ty.is_str() && op.is_add() {
341            if op == BinaryOp::AddAssign {
342                let left = self.convert(ctx, left, Type::Any)?;
343                let right = self.convert(ctx, right, Type::Any)?;
344                return Ok((self.strcat_assign(ctx, left, right)?, ty));
345            }
346            if left.1.is_str() && right.1.is_str() {
347                return Ok((self.strcat(ctx, left.0, right.0)?, Type::Str));
348            }
349            if left.1.is_str() && right.1.is_int() {
350                let right = self.convert(ctx, right, Type::I64)?;
351                return Ok((self.strcat_i64(ctx, left.0, right)?, Type::Str));
352            }
353            let left = self.convert(ctx, left, Type::Any)?;
354            let right = self.convert(ctx, right, Type::Any)?;
355            let result = self.any_binary(ctx, left, op, right)?.0;
356            return Ok((result, ty));
357        }
358        let left = self.convert(ctx, left, ty.clone())?;
359        let right = self.convert(ctx, right, ty.clone())?;
360        if ty.is_any() {
361            if op.is_logic() {
362                return self.any_logic(ctx, left, op, right);
363            } else {
364                return self.any_binary(ctx, left, op, right);
365            }
366        }
367        if ty.is_str() && op.is_logic() {
368            return self.any_logic(ctx, left, op, right);
369        }
370        match op {
371            BinaryOp::Add | BinaryOp::AddAssign => {
372                if ty.is_int() || ty.is_uint() {
373                    return Ok((ctx.builder.ins().iadd(left, right), ty));
374                } else if ty.is_float() {
375                    return Ok((ctx.builder.ins().fadd(left, right), ty));
376                } else if ty.is_str() {
377                    let result = self.any_binary(ctx, left, op, right)?.0;
378                    return Ok((result, ty));
379                }
380            }
381            BinaryOp::Sub | BinaryOp::SubAssign => {
382                if ty.is_int() || ty.is_uint() {
383                    return Ok((ctx.builder.ins().isub(left, right), ty));
384                } else if ty.is_float() {
385                    return Ok((ctx.builder.ins().fsub(left, right), ty));
386                }
387            }
388            BinaryOp::Mul | BinaryOp::MulAssign => {
389                if ty.is_int() || ty.is_uint() {
390                    return Ok((ctx.builder.ins().imul(left, right), ty));
391                } else if ty.is_float() {
392                    return Ok((ctx.builder.ins().fmul(left, right), ty));
393                }
394            }
395            BinaryOp::Div | BinaryOp::DivAssign => {
396                if ty.is_int() {
397                    return Ok((self.guarded_idiv(ctx, left, right, true, false)?, ty));
398                } else if ty.is_uint() {
399                    return Ok((self.guarded_idiv(ctx, left, right, false, false)?, ty));
400                } else if ty.is_float() {
401                    return Ok((ctx.builder.ins().fdiv(left, right), ty));
402                }
403            }
404            BinaryOp::Mod | BinaryOp::ModAssign => {
405                if ty.is_int() {
406                    return Ok((self.guarded_idiv(ctx, left, right, true, true)?, ty));
407                } else if ty.is_uint() {
408                    return Ok((self.guarded_idiv(ctx, left, right, false, true)?, ty));
409                }
410            }
411            BinaryOp::Shl | BinaryOp::ShlAssign => {
412                if ty.is_int() || ty.is_uint() {
413                    return Ok((ctx.builder.ins().ishl(left, right), ty));
414                }
415            }
416            BinaryOp::Shr | BinaryOp::ShrAssign => {
417                if ty.is_int() {
418                    return Ok((ctx.builder.ins().sshr(left, right), ty));
419                } else if ty.is_uint() {
420                    return Ok((ctx.builder.ins().ushr(left, right), ty));
421                }
422            }
423            BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
424                return Ok((ctx.builder.ins().band(left, right), ty));
425            }
426            BinaryOp::BitOr | BinaryOp::BitOrAssign => {
427                return Ok((ctx.builder.ins().bor(left, right), ty));
428            }
429            BinaryOp::BitXor | BinaryOp::BitXorAssign => {
430                return Ok((ctx.builder.ins().bxor(left, right), ty));
431            }
432            BinaryOp::Eq => {
433                if ty.is_int() | ty.is_uint() || ty.is_bool() {
434                    return Ok((ctx.builder.ins().icmp(IntCC::Equal, left, right), Type::Bool));
435                } else if ty.is_float() {
436                    return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right), Type::Bool));
437                }
438            }
439            BinaryOp::Ne => {
440                if ty.is_int() | ty.is_uint() || ty.is_bool() {
441                    return Ok((ctx.builder.ins().icmp(IntCC::NotEqual, left, right), Type::Bool));
442                } else if ty.is_float() {
443                    return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right), Type::Bool));
444                }
445            }
446            BinaryOp::Lt => {
447                if ty.is_int() {
448                    return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThan, left, right), Type::Bool));
449                } else if ty.is_uint() {
450                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThan, left, right), Type::Bool));
451                } else if ty.is_float() {
452                    return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right), Type::Bool));
453                }
454            }
455            BinaryOp::Le => {
456                if ty.is_int() {
457                    return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThanOrEqual, left, right), Type::Bool));
458                } else if ty.is_uint() {
459                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThanOrEqual, left, right), Type::Bool));
460                } else if ty.is_float() {
461                    return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right), Type::Bool));
462                }
463            }
464            BinaryOp::Gt => {
465                if ty.is_int() {
466                    return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThan, left, right), Type::Bool));
467                } else if ty.is_uint() {
468                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThan, left, right), Type::Bool));
469                } else if ty.is_float() {
470                    return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right), Type::Bool));
471                }
472            }
473            BinaryOp::Ge => {
474                if ty.is_int() {
475                    return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThanOrEqual, left, right), Type::Bool));
476                } else if ty.is_uint() {
477                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThanOrEqual, left, right), Type::Bool));
478                } else if ty.is_float() {
479                    return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right), Type::Bool));
480                }
481            }
482            _ => {}
483        }
484        // 回退到动态分发,避免因未知类型组合导致进程崩溃
485        log::debug!("binary_with_expected fallback to dynamic: {:?} {:?} {:?}", ty, op, right);
486        let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
487        let right_any = self.convert(ctx, (right, ty.clone()), Type::Any)?;
488        if op.is_logic() { self.any_logic(ctx, left_any, op, right_any) } else { self.any_binary(ctx, left_any, op, right_any) }
489    }
490
491    pub(crate) fn binary_imm<'a>(&mut self, ctx: &'a mut BuildContext, left: (Value, Type), op: BinaryOp, right: Dynamic) -> Result<(Value, Type)> {
492        let ty = left.1.clone() + right.get_type();
493        let bool_imm = || right.as_bool().map(|value| if value { 1 } else { 0 });
494        if ty.is_str() && op.is_add() {
495            if op == BinaryOp::AddAssign {
496                let left = self.convert(ctx, left, Type::Any)?;
497                let right_vt = ctx.get_const(&right).or_else(|_| {
498                    let idx = self.compiler.get_const(right.clone());
499                    self.get_const_value(ctx, idx)
500                })?;
501                let right = self.convert(ctx, right_vt, Type::Any)?;
502                return Ok((self.strcat_assign(ctx, left, right)?, ty));
503            }
504            if left.1.is_str() && right.is_str() {
505                let right_vt = ctx.get_const(&right).or_else(|_| {
506                    let idx = self.compiler.get_const(right.clone());
507                    self.get_const_value(ctx, idx)
508                })?;
509                let right = self.convert(ctx, right_vt, Type::Str)?;
510                return Ok((self.strcat(ctx, left.0, right)?, Type::Str));
511            }
512            if left.1.is_str() && right.is_int() {
513                let right = ctx.get_const(&right)?;
514                let right = self.convert(ctx, right, Type::I64)?;
515                return Ok((self.strcat_i64(ctx, left.0, right)?, Type::Str));
516            }
517            let left = self.convert(ctx, left, Type::Any)?;
518            let right_vt = ctx.get_const(&right).or_else(|_| {
519                let idx = self.compiler.get_const(right.clone());
520                self.get_const_value(ctx, idx)
521            })?;
522            let right = self.convert(ctx, right_vt, Type::Any)?;
523            let result = self.any_binary(ctx, left, op, right)?.0;
524            return Ok((result, ty));
525        }
526        let left = self.convert(ctx, left, ty.clone())?;
527        if ty.is_str() && op.is_logic() {
528            let right_vt = ctx.get_const(&right).or_else(|_| {
529                let idx = self.compiler.get_const(right.clone());
530                self.get_const_value(ctx, idx)
531            })?;
532            let right = self.convert(ctx, right_vt, Type::Str)?;
533            return self.any_logic(ctx, left, op, right);
534        }
535        let right_float = if ty.is_float() {
536            let right = right.as_float().ok_or(anyhow!("非数字"))?;
537            Some(if ty.is_f32() { ctx.builder.ins().f32const(right as f32) } else { ctx.builder.ins().f64const(right) })
538        } else {
539            None
540        };
541        match op {
542            BinaryOp::Add | BinaryOp::AddAssign => {
543                if ty.is_str() {
544                    let right_vt = ctx.get_const(&right).or_else(|_| {
545                        let idx = self.compiler.get_const(right.clone());
546                        self.get_const_value(ctx, idx)
547                    })?;
548                    let right = self.convert(ctx, right_vt, Type::Str)?;
549                    let result = self.any_binary(ctx, left, op, right)?.0;
550                    return Ok((result, ty));
551                }
552                if ty.is_int() | ty.is_uint() {
553                    return Ok((ctx.builder.ins().iadd_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
554                } else if ty.is_float() {
555                    return Ok((ctx.builder.ins().fadd(left, right_float.unwrap()), ty));
556                }
557            }
558            BinaryOp::Sub | BinaryOp::SubAssign => {
559                if ty.is_int() | ty.is_uint() {
560                    return Ok((ctx.builder.ins().iadd_imm(left, -right.as_int().ok_or(anyhow!("非整数"))?), ty));
561                } else if ty.is_float() {
562                    return Ok((ctx.builder.ins().fsub(left, right_float.unwrap()), ty));
563                }
564            }
565            BinaryOp::Mul | BinaryOp::MulAssign => {
566                if ty.is_int() | ty.is_uint() {
567                    return Ok((ctx.builder.ins().imul_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
568                } else if ty.is_float() {
569                    return Ok((ctx.builder.ins().fmul(left, right_float.unwrap()), ty));
570                }
571            }
572            BinaryOp::Div | BinaryOp::DivAssign => {
573                if ty.is_int() || ty.is_uint() {
574                    let divisor = right.as_int().ok_or(anyhow!("非整数"))?;
575                    return Ok((self.idiv_imm(ctx, left, divisor, ty.is_int(), false)?, ty));
576                } else if ty.is_float() {
577                    return Ok((ctx.builder.ins().fdiv(left, right_float.unwrap()), ty));
578                }
579            }
580            BinaryOp::Shl | BinaryOp::ShlAssign => {
581                if ty.is_int() || ty.is_uint() {
582                    return Ok((ctx.builder.ins().ishl_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
583                }
584            }
585            BinaryOp::Shr | BinaryOp::ShrAssign => {
586                if ty.is_int() {
587                    return Ok((ctx.builder.ins().sshr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
588                } else if ty.is_uint() {
589                    return Ok((ctx.builder.ins().ushr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
590                }
591            }
592            BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
593                return Ok((ctx.builder.ins().band_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
594            }
595            BinaryOp::BitOr | BinaryOp::BitOrAssign => {
596                return Ok((ctx.builder.ins().bor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
597            }
598            BinaryOp::BitXor | BinaryOp::BitXorAssign => {
599                return Ok((ctx.builder.ins().bxor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
600            }
601            BinaryOp::Eq => {
602                if ty.is_int() | ty.is_uint() {
603                    return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, right.as_int().unwrap()), Type::Bool));
604                } else if ty.is_bool() {
605                    return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, bool_imm().unwrap()), Type::Bool));
606                } else if ty.is_float() {
607                    return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right_float.unwrap()), Type::Bool));
608                }
609            }
610            BinaryOp::Ne => {
611                if ty.is_int() | ty.is_uint() {
612                    return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, right.as_int().unwrap()), Type::Bool));
613                } else if ty.is_bool() {
614                    return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, bool_imm().unwrap()), Type::Bool));
615                } else if ty.is_float() {
616                    return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right_float.unwrap()), Type::Bool));
617                }
618            }
619            BinaryOp::Le => {
620                if ty.is_int() {
621                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
622                } else if ty.is_uint() {
623                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
624                } else if ty.is_float() {
625                    return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right_float.unwrap()), Type::Bool));
626                }
627            }
628            BinaryOp::Lt => {
629                if ty.is_int() {
630                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThan, left, right.as_int().unwrap()), Type::Bool));
631                } else if ty.is_uint() {
632                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThan, left, right.as_int().unwrap()), Type::Bool));
633                } else if ty.is_float() {
634                    return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right_float.unwrap()), Type::Bool));
635                }
636            }
637            BinaryOp::Ge => {
638                if ty.is_int() {
639                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
640                } else if ty.is_uint() {
641                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
642                } else if ty.is_float() {
643                    return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right_float.unwrap()), Type::Bool));
644                }
645            }
646            BinaryOp::Gt => {
647                if ty.is_int() {
648                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
649                } else if ty.is_uint() {
650                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
651                } else if ty.is_float() {
652                    return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right_float.unwrap()), Type::Bool));
653                }
654            }
655            BinaryOp::Mod | BinaryOp::ModAssign => {
656                if ty.is_int() || ty.is_uint() {
657                    let divisor = right.as_int().ok_or(anyhow!("非整数"))?;
658                    return Ok((self.idiv_imm(ctx, left, divisor, ty.is_int(), true)?, ty));
659                }
660            }
661            exp => {
662                // 回退到动态分发,避免因未知操作导致进程崩溃
663                log::debug!("binary_imm fallback to dynamic (unsupported op): {:?} {:?}", ty, exp);
664                let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
665                let right_vt = ctx.get_const(&right).or_else(|_| {
666                    let idx = self.compiler.get_const(right.clone());
667                    self.get_const_value(ctx, idx)
668                })?;
669                let right_any = self.convert(ctx, right_vt, Type::Any)?;
670                if exp.is_logic() {
671                    return self.any_logic(ctx, left_any, exp, right_any);
672                }
673                return self.any_binary(ctx, left_any, exp, right_any);
674            }
675        }
676        // 回退到动态分发,避免因未知类型组合导致进程崩溃
677        log::debug!("binary_imm fallback to dynamic (unsupported type combo): {:?} {:?} {:?}", ty, op, right.get_type());
678        let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
679        let right_vt = ctx.get_const(&right).or_else(|_| {
680            let idx = self.compiler.get_const(right.clone());
681            self.get_const_value(ctx, idx)
682        })?;
683        let right_any = self.convert(ctx, right_vt, Type::Any)?;
684        if op.is_logic() { self.any_logic(ctx, left_any, op, right_any) } else { self.any_binary(ctx, left_any, op, right_any) }
685    }
686}