better force eval ergonomic

This commit is contained in:
2026-04-21 22:05:49 +08:00
parent b31c2a4906
commit e469d1b819
7 changed files with 303 additions and 123 deletions
+28 -69
View File
@@ -2,8 +2,8 @@ use std::cmp::Ordering;
use gc_arena::{Gc, Mutation};
use crate::{BytecodeReader, NixNum, Step, VmContextExt, VmError};
use crate::value::*;
use crate::{BytecodeReader, NixNum, Step, VmContextExt, VmError};
impl<'gc> crate::Vm<'gc> {
#[inline(always)]
@@ -13,10 +13,7 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let rhs = self.pop_forced();
let lhs = self.pop_forced();
let (lhs, rhs) = self.try_force::<(StrictValue, StrictValue)>(reader, mc)?;
if let (Some(ls), Some(rs)) = (
VmContextExt::get_string(ctx, lhs),
VmContextExt::get_string(ctx, rhs),
@@ -61,10 +58,7 @@ impl<'gc> crate::Vm<'gc> {
int_op: fn(i64, i64) -> i64,
float_op: fn(f64, f64) -> f64,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let rhs = self.pop_forced();
let lhs = self.pop_forced();
let (lhs, rhs) = self.try_force::<(StrictValue, StrictValue)>(reader, mc)?;
let res = numeric_binop(lhs, rhs, mc, int_op, float_op);
match res {
Ok(val) => {
@@ -81,10 +75,7 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let rhs = self.pop_forced();
let lhs = self.pop_forced();
let (lhs, rhs) = self.try_force::<(StrictValue, StrictValue)>(reader, mc)?;
match (get_num(rhs), get_num(lhs)) {
(_, Some(NixNum::Int(0))) | (_, Some(NixNum::Float(0.))) => {
return self.finish_vm_err(VmError::Uncatchable(fix_error::Error::eval_error(
@@ -110,9 +101,8 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let eq = match self.values_equal(ctx) {
let (lhs, rhs) = self.try_force::<(StrictValue, StrictValue)>(reader, mc)?;
let eq = match self.values_equal(ctx, lhs, rhs) {
Ok(eq) => eq,
Err(e) => return self.finish_vm_err(e),
};
@@ -127,9 +117,8 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let eq = match self.values_equal(ctx) {
let (lhs, rhs) = self.try_force::<(StrictValue, StrictValue)>(reader, mc)?;
let eq = match self.values_equal(ctx, lhs, rhs) {
Ok(eq) => eq,
Err(e) => return self.finish_vm_err(e),
};
@@ -184,9 +173,8 @@ impl<'gc> crate::Vm<'gc> {
mc: &Mutation<'gc>,
pred: fn(Ordering) -> bool,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
match self.compare_values_inner(ctx, pred) {
let (lhs, rhs) = self.try_force::<(StrictValue, StrictValue)>(reader, mc)?;
match self.compare_values_inner(ctx, pred, lhs, rhs) {
Ok(()) => Step::Continue(()),
Err(e) => self.finish_vm_err(e),
}
@@ -198,16 +186,7 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let r = match self.pop_forced_expect_gc::<List>() {
Ok(val) => val,
Err(got) => return self.finish_type_err(NixType::List, got)
};
let l = match self.pop_forced_expect_gc::<List>() {
Ok(val) => val,
Err(got) => return self.finish_type_err(NixType::List, got)
};
let (l, r) = self.try_force::<(Gc<List>, Gc<List>)>(reader, mc)?;
let mut items = smallvec::SmallVec::new();
items.extend_from_slice(&l);
items.extend_from_slice(&r);
@@ -221,16 +200,7 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.try_force(1, reader, mc)?;
self.try_force(0, reader, mc)?;
let r = match self.pop_forced_expect_gc::<AttrSet>() {
Ok(val) => val,
Err(got) => return self.finish_type_err(NixType::AttrSet, got)
};
let l = match self.pop_forced_expect_gc::<AttrSet>() {
Ok(val) => val,
Err(got) => return self.finish_type_err(NixType::AttrSet, got)
};
let (l, r) = self.try_force::<(Gc<AttrSet>, Gc<AttrSet>)>(reader, mc)?;
self.push(Value::new_gc(l.merge(&r, mc)));
Step::Continue(())
}
@@ -245,10 +215,12 @@ impl<'gc> crate::Vm<'gc> {
todo!("implement unary operation");
}
pub(crate) fn values_equal(&mut self, ctx: &impl crate::VmContext) -> crate::VmResult<bool> {
let rhs = self.pop_forced();
let lhs = self.pop_forced();
pub(crate) fn values_equal(
&mut self,
ctx: &impl crate::VmContext,
lhs: StrictValue<'gc>,
rhs: StrictValue<'gc>,
) -> crate::VmResult<bool> {
if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) {
return Ok(match (a, b) {
(NixNum::Int(a), NixNum::Int(b)) => a == b,
@@ -273,16 +245,10 @@ impl<'gc> crate::Vm<'gc> {
if a.inner.len() != b.inner.len() {
return Ok(false);
}
let len = a.inner.len();
for (x, y) in a.inner.iter().zip(b.inner.iter()).rev() {
self.push(*x);
self.push(*y);
}
for i in 0..len {
let eq = self.values_equal(ctx)?;
if !eq {
let rem = len - 1 - i;
self.stack.truncate(self.stack.len() - rem * 2);
for (x, y) in a.inner.iter().zip(b.inner.iter()) {
let lx = x.restrict().expect("forced");
let ly = y.restrict().expect("forced");
if !self.values_equal(ctx, lx, ly)? {
return Ok(false);
}
}
@@ -292,19 +258,13 @@ impl<'gc> crate::Vm<'gc> {
if a.len() != b.len() {
return Ok(false);
}
let len = a.len();
for ((k1, v1), (k2, v2)) in a.iter().zip(b.iter()).rev() {
for ((k1, v1), (k2, v2)) in a.iter().zip(b.iter()) {
if k1 != k2 {
return Ok(false);
}
self.push(*v1);
self.push(*v2);
}
for i in 0..len {
let eq = self.values_equal(ctx)?;
if !eq {
let rem = len - 1 - i;
self.stack.truncate(self.stack.len() - rem * 2);
let lv1 = v1.restrict().expect("forced");
let lv2 = v2.restrict().expect("forced");
if !self.values_equal(ctx, lv1, lv2)? {
return Ok(false);
}
}
@@ -317,10 +277,9 @@ impl<'gc> crate::Vm<'gc> {
&mut self,
ctx: &impl crate::VmContext,
pred: fn(Ordering) -> bool,
lhs: StrictValue<'gc>,
rhs: StrictValue<'gc>,
) -> crate::VmResult<()> {
let rhs = self.pop_forced();
let lhs = self.pop_forced();
if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) {
let ord = match (a, b) {
(NixNum::Int(a), NixNum::Int(b)) => a.cmp(&b),