better type assertion ergonomic
This commit is contained in:
@@ -2,7 +2,8 @@ use std::cmp::Ordering;
|
||||
|
||||
use gc_arena::{Gc, Mutation};
|
||||
|
||||
use crate::{BytecodeReader, NixNum, StepResult, StrictValue, Value, VmContextExt, VmError};
|
||||
use crate::{BytecodeReader, NixNum, Step, VmContextExt, VmError};
|
||||
use crate::value::*;
|
||||
|
||||
impl<'gc> crate::Vm<'gc> {
|
||||
#[inline(always)]
|
||||
@@ -11,28 +12,28 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
if let Some(step) = self.try_force(0, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
let rhs = self.pop_forced();
|
||||
let lhs = self.pop_forced();
|
||||
if let (Some(ls), Some(rs)) = (
|
||||
VmContextExt::get_string(ctx, lhs),
|
||||
VmContextExt::get_string(ctx, rhs),
|
||||
) {
|
||||
let ns = Gc::new(mc, crate::NixString::new(format!("{ls}{rs}")));
|
||||
self.push_stack(Value::new_gc(ns));
|
||||
return StepResult::Continue;
|
||||
self.push(Value::new_gc(ns));
|
||||
return Step::Continue;
|
||||
}
|
||||
let res = numeric_binop(lhs, rhs, mc, i64::wrapping_add, |a, b| a + b);
|
||||
match res {
|
||||
Ok(val) => {
|
||||
self.push_stack(val);
|
||||
StepResult::Continue
|
||||
self.push(val);
|
||||
Step::Continue
|
||||
}
|
||||
Err(e) => self.finish_vm_err(e),
|
||||
}
|
||||
@@ -43,7 +44,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
self.op_arith(reader, mc, i64::wrapping_sub, |a, b| a - b)
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
self.op_arith(reader, mc, i64::wrapping_mul, |a, b| a * b)
|
||||
}
|
||||
|
||||
@@ -63,20 +64,20 @@ impl<'gc> crate::Vm<'gc> {
|
||||
mc: &Mutation<'gc>,
|
||||
int_op: fn(i64, i64) -> i64,
|
||||
float_op: fn(f64, f64) -> f64,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
if let Some(step) = self.try_force(0, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
let rhs = self.pop_forced();
|
||||
let lhs = self.pop_forced();
|
||||
let res = numeric_binop(lhs, rhs, mc, int_op, float_op);
|
||||
match res {
|
||||
Ok(val) => {
|
||||
self.push_stack(val);
|
||||
StepResult::Continue
|
||||
self.push(val);
|
||||
Step::Continue
|
||||
}
|
||||
Err(e) => self.finish_vm_err(e),
|
||||
}
|
||||
@@ -87,15 +88,15 @@ impl<'gc> crate::Vm<'gc> {
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
if let Some(step) = self.try_force(0, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
let rhs = self.pop_forced();
|
||||
let lhs = self.pop_forced();
|
||||
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(
|
||||
@@ -107,8 +108,8 @@ impl<'gc> crate::Vm<'gc> {
|
||||
let res = numeric_binop(lhs, rhs, mc, |a, b| a / b, |a, b| a / b);
|
||||
match res {
|
||||
Ok(val) => {
|
||||
self.push_stack(val);
|
||||
StepResult::Continue
|
||||
self.push(val);
|
||||
Step::Continue
|
||||
}
|
||||
Err(e) => self.finish_vm_err(e),
|
||||
}
|
||||
@@ -120,7 +121,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
@@ -131,8 +132,8 @@ impl<'gc> crate::Vm<'gc> {
|
||||
Ok(eq) => eq,
|
||||
Err(e) => return self.finish_vm_err(e),
|
||||
};
|
||||
self.push_stack(Value::new_inline(eq));
|
||||
StepResult::Continue
|
||||
self.push(Value::new_inline(eq));
|
||||
Step::Continue
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -141,7 +142,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
@@ -152,8 +153,8 @@ impl<'gc> crate::Vm<'gc> {
|
||||
Ok(eq) => eq,
|
||||
Err(e) => return self.finish_vm_err(e),
|
||||
};
|
||||
self.push_stack(Value::new_inline(!eq));
|
||||
StepResult::Continue
|
||||
self.push(Value::new_inline(!eq));
|
||||
Step::Continue
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -162,7 +163,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
self.compare_values(ctx, reader, mc, Ordering::is_lt)
|
||||
}
|
||||
|
||||
@@ -172,7 +173,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
self.compare_values(ctx, reader, mc, Ordering::is_gt)
|
||||
}
|
||||
|
||||
@@ -182,7 +183,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
self.compare_values(ctx, reader, mc, Ordering::is_le)
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &mut impl crate::VmContext,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
self.compare_values(ctx, reader, mc, Ordering::is_ge)
|
||||
}
|
||||
|
||||
@@ -202,7 +203,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
pred: fn(Ordering) -> bool,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
@@ -210,7 +211,7 @@ impl<'gc> crate::Vm<'gc> {
|
||||
return step;
|
||||
}
|
||||
match self.compare_values_inner(ctx, pred) {
|
||||
Ok(()) => StepResult::Continue,
|
||||
Ok(()) => Step::Continue,
|
||||
Err(e) => self.finish_vm_err(e),
|
||||
}
|
||||
}
|
||||
@@ -220,30 +221,26 @@ impl<'gc> crate::Vm<'gc> {
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
if let Some(step) = self.try_force(0, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
let Some(l) = lhs.as_gc::<crate::List>() else {
|
||||
return self.finish_err(fix_error::Error::eval_error(
|
||||
"cannot concatenate: left operand is not a list",
|
||||
));
|
||||
let r = match self.pop_forced_expect_gc::<List>() {
|
||||
Ok(val) => val,
|
||||
Err(got) => return self.finish_type_err(NixType::List, got)
|
||||
};
|
||||
let Some(r) = rhs.as_gc::<crate::List>() else {
|
||||
return self.finish_err(fix_error::Error::eval_error(
|
||||
"cannot concatenate: right operand is not a list",
|
||||
));
|
||||
let l = match self.pop_forced_expect_gc::<List>() {
|
||||
Ok(val) => val,
|
||||
Err(got) => return self.finish_type_err(NixType::List, got)
|
||||
};
|
||||
let mut items = smallvec::SmallVec::new();
|
||||
items.extend_from_slice(&l);
|
||||
items.extend_from_slice(&r);
|
||||
self.push_stack(Value::new_gc(Gc::new(mc, crate::List { inner: items })));
|
||||
StepResult::Continue
|
||||
self.push(Value::new_gc(Gc::new(mc, crate::List { inner: items })));
|
||||
Step::Continue
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -251,42 +248,38 @@ impl<'gc> crate::Vm<'gc> {
|
||||
&mut self,
|
||||
reader: &mut BytecodeReader<'_>,
|
||||
mc: &Mutation<'gc>,
|
||||
) -> StepResult {
|
||||
) -> Step {
|
||||
if let Some(step) = self.try_force(1, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
if let Some(step) = self.try_force(0, reader, mc) {
|
||||
return step;
|
||||
}
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
let Some(l) = lhs.as_gc::<crate::AttrSet>() else {
|
||||
return self.finish_err(fix_error::Error::eval_error(
|
||||
"cannot update: left operand is not a set",
|
||||
));
|
||||
let r = match self.pop_forced_expect_gc::<AttrSet>() {
|
||||
Ok(val) => val,
|
||||
Err(got) => return self.finish_type_err(NixType::AttrSet, got)
|
||||
};
|
||||
let Some(r) = rhs.as_gc::<crate::AttrSet>() else {
|
||||
return self.finish_err(fix_error::Error::eval_error(
|
||||
"cannot update: right operand is not a set",
|
||||
));
|
||||
let l = match self.pop_forced_expect_gc::<AttrSet>() {
|
||||
Ok(val) => val,
|
||||
Err(got) => return self.finish_type_err(NixType::AttrSet, got)
|
||||
};
|
||||
self.push_stack(Value::new_gc(l.merge(&r, mc)));
|
||||
StepResult::Continue
|
||||
self.push(Value::new_gc(l.merge(&r, mc)));
|
||||
Step::Continue
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_neg(&mut self) -> StepResult {
|
||||
pub(crate) fn op_neg(&mut self) -> Step {
|
||||
todo!("implement unary operation");
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn op_not(&mut self) -> StepResult {
|
||||
pub(crate) fn op_not(&mut self) -> Step {
|
||||
todo!("implement unary operation");
|
||||
}
|
||||
|
||||
pub(crate) fn values_equal(&mut self, ctx: &impl crate::VmContext) -> crate::VmResult<bool> {
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
let rhs = self.pop_forced();
|
||||
let lhs = self.pop_forced();
|
||||
|
||||
if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) {
|
||||
return Ok(match (a, b) {
|
||||
@@ -314,8 +307,8 @@ impl<'gc> crate::Vm<'gc> {
|
||||
}
|
||||
let len = a.inner.len();
|
||||
for (x, y) in a.inner.iter().zip(b.inner.iter()).rev() {
|
||||
self.push_stack(*x);
|
||||
self.push_stack(*y);
|
||||
self.push(*x);
|
||||
self.push(*y);
|
||||
}
|
||||
for i in 0..len {
|
||||
let eq = self.values_equal(ctx)?;
|
||||
@@ -336,8 +329,8 @@ impl<'gc> crate::Vm<'gc> {
|
||||
if k1 != k2 {
|
||||
return Ok(false);
|
||||
}
|
||||
self.push_stack(*v1);
|
||||
self.push_stack(*v2);
|
||||
self.push(*v1);
|
||||
self.push(*v2);
|
||||
}
|
||||
for i in 0..len {
|
||||
let eq = self.values_equal(ctx)?;
|
||||
@@ -357,8 +350,8 @@ impl<'gc> crate::Vm<'gc> {
|
||||
ctx: &impl crate::VmContext,
|
||||
pred: fn(Ordering) -> bool,
|
||||
) -> crate::VmResult<()> {
|
||||
let rhs = self.pop_stack_forced();
|
||||
let lhs = self.pop_stack_forced();
|
||||
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) {
|
||||
@@ -371,16 +364,17 @@ impl<'gc> crate::Vm<'gc> {
|
||||
a.partial_cmp(&(b as f64)).unwrap_or(Ordering::Less)
|
||||
}
|
||||
};
|
||||
self.push_stack(Value::new_inline(pred(ord)));
|
||||
self.push(Value::new_inline(pred(ord)));
|
||||
return Ok(());
|
||||
}
|
||||
if let (Some(a), Some(b)) = (
|
||||
VmContextExt::get_string(ctx, lhs),
|
||||
VmContextExt::get_string(ctx, rhs),
|
||||
) {
|
||||
self.push_stack(Value::new_inline(pred(a.cmp(b))));
|
||||
self.push(Value::new_inline(pred(a.cmp(b))));
|
||||
return Ok(());
|
||||
}
|
||||
// TODO: compare other types
|
||||
Err(crate::vm_err("cannot compare these types"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user