better type assertion ergonomic

This commit is contained in:
2026-04-20 17:57:54 +08:00
parent 581c333070
commit 11b0b8a78e
13 changed files with 399 additions and 258 deletions
+24 -8
View File
@@ -160,6 +160,22 @@ enum TagVal {
pub(crate) struct RawTag(TagVal); pub(crate) struct RawTag(TagVal);
impl RawTag { impl RawTag {
pub(crate) const P1: RawTag = RawTag(TagVal::_P1);
pub(crate) const P2: RawTag = RawTag(TagVal::_P2);
pub(crate) const P3: RawTag = RawTag(TagVal::_P3);
pub(crate) const P4: RawTag = RawTag(TagVal::_P4);
pub(crate) const P5: RawTag = RawTag(TagVal::_P5);
pub(crate) const P6: RawTag = RawTag(TagVal::_P6);
pub(crate) const P7: RawTag = RawTag(TagVal::_P7);
pub(crate) const N1: RawTag = RawTag(TagVal::_N1);
pub(crate) const N2: RawTag = RawTag(TagVal::_N2);
pub(crate) const N3: RawTag = RawTag(TagVal::_N3);
pub(crate) const N4: RawTag = RawTag(TagVal::_N4);
pub(crate) const N5: RawTag = RawTag(TagVal::_N5);
pub(crate) const N6: RawTag = RawTag(TagVal::_N6);
pub(crate) const N7: RawTag = RawTag(TagVal::_N7);
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn new(neg: bool, val: NonZeroU8) -> RawTag { pub(crate) fn new(neg: bool, val: NonZeroU8) -> RawTag {
@@ -195,7 +211,7 @@ impl RawTag {
/// `val` must be in the range `1..8` /// `val` must be in the range `1..8`
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) unsafe fn new_unchecked(neg: bool, val: u8) -> RawTag { pub(crate) const unsafe fn new_unchecked(neg: bool, val: u8) -> RawTag {
RawTag(match (neg, val) { RawTag(match (neg, val) {
(false, 1) => TagVal::_P1, (false, 1) => TagVal::_P1,
(false, 2) => TagVal::_P2, (false, 2) => TagVal::_P2,
@@ -244,7 +260,7 @@ impl RawTag {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn neg_val(self) -> (bool, u8) { pub(crate) const fn neg_val(self) -> (bool, u8) {
match self.0 { match self.0 {
TagVal::_P1 => (false, 1), TagVal::_P1 => (false, 1),
TagVal::_P2 => (false, 2), TagVal::_P2 => (false, 2),
@@ -285,17 +301,17 @@ impl Header {
} }
#[inline] #[inline]
fn tag(self) -> RawTag { const fn tag(self) -> RawTag {
unsafe { RawTag::new_unchecked(self.get_sign(), self.get_tag()) } unsafe { RawTag::new_unchecked(self.get_sign(), self.get_tag()) }
} }
#[inline] #[inline]
fn get_sign(self) -> bool { const fn get_sign(self) -> bool {
self.0 & 0x8000 != 0 self.0 & 0x8000 != 0
} }
#[inline] #[inline]
fn get_tag(self) -> u8 { const fn get_tag(self) -> u8 {
(self.0 & 0x0007) as u8 (self.0 & 0x0007) as u8
} }
@@ -341,7 +357,7 @@ impl Value {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn tag(&self) -> RawTag { pub(crate) const fn tag(&self) -> RawTag {
self.header.tag() self.header.tag()
} }
@@ -417,7 +433,7 @@ impl RawBox {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn tag(&self) -> Option<RawTag> { pub(crate) const fn tag(&self) -> Option<RawTag> {
if self.is_value() { if self.is_value() {
Some(unsafe { self.value.tag() }) Some(unsafe { self.value.tag() })
} else { } else {
@@ -433,7 +449,7 @@ impl RawBox {
#[inline] #[inline]
#[must_use] #[must_use]
pub(crate) fn is_value(&self) -> bool { pub(crate) const fn is_value(&self) -> bool {
(unsafe { self.float.is_nan() } && unsafe { self.bits & SIGN_MASK != QUIET_NAN }) (unsafe { self.float.is_nan() } && unsafe { self.bits & SIGN_MASK != QUIET_NAN })
} }
+3 -3
View File
@@ -2,7 +2,7 @@
use gc_arena::Mutation; use gc_arena::Mutation;
use crate::{BytecodeReader, StepResult, Vm, VmContext}; use crate::{BytecodeReader, Step, Vm, VmContext};
pub(crate) enum TailResult { pub(crate) enum TailResult {
YieldFuel(u32), YieldFuel(u32),
@@ -36,8 +36,8 @@ extern "rust-preserve-none" fn op_illegal<'gc, C: VmContext>(
macro_rules! tail_dispatch_after { macro_rules! tail_dispatch_after {
($result:expr, $new_pc:expr, $vm:ident, $mc:ident, $ctx:ident, $bc:ident, $table:ident, $fuel:ident) => {{ ($result:expr, $new_pc:expr, $vm:ident, $mc:ident, $ctx:ident, $bc:ident, $table:ident, $fuel:ident) => {{
match $result { match $result {
StepResult::Continue => {} Step::Continue => {}
StepResult::Done => return TailResult::Done, Step::Done => return TailResult::Done,
} }
let new_pc: u32 = $new_pc; let new_pc: u32 = $new_pc;
if $fuel == 0 { if $fuel == 0 {
+64 -70
View File
@@ -2,7 +2,8 @@ use std::cmp::Ordering;
use gc_arena::{Gc, Mutation}; 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> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
@@ -11,28 +12,28 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let rhs = self.pop_stack_forced(); let rhs = self.pop_forced();
let lhs = self.pop_stack_forced(); let lhs = self.pop_forced();
if let (Some(ls), Some(rs)) = ( if let (Some(ls), Some(rs)) = (
VmContextExt::get_string(ctx, lhs), VmContextExt::get_string(ctx, lhs),
VmContextExt::get_string(ctx, rhs), VmContextExt::get_string(ctx, rhs),
) { ) {
let ns = Gc::new(mc, crate::NixString::new(format!("{ls}{rs}"))); let ns = Gc::new(mc, crate::NixString::new(format!("{ls}{rs}")));
self.push_stack(Value::new_gc(ns)); self.push(Value::new_gc(ns));
return StepResult::Continue; return Step::Continue;
} }
let res = numeric_binop(lhs, rhs, mc, i64::wrapping_add, |a, b| a + b); let res = numeric_binop(lhs, rhs, mc, i64::wrapping_add, |a, b| a + b);
match res { match res {
Ok(val) => { Ok(val) => {
self.push_stack(val); self.push(val);
StepResult::Continue Step::Continue
} }
Err(e) => self.finish_vm_err(e), Err(e) => self.finish_vm_err(e),
} }
@@ -43,7 +44,7 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.op_arith(reader, mc, i64::wrapping_sub, |a, b| a - b) self.op_arith(reader, mc, i64::wrapping_sub, |a, b| a - b)
} }
@@ -52,7 +53,7 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.op_arith(reader, mc, i64::wrapping_mul, |a, b| a * b) self.op_arith(reader, mc, i64::wrapping_mul, |a, b| a * b)
} }
@@ -63,20 +64,20 @@ impl<'gc> crate::Vm<'gc> {
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
int_op: fn(i64, i64) -> i64, int_op: fn(i64, i64) -> i64,
float_op: fn(f64, f64) -> f64, float_op: fn(f64, f64) -> f64,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let rhs = self.pop_stack_forced(); let rhs = self.pop_forced();
let lhs = self.pop_stack_forced(); let lhs = self.pop_forced();
let res = numeric_binop(lhs, rhs, mc, int_op, float_op); let res = numeric_binop(lhs, rhs, mc, int_op, float_op);
match res { match res {
Ok(val) => { Ok(val) => {
self.push_stack(val); self.push(val);
StepResult::Continue Step::Continue
} }
Err(e) => self.finish_vm_err(e), Err(e) => self.finish_vm_err(e),
} }
@@ -87,15 +88,15 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let rhs = self.pop_stack_forced(); let rhs = self.pop_forced();
let lhs = self.pop_stack_forced(); let lhs = self.pop_forced();
match (get_num(rhs), get_num(lhs)) { match (get_num(rhs), get_num(lhs)) {
(_, Some(NixNum::Int(0))) | (_, Some(NixNum::Float(0.))) => { (_, Some(NixNum::Int(0))) | (_, Some(NixNum::Float(0.))) => {
return self.finish_vm_err(VmError::Uncatchable(fix_error::Error::eval_error( 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); let res = numeric_binop(lhs, rhs, mc, |a, b| a / b, |a, b| a / b);
match res { match res {
Ok(val) => { Ok(val) => {
self.push_stack(val); self.push(val);
StepResult::Continue Step::Continue
} }
Err(e) => self.finish_vm_err(e), Err(e) => self.finish_vm_err(e),
} }
@@ -120,7 +121,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
@@ -131,8 +132,8 @@ impl<'gc> crate::Vm<'gc> {
Ok(eq) => eq, Ok(eq) => eq,
Err(e) => return self.finish_vm_err(e), Err(e) => return self.finish_vm_err(e),
}; };
self.push_stack(Value::new_inline(eq)); self.push(Value::new_inline(eq));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -141,7 +142,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
@@ -152,8 +153,8 @@ impl<'gc> crate::Vm<'gc> {
Ok(eq) => eq, Ok(eq) => eq,
Err(e) => return self.finish_vm_err(e), Err(e) => return self.finish_vm_err(e),
}; };
self.push_stack(Value::new_inline(!eq)); self.push(Value::new_inline(!eq));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -162,7 +163,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.compare_values(ctx, reader, mc, Ordering::is_lt) self.compare_values(ctx, reader, mc, Ordering::is_lt)
} }
@@ -172,7 +173,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.compare_values(ctx, reader, mc, Ordering::is_gt) self.compare_values(ctx, reader, mc, Ordering::is_gt)
} }
@@ -182,7 +183,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.compare_values(ctx, reader, mc, Ordering::is_le) self.compare_values(ctx, reader, mc, Ordering::is_le)
} }
@@ -192,7 +193,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.compare_values(ctx, reader, mc, Ordering::is_ge) self.compare_values(ctx, reader, mc, Ordering::is_ge)
} }
@@ -202,7 +203,7 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
pred: fn(Ordering) -> bool, pred: fn(Ordering) -> bool,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
@@ -210,7 +211,7 @@ impl<'gc> crate::Vm<'gc> {
return step; return step;
} }
match self.compare_values_inner(ctx, pred) { match self.compare_values_inner(ctx, pred) {
Ok(()) => StepResult::Continue, Ok(()) => Step::Continue,
Err(e) => self.finish_vm_err(e), Err(e) => self.finish_vm_err(e),
} }
} }
@@ -220,30 +221,26 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let rhs = self.pop_stack_forced(); let r = match self.pop_forced_expect_gc::<List>() {
let lhs = self.pop_stack_forced(); Ok(val) => val,
let Some(l) = lhs.as_gc::<crate::List>() else { Err(got) => return self.finish_type_err(NixType::List, got)
return self.finish_err(fix_error::Error::eval_error(
"cannot concatenate: left operand is not a list",
));
}; };
let Some(r) = rhs.as_gc::<crate::List>() else { let l = match self.pop_forced_expect_gc::<List>() {
return self.finish_err(fix_error::Error::eval_error( Ok(val) => val,
"cannot concatenate: right operand is not a list", Err(got) => return self.finish_type_err(NixType::List, got)
));
}; };
let mut items = smallvec::SmallVec::new(); let mut items = smallvec::SmallVec::new();
items.extend_from_slice(&l); items.extend_from_slice(&l);
items.extend_from_slice(&r); items.extend_from_slice(&r);
self.push_stack(Value::new_gc(Gc::new(mc, crate::List { inner: items }))); self.push(Value::new_gc(Gc::new(mc, crate::List { inner: items })));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -251,42 +248,38 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(1, reader, mc) { if let Some(step) = self.try_force(1, reader, mc) {
return step; return step;
} }
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let rhs = self.pop_stack_forced(); let r = match self.pop_forced_expect_gc::<AttrSet>() {
let lhs = self.pop_stack_forced(); Ok(val) => val,
let Some(l) = lhs.as_gc::<crate::AttrSet>() else { Err(got) => return self.finish_type_err(NixType::AttrSet, got)
return self.finish_err(fix_error::Error::eval_error(
"cannot update: left operand is not a set",
));
}; };
let Some(r) = rhs.as_gc::<crate::AttrSet>() else { let l = match self.pop_forced_expect_gc::<AttrSet>() {
return self.finish_err(fix_error::Error::eval_error( Ok(val) => val,
"cannot update: right operand is not a set", Err(got) => return self.finish_type_err(NixType::AttrSet, got)
));
}; };
self.push_stack(Value::new_gc(l.merge(&r, mc))); self.push(Value::new_gc(l.merge(&r, mc)));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_neg(&mut self) -> StepResult { pub(crate) fn op_neg(&mut self) -> Step {
todo!("implement unary operation"); todo!("implement unary operation");
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_not(&mut self) -> StepResult { pub(crate) fn op_not(&mut self) -> Step {
todo!("implement unary operation"); todo!("implement unary operation");
} }
pub(crate) fn values_equal(&mut self, ctx: &impl crate::VmContext) -> crate::VmResult<bool> { pub(crate) fn values_equal(&mut self, ctx: &impl crate::VmContext) -> crate::VmResult<bool> {
let rhs = self.pop_stack_forced(); let rhs = self.pop_forced();
let lhs = self.pop_stack_forced(); let lhs = self.pop_forced();
if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) { if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) {
return Ok(match (a, b) { return Ok(match (a, b) {
@@ -314,8 +307,8 @@ impl<'gc> crate::Vm<'gc> {
} }
let len = a.inner.len(); let len = a.inner.len();
for (x, y) in a.inner.iter().zip(b.inner.iter()).rev() { for (x, y) in a.inner.iter().zip(b.inner.iter()).rev() {
self.push_stack(*x); self.push(*x);
self.push_stack(*y); self.push(*y);
} }
for i in 0..len { for i in 0..len {
let eq = self.values_equal(ctx)?; let eq = self.values_equal(ctx)?;
@@ -336,8 +329,8 @@ impl<'gc> crate::Vm<'gc> {
if k1 != k2 { if k1 != k2 {
return Ok(false); return Ok(false);
} }
self.push_stack(*v1); self.push(*v1);
self.push_stack(*v2); self.push(*v2);
} }
for i in 0..len { for i in 0..len {
let eq = self.values_equal(ctx)?; let eq = self.values_equal(ctx)?;
@@ -357,8 +350,8 @@ impl<'gc> crate::Vm<'gc> {
ctx: &impl crate::VmContext, ctx: &impl crate::VmContext,
pred: fn(Ordering) -> bool, pred: fn(Ordering) -> bool,
) -> crate::VmResult<()> { ) -> crate::VmResult<()> {
let rhs = self.pop_stack_forced(); let rhs = self.pop_forced();
let lhs = self.pop_stack_forced(); let lhs = self.pop_forced();
if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) { if let (Some(a), Some(b)) = (get_num(lhs), get_num(rhs)) {
let ord = match (a, b) { let ord = match (a, b) {
@@ -371,16 +364,17 @@ impl<'gc> crate::Vm<'gc> {
a.partial_cmp(&(b as f64)).unwrap_or(Ordering::Less) 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(()); return Ok(());
} }
if let (Some(a), Some(b)) = ( if let (Some(a), Some(b)) = (
VmContextExt::get_string(ctx, lhs), VmContextExt::get_string(ctx, lhs),
VmContextExt::get_string(ctx, rhs), 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(()); return Ok(());
} }
// TODO: compare other types
Err(crate::vm_err("cannot compare these types")) Err(crate::vm_err("cannot compare these types"))
} }
} }
+12 -12
View File
@@ -1,28 +1,28 @@
use fix_builtins::BuiltinId; use fix_builtins::BuiltinId;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use crate::{BytecodeReader, PrimOp, StepResult, Value}; use crate::{BytecodeReader, PrimOp, Step, Value};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
pub(crate) fn op_load_builtins(&mut self) -> StepResult { pub(crate) fn op_load_builtins(&mut self) -> Step {
self.push_stack(self.builtins); self.push(self.builtins);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_load_builtin(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_load_builtin(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let Ok(id) = BuiltinId::try_from_primitive(reader.read_u8()) let Ok(id) = BuiltinId::try_from_primitive(reader.read_u8())
.map_err(|err| panic!("unknown builtin id: {}", err.number)); .map_err(|err| panic!("unknown builtin id: {}", err.number));
self.push_stack(Value::new_inline(PrimOp { self.push(Value::new_inline(PrimOp {
id, id,
arity: fix_builtins::BUILTINS[id as usize].1, arity: fix_builtins::BUILTINS[id as usize].1,
})); }));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_mk_pos(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_mk_pos(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let _span_id = reader.read_u32(); let _span_id = reader.read_u32();
todo!("MkPos"); todo!("MkPos");
} }
@@ -31,7 +31,7 @@ impl<'gc> crate::Vm<'gc> {
pub(crate) fn op_load_repl_binding( pub(crate) fn op_load_repl_binding(
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
) -> StepResult { ) -> Step {
let _name = reader.read_string_id(); let _name = reader.read_string_id();
todo!("LoadReplBinding"); todo!("LoadReplBinding");
} }
@@ -40,7 +40,7 @@ impl<'gc> crate::Vm<'gc> {
pub(crate) fn op_load_scoped_binding( pub(crate) fn op_load_scoped_binding(
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
) -> StepResult { ) -> Step {
let _name = reader.read_string_id(); let _name = reader.read_string_id();
todo!("LoadScopedBinding"); todo!("LoadScopedBinding");
} }
@@ -51,7 +51,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
_mc: &gc_arena::Mutation<'gc>, _mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let _parts_count = reader.read_u16() as usize; let _parts_count = reader.read_u16() as usize;
let _force_string = reader.read_u8() != 0; let _force_string = reader.read_u8() != 0;
let mut _operands: smallvec::SmallVec<[crate::OperandData; 4]> = let mut _operands: smallvec::SmallVec<[crate::OperandData; 4]> =
@@ -63,7 +63,7 @@ impl<'gc> crate::Vm<'gc> {
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_resolve_path(&mut self, _ctx: &mut impl crate::VmContext) -> StepResult { pub(crate) fn op_resolve_path(&mut self, _ctx: &mut impl crate::VmContext) -> Step {
todo!("implement ResolvePath"); todo!("implement ResolvePath");
} }
} }
+12 -12
View File
@@ -1,7 +1,7 @@
use fix_error::Error; use fix_error::Error;
use gc_arena::{Gc, Mutation, RefLock}; use gc_arena::{Gc, Mutation, RefLock};
use crate::{BytecodeReader, CallFrame, Closure, Env, StepResult, ThunkState, VmContextExt}; use crate::{BytecodeReader, CallFrame, Closure, Env, Step, ThunkState, VmContextExt};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
@@ -10,7 +10,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
@@ -18,7 +18,7 @@ impl<'gc> crate::Vm<'gc> {
return self.finish_err(Error::eval_error("stack overflow; max-call-depth exceeded")); return self.finish_err(Error::eval_error("stack overflow; max-call-depth exceeded"));
} }
self.call_depth += 1; self.call_depth += 1;
let func = self.pop_stack(); let func = self.pop();
let arg = reader.read_operand_data(ctx).resolve(mc, self); let arg = reader.read_operand_data(ctx).resolve(mc, self);
if let Some(closure) = func.as_gc::<Closure>() { if let Some(closure) = func.as_gc::<Closure>() {
let ip = closure.ip; let ip = closure.ip;
@@ -41,7 +41,7 @@ impl<'gc> crate::Vm<'gc> {
} else { } else {
todo!("call other types: {func:?}") todo!("call other types: {func:?}")
} }
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -50,7 +50,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
self.handle_return(reader, ctx, mc) self.handle_return(reader, ctx, mc)
} }
@@ -59,7 +59,7 @@ impl<'gc> crate::Vm<'gc> {
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
ctx: &C, ctx: &C,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let ret_inst_pc = reader.pc() - 1; let ret_inst_pc = reader.pc() - 1;
let Some(CallFrame { let Some(CallFrame {
pc: ret_pc, pc: ret_pc,
@@ -69,18 +69,18 @@ impl<'gc> crate::Vm<'gc> {
with_env, with_env,
}) = self.call_stack.pop() }) = self.call_stack.pop()
else { else {
let val = self.pop_stack(); let val = self.pop();
return self.finish_ok(ctx.convert_value(val)); return self.finish_ok(ctx.convert_value(val));
}; };
reader.set_pc(ret_pc); reader.set_pc(ret_pc);
if let Some(outer_thunk) = thunk { if let Some(outer_thunk) = thunk {
let val = self.pop_stack(); let val = self.pop();
match val.restrict() { match val.restrict() {
Ok(val) => { Ok(val) => {
*outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val); *outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val);
if reader.bytecode().get(ret_pc).copied() == Some(fix_codegen::Op::Return as u8) if reader.bytecode().get(ret_pc).copied() == Some(fix_codegen::Op::Return as u8)
{ {
self.push_stack(val.relax()); self.push(val.relax());
} }
} }
Err(inner_thunk) => { Err(inner_thunk) => {
@@ -109,14 +109,14 @@ impl<'gc> crate::Vm<'gc> {
reader.set_pc(inner_ip); reader.set_pc(inner_ip);
self.env = inner_env; self.env = inner_env;
self.with_env = inner_with_env; self.with_env = inner_with_env;
return StepResult::Continue; return Step::Continue;
} }
ThunkState::Evaluated(val) => { ThunkState::Evaluated(val) => {
*outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val); *outer_thunk.borrow_mut(mc) = ThunkState::Evaluated(val);
if reader.bytecode().get(ret_pc).copied() if reader.bytecode().get(ret_pc).copied()
== Some(fix_codegen::Op::Return as u8) == Some(fix_codegen::Op::Return as u8)
{ {
self.push_stack(val.relax()); self.push(val.relax());
} }
} }
ThunkState::Apply { func: _, arg: _ } => todo!("force Apply thunk"), ThunkState::Apply { func: _, arg: _ } => todo!("force Apply thunk"),
@@ -132,6 +132,6 @@ impl<'gc> crate::Vm<'gc> {
} }
self.env = env; self.env = env;
self.with_env = with_env; self.with_env = with_env;
StepResult::Continue Step::Continue
} }
} }
+10 -10
View File
@@ -1,6 +1,6 @@
use gc_arena::{Gc, Mutation, RefLock}; use gc_arena::{Gc, Mutation, RefLock};
use crate::{BytecodeReader, StepResult, ThunkState, Value}; use crate::{BytecodeReader, Step, ThunkState, Value};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
@@ -8,7 +8,7 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let entry_point = reader.read_u32(); let entry_point = reader.read_u32();
let thunk = Gc::new( let thunk = Gc::new(
mc, mc,
@@ -18,8 +18,8 @@ impl<'gc> crate::Vm<'gc> {
with_env: self.with_env, with_env: self.with_env,
}), }),
); );
self.push_stack(Value::new_gc(thunk)); self.push(Value::new_gc(thunk));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -27,7 +27,7 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let entry_point = reader.read_u32(); let entry_point = reader.read_u32();
let n_locals = reader.read_u32(); let n_locals = reader.read_u32();
let closure = Gc::new( let closure = Gc::new(
@@ -39,8 +39,8 @@ impl<'gc> crate::Vm<'gc> {
pattern: None, pattern: None,
}, },
); );
self.push_stack(Value::new_gc(closure)); self.push(Value::new_gc(closure));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -48,7 +48,7 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let entry_point = reader.read_u32(); let entry_point = reader.read_u32();
let n_locals = reader.read_u32(); let n_locals = reader.read_u32();
let req_count = reader.read_u16() as usize; let req_count = reader.read_u16() as usize;
@@ -89,7 +89,7 @@ impl<'gc> crate::Vm<'gc> {
pattern: Some(pattern), pattern: Some(pattern),
}, },
); );
self.push_stack(Value::new_gc(closure)); self.push(Value::new_gc(closure));
StepResult::Continue Step::Continue
} }
} }
+24 -24
View File
@@ -3,7 +3,7 @@ use gc_arena::Gc;
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::{ use crate::{
AttrKeyData, AttrSet, BytecodeReader, List, NixString, OperandData, StepResult, Value, AttrKeyData, AttrSet, BytecodeReader, List, NixString, OperandData, Step, Value,
}; };
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
@@ -13,7 +13,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let count = reader.read_u32() as usize; let count = reader.read_u32() as usize;
let mut entries: SmallVec<[AttrEntry; 4]> = SmallVec::with_capacity(count); let mut entries: SmallVec<[AttrEntry; 4]> = SmallVec::with_capacity(count);
for _ in 0..count { for _ in 0..count {
@@ -37,14 +37,14 @@ impl<'gc> crate::Vm<'gc> {
} }
kv.sort_by_key(|(k, _)| *k); kv.sort_by_key(|(k, _)| *k);
let attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(kv)); let attrs = Gc::new(mc, AttrSet::from_sorted_unchecked(kv));
self.push_stack(Value::new_gc(attrs)); self.push(Value::new_gc(attrs));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_make_empty_attrs(&mut self) -> StepResult { pub(crate) fn op_make_empty_attrs(&mut self) -> Step {
self.push_stack(self.empty_attrs); self.push(self.empty_attrs);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -53,7 +53,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let _span_id = reader.read_u32(); let _span_id = reader.read_u32();
let key = reader.read_string_id(); let key = reader.read_string_id();
@@ -61,7 +61,7 @@ impl<'gc> crate::Vm<'gc> {
return step; return step;
} }
let attrs = self.peek_stack(0).restrict().expect("forced"); let attrs = self.peek(0).restrict().expect("forced");
let Some(attrset) = attrs.as_gc::<AttrSet>() else { let Some(attrset) = attrs.as_gc::<AttrSet>() else {
return self.finish_err(Error::eval_error( return self.finish_err(Error::eval_error(
"value is not a set while a set was expected", "value is not a set while a set was expected",
@@ -70,7 +70,7 @@ impl<'gc> crate::Vm<'gc> {
match attrset.lookup(key) { match attrset.lookup(key) {
Some(v) => { Some(v) => {
self.replace_stack(0, v); self.replace(0, v);
} }
None => loop { None => loop {
let byte = reader.bytecode()[reader.pc()]; let byte = reader.bytecode()[reader.pc()];
@@ -80,7 +80,7 @@ impl<'gc> crate::Vm<'gc> {
reader.set_pc(reader.pc() + 1 + 4); reader.set_pc(reader.pc() + 1 + 4);
} else if byte == fix_codegen::Op::JumpIfSelectSucceeded as u8 { } else if byte == fix_codegen::Op::JumpIfSelectSucceeded as u8 {
reader.set_pc(reader.pc() + 1 + 4); reader.set_pc(reader.pc() + 1 + 4);
let _ = self.pop_stack(); let _ = self.pop();
break; break;
} else { } else {
let name = ctx.resolve_string(key); let name = ctx.resolve_string(key);
@@ -89,7 +89,7 @@ impl<'gc> crate::Vm<'gc> {
} }
}, },
} }
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -98,7 +98,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let _span_id = reader.read_u32(); let _span_id = reader.read_u32();
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
@@ -129,28 +129,28 @@ impl<'gc> crate::Vm<'gc> {
match attrset.lookup(key_sid) { match attrset.lookup(key_sid) {
Some(v) => { Some(v) => {
self.stack.truncate(self.stack.len() - 2); self.stack.truncate(self.stack.len() - 2);
self.push_stack(v); self.push(v);
} }
None => { None => {
let name = ctx.resolve_string(key_sid); let name = ctx.resolve_string(key_sid);
return self.finish_err(Error::eval_error(format!("attribute '{name}' missing"))); return self.finish_err(Error::eval_error(format!("attribute '{name}' missing")));
} }
} }
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_jump_if_select_succeeded( pub(crate) fn op_jump_if_select_succeeded(
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
) -> StepResult { ) -> Step {
let offset = reader.read_i32(); let offset = reader.read_i32();
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_has_attr(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_has_attr(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let _n = reader.read_u16() as usize; let _n = reader.read_u16() as usize;
todo!("HasAttr"); todo!("HasAttr");
} }
@@ -161,21 +161,21 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let count = reader.read_u32() as usize; let count = reader.read_u32() as usize;
let mut items: SmallVec<[Value; 4]> = SmallVec::with_capacity(count); let mut items: SmallVec<[Value; 4]> = SmallVec::with_capacity(count);
for _ in 0..count { for _ in 0..count {
items.push(reader.read_operand_data(ctx).resolve(mc, self)); items.push(reader.read_operand_data(ctx).resolve(mc, self));
} }
let list = Gc::new(mc, List { inner: items }); let list = Gc::new(mc, List { inner: items });
self.push_stack(Value::new_gc(list)); self.push(Value::new_gc(list));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_make_empty_list(&mut self) -> StepResult { pub(crate) fn op_make_empty_list(&mut self) -> Step {
self.push_stack(self.empty_list); self.push(self.empty_list);
StepResult::Continue Step::Continue
} }
} }
+10 -10
View File
@@ -1,4 +1,4 @@
use crate::{BytecodeReader, StepResult}; use crate::{BytecodeReader, Step};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
@@ -6,16 +6,16 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let offset = reader.read_i32(); let offset = reader.read_i32();
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let cond = self.pop_stack(); let cond = self.pop();
if cond.as_inline::<bool>() == Some(false) { if cond.as_inline::<bool>() == Some(false) {
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
} }
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -23,27 +23,27 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let offset = reader.read_i32(); let offset = reader.read_i32();
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let cond = self.pop_stack(); let cond = self.pop();
if cond.as_inline::<bool>() == Some(true) { if cond.as_inline::<bool>() == Some(true) {
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
} }
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_jump(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_jump(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let offset = reader.read_i32(); let offset = reader.read_i32();
reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize); reader.set_pc(((reader.pc() as isize) + (offset as isize)) as usize);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_assert(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_assert(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let _raw_idx = reader.read_u32(); let _raw_idx = reader.read_u32();
let _span_id = reader.read_u32(); let _span_id = reader.read_u32();
todo!("implement Assert (force TOS)"); todo!("implement Assert (force TOS)");
+22 -22
View File
@@ -1,13 +1,13 @@
use gc_arena::{Gc, Mutation}; use gc_arena::{Gc, Mutation};
use crate::{BytecodeReader, StepResult, Value}; use crate::{BytecodeReader, Step, Value};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
pub(crate) fn op_push_smi(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_push_smi(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let val = reader.read_i32(); let val = reader.read_i32();
self.push_stack(Value::new_inline(val)); self.push(Value::new_inline(val));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -15,41 +15,41 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let val = reader.read_i64(); let val = reader.read_i64();
self.push_stack(Value::new_gc(Gc::new(mc, val))); self.push(Value::new_gc(Gc::new(mc, val)));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_push_float(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_push_float(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let val = reader.read_f64(); let val = reader.read_f64();
self.push_stack(Value::new_float(val)); self.push(Value::new_float(val));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_push_string(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_push_string(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let sid = reader.read_string_id(); let sid = reader.read_string_id();
self.push_stack(Value::new_inline(sid)); self.push(Value::new_inline(sid));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_push_null(&mut self) -> StepResult { pub(crate) fn op_push_null(&mut self) -> Step {
self.push_stack(Value::new_inline(crate::Null)); self.push(Value::new_inline(crate::Null));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_push_true(&mut self) -> StepResult { pub(crate) fn op_push_true(&mut self) -> Step {
self.push_stack(Value::new_inline(true)); self.push(Value::new_inline(true));
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_push_false(&mut self) -> StepResult { pub(crate) fn op_push_false(&mut self) -> Step {
self.push_stack(Value::new_inline(false)); self.push(Value::new_inline(false));
StepResult::Continue Step::Continue
} }
} }
+12 -12
View File
@@ -1,15 +1,15 @@
use crate::{BytecodeReader, Mutation, StepResult, Value}; use crate::{BytecodeReader, Mutation, Step, Value};
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
pub(crate) fn op_load_local(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_load_local(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let idx = reader.read_u32() as usize; let idx = reader.read_u32() as usize;
self.push_stack(self.env.borrow().locals[idx]); self.push(self.env.borrow().locals[idx]);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_load_outer(&mut self, reader: &mut BytecodeReader<'_>) -> StepResult { pub(crate) fn op_load_outer(&mut self, reader: &mut BytecodeReader<'_>) -> Step {
let layer = reader.read_u8(); let layer = reader.read_u8();
let idx = reader.read_u32() as usize; let idx = reader.read_u32() as usize;
let mut cur = self.env; let mut cur = self.env;
@@ -18,8 +18,8 @@ impl<'gc> crate::Vm<'gc> {
cur = prev; cur = prev;
} }
let val = cur.borrow().locals[idx]; let val = cur.borrow().locals[idx];
self.push_stack(val); self.push(val);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -27,11 +27,11 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let idx = reader.read_u32() as usize; let idx = reader.read_u32() as usize;
let val = self.pop_stack(); let val = self.pop();
self.env.borrow_mut(mc).locals[idx] = val; self.env.borrow_mut(mc).locals[idx] = val;
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -39,12 +39,12 @@ impl<'gc> crate::Vm<'gc> {
&mut self, &mut self,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> StepResult { ) -> Step {
let count = reader.read_u32() as usize; let count = reader.read_u32() as usize;
self.env self.env
.borrow_mut(mc) .borrow_mut(mc)
.locals .locals
.extend(std::iter::repeat_n(Value::default(), count)); .extend(std::iter::repeat_n(Value::default(), count));
StepResult::Continue Step::Continue
} }
} }
+17 -13
View File
@@ -2,7 +2,8 @@ use fix_common::Symbol;
use fix_error::Error; use fix_error::Error;
use gc_arena::Gc; use gc_arena::Gc;
use crate::{BytecodeReader, CallFrame, StepResult, WithEnv}; use crate::{BytecodeReader, CallFrame, Step, WithEnv};
use crate::value::*;
impl<'gc> crate::Vm<'gc> { impl<'gc> crate::Vm<'gc> {
#[inline(always)] #[inline(always)]
@@ -11,7 +12,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let env = reader.read_operand_data(ctx).resolve(mc, self); let env = reader.read_operand_data(ctx).resolve(mc, self);
let scope = Gc::new( let scope = Gc::new(
mc, mc,
@@ -21,20 +22,20 @@ impl<'gc> crate::Vm<'gc> {
}, },
); );
self.with_env = Some(scope); self.with_env = Some(scope);
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_pop_with(&mut self) -> StepResult { pub(crate) fn op_pop_with(&mut self) -> Step {
let Some(scope) = self.with_env else { let Some(scope) = self.with_env else {
unreachable!("no with_scope to pop"); unreachable!("no with_scope to pop");
}; };
self.with_env = scope.prev; self.with_env = scope.prev;
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
pub(crate) fn op_prepare_with(&mut self) -> StepResult { pub(crate) fn op_prepare_with(&mut self) -> Step {
self.call_stack.push(CallFrame { self.call_stack.push(CallFrame {
pc: usize::MAX, pc: usize::MAX,
stack_depth: 0, stack_depth: 0,
@@ -42,7 +43,7 @@ impl<'gc> crate::Vm<'gc> {
env: self.env, env: self.env,
with_env: self.with_env, with_env: self.with_env,
}); });
StepResult::Continue Step::Continue
} }
#[inline(always)] #[inline(always)]
@@ -51,7 +52,7 @@ impl<'gc> crate::Vm<'gc> {
ctx: &mut impl crate::VmContext, ctx: &mut impl crate::VmContext,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &gc_arena::Mutation<'gc>, mc: &gc_arena::Mutation<'gc>,
) -> StepResult { ) -> Step {
let name = reader.read_string_id(); let name = reader.read_string_id();
let Some(&WithEnv { env, prev }) = self.with_env.as_deref() else { let Some(&WithEnv { env, prev }) = self.with_env.as_deref() else {
@@ -64,23 +65,26 @@ impl<'gc> crate::Vm<'gc> {
Symbol::from(ctx.resolve_string(name)) Symbol::from(ctx.resolve_string(name))
))); )));
}; };
self.push_stack(env); self.push(env);
if let Some(step) = self.try_force(0, reader, mc) { if let Some(step) = self.try_force(0, reader, mc) {
return step; return step;
} }
let env = self.pop_stack().as_gc::<crate::AttrSet>().unwrap(); let env = match self.pop_forced_expect_gc::<AttrSet>() {
Ok(val) => val,
Err(got) => return self.finish_type_err(NixType::List, got)
};
let Some(val) = env.lookup(name) else { let Some(val) = env.lookup(name) else {
reader.set_pc(reader.inst_start_pc()); reader.set_pc(reader.inst_start_pc());
self.with_env = prev; self.with_env = prev;
return StepResult::Continue; return Step::Continue;
}; };
self.push_stack(val); self.push(val);
let Some(CallFrame { with_env, .. }) = self.call_stack.pop() else { let Some(CallFrame { with_env, .. }) = self.call_stack.pop() else {
unreachable!() unreachable!()
}; };
self.with_env = with_env; self.with_env = with_env;
StepResult::Continue Step::Continue
} }
} }
+54 -17
View File
@@ -132,7 +132,7 @@ impl<T: VmContext> VmContextExt for T {
} }
#[repr(u8)] #[repr(u8)]
pub(crate) enum StepResult { pub(crate) enum Step {
Continue, Continue,
Done, Done,
} }
@@ -271,36 +271,42 @@ impl<'gc> Vm<'gc> {
} }
#[inline(always)] #[inline(always)]
pub(crate) fn finish_ok(&mut self, val: fix_common::Value) -> StepResult { pub(crate) fn finish_ok(&mut self, val: fix_common::Value) -> Step {
self.result = Some(Ok(val)); self.result = Some(Ok(val));
StepResult::Done Step::Done
} }
#[inline(always)] #[inline(always)]
pub(crate) fn finish_err(&mut self, err: Box<Error>) -> StepResult { pub(crate) fn finish_err(&mut self, err: Box<Error>) -> Step {
self.result = Some(Err(err)); self.result = Some(Err(err));
StepResult::Done Step::Done
} }
#[inline(always)] #[inline(always)]
pub(crate) fn finish_vm_err(&mut self, err: VmError) -> StepResult { pub(crate) fn finish_type_err(&mut self, expected: NixType, got: NixType) -> Step {
self.result = Some(Err(Error::eval_error(format!("expected {expected}, got {got}"))));
Step::Done
}
#[inline(always)]
pub(crate) fn finish_vm_err(&mut self, err: VmError) -> Step {
self.finish_err(err.into_error()) self.finish_err(err.into_error())
} }
#[inline(always)] #[inline(always)]
pub(crate) fn push_stack(&mut self, val: Value<'gc>) { pub(crate) fn push(&mut self, val: Value<'gc>) {
self.stack.push(val); self.stack.push(val);
} }
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn pop_stack(&mut self) -> Value<'gc> { pub(crate) fn pop(&mut self) -> Value<'gc> {
self.stack.pop().expect("stack underflow") self.stack.pop().expect("stack underflow")
} }
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn peek_stack(&mut self, depth: usize) -> Value<'gc> { pub(crate) fn peek(&mut self, depth: usize) -> Value<'gc> {
*self *self
.stack .stack
.get(self.stack.len() - depth - 1) .get(self.stack.len() - depth - 1)
@@ -308,7 +314,18 @@ impl<'gc> Vm<'gc> {
} }
#[inline(always)] #[inline(always)]
pub(crate) fn replace_stack(&mut self, depth: usize, val: Value<'gc>) { #[must_use]
pub(crate) fn peek_forced(&mut self, depth: usize) -> StrictValue<'gc> {
self
.stack
.get(self.stack.len() - depth - 1)
.expect("stack underflow")
.restrict()
.expect("forced")
}
#[inline(always)]
pub(crate) fn replace(&mut self, depth: usize, val: Value<'gc>) {
let len = self.stack.len(); let len = self.stack.len();
*self *self
.stack .stack
@@ -318,7 +335,7 @@ impl<'gc> Vm<'gc> {
#[inline(always)] #[inline(always)]
#[cfg_attr(debug_assertions, track_caller)] #[cfg_attr(debug_assertions, track_caller)]
pub(crate) fn pop_stack_forced(&mut self) -> StrictValue<'gc> { pub(crate) fn pop_forced(&mut self) -> StrictValue<'gc> {
self.stack self.stack
.pop() .pop()
.expect("stack underflow") .expect("stack underflow")
@@ -326,14 +343,34 @@ impl<'gc> Vm<'gc> {
.expect("forced") .expect("forced")
} }
#[inline(always)]
pub(crate) fn pop_forced_expect_inline<T: InlineStorable>(&mut self) -> std::result::Result<T, NixType> {
self.pop_forced().expect_inline::<T>()
}
#[inline(always)]
pub(crate) fn pop_forced_expect_gc<T: GcStorable>(&mut self) -> std::result::Result<Gc<'gc, T>, NixType> {
self.pop_forced().expect_gc::<T>()
}
#[inline(always)]
pub(crate) fn pop_forced_expect_num(&mut self) -> std::result::Result<NixNum, NixType> {
self.pop_forced().expect_num()
}
#[inline(always)]
pub(crate) fn pop_forced_expect_bool(&mut self) -> std::result::Result<bool, NixType> {
self.pop_forced().expect_bool()
}
#[inline(always)] #[inline(always)]
pub(crate) fn try_force( pub(crate) fn try_force(
&mut self, &mut self,
depth: usize, depth: usize,
reader: &mut BytecodeReader<'_>, reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>, mc: &Mutation<'gc>,
) -> Option<StepResult> { ) -> Option<Step> {
let thunk = self.peek_stack(depth).as_gc::<Thunk>()?; let thunk = self.peek(depth).as_gc::<Thunk>()?;
let mut state = thunk.borrow_mut(mc); let mut state = thunk.borrow_mut(mc);
match *state { match *state {
ThunkState::Pending { ip, env, with_env } => { ThunkState::Pending { ip, env, with_env } => {
@@ -349,11 +386,11 @@ impl<'gc> Vm<'gc> {
self.env = env; self.env = env;
self.with_env = with_env; self.with_env = with_env;
reader.set_pc(ip); reader.set_pc(ip);
Some(StepResult::Continue) Some(Step::Continue)
} }
ThunkState::Evaluated(v) => { ThunkState::Evaluated(v) => {
drop(state); drop(state);
self.replace_stack(depth, v.relax()); self.replace(depth, v.relax());
None None
} }
ThunkState::Apply { .. } => todo!("force apply"), ThunkState::Apply { .. } => todo!("force apply"),
@@ -545,8 +582,8 @@ impl<'gc> Vm<'gc> {
}; };
match result { match result {
StepResult::Continue => {} Step::Continue => {}
StepResult::Done => { Step::Done => {
return Action::Done( return Action::Done(
self.result.take().expect("StepResult::Done without result"), self.result.take().expect("StepResult::Done without result"),
); );
+135 -45
View File
@@ -23,10 +23,10 @@ mod private {
/// # Safety /// # Safety
/// ///
/// 1. TAG must be unique among all implementors. /// TAG must be unique among all implementors.
/// 2. TAG must be within 1..=7 #[allow(private_interfaces)]
pub unsafe trait Storable: private::Cealed { pub unsafe trait Storable: private::Cealed {
const TAG: (bool, u8); const TAG: RawTag;
} }
#[allow(private_bounds)] #[allow(private_bounds)]
pub trait InlineStorable: Storable + RawStore {} pub trait InlineStorable: Storable + RawStore {}
@@ -38,15 +38,17 @@ macro_rules! define_value_types {
gc { $($gtype:ty => $gtag:expr, $gname:literal;)* } gc { $($gtype:ty => $gtag:expr, $gname:literal;)* }
) => { ) => {
$( $(
#[allow(private_interfaces)]
unsafe impl Storable for $itype { unsafe impl Storable for $itype {
const TAG: (bool, u8) = $itag; const TAG: RawTag = $itag;
} }
impl InlineStorable for $itype {} impl InlineStorable for $itype {}
impl private::Cealed for $itype {} impl private::Cealed for $itype {}
)* )*
$( $(
#[allow(private_interfaces)]
unsafe impl Storable for $gtype { unsafe impl Storable for $gtype {
const TAG: (bool, u8) = $gtag; const TAG: RawTag = $gtag;
} }
impl GcStorable for $gtype {} impl GcStorable for $gtype {}
impl private::Cealed for $gtype {} impl private::Cealed for $gtype {}
@@ -54,11 +56,9 @@ macro_rules! define_value_types {
const _: () = assert!(size_of::<Value<'static>>() == 8); const _: () = assert!(size_of::<Value<'static>>() == 8);
$(const _: () = assert!(size_of::<$itype>() <= 6);)* $(const _: () = assert!(size_of::<$itype>() <= 6);)*
$(const _: () = { let (_, val) = $itag; assert!(val >= 1 && val <= 7); };)*
$(const _: () = { let (_, val) = $gtag; assert!(val >= 1 && val <= 7); };)*
const _: () = { const _: () = {
let tags: &[(bool, u8)] = &[$($itag),*, $($gtag),*]; let tags: &[(bool, u8)] = &[$(RawTag::neg_val($itag)),*, $(RawTag::neg_val($gtag)),*];
let mut mask_false: u8 = 0; let mut mask_false: u8 = 0;
let mut mask_true: u8 = 0; let mut mask_true: u8 = 0;
let mut i = 0; let mut i = 0;
@@ -80,12 +80,12 @@ macro_rules! define_value_types {
const NEEDS_TRACE: bool = true; const NEEDS_TRACE: bool = true;
fn trace<T: Trace<'gc>>(&self, cc: &mut T) { fn trace<T: Trace<'gc>>(&self, cc: &mut T) {
let Some(tag) = self.raw.tag() else { return }; let Some(tag) = self.raw.tag() else { return };
match tag.neg_val() { match tag {
$(<$gtype as Storable>::TAG => unsafe { $(<$gtype as Storable>::TAG => unsafe {
self.load_gc::<$gtype>().trace(cc) self.load_gc::<$gtype>().trace(cc)
},)* },)*
$(<$itype as Storable>::TAG => (),)* $(<$itype as Storable>::TAG => (),)*
(neg, val) => unreachable!("invalid tag: neg={neg}, val={val}"), _ => unreachable!("invalid value tag"),
} }
} }
} }
@@ -101,7 +101,7 @@ macro_rules! define_value_types {
}),)* }),)*
$(Some(<$gtype as Storable>::TAG) => $(Some(<$gtype as Storable>::TAG) =>
write!(f, "{}(..)", $gname),)* write!(f, "{}(..)", $gname),)*
Some((neg, val)) => write!(f, "Unknown(neg={neg}, val={val})"), _ => unreachable!("invalid value tag"),
} }
} }
} }
@@ -110,20 +110,20 @@ macro_rules! define_value_types {
define_value_types! { define_value_types! {
inline { inline {
i32 => (false, 1), "SmallInt"; i32 => RawTag::P1, "SmallInt";
bool => (false, 2), "Bool"; bool => RawTag::P2, "Bool";
Null => (false, 3), "Null"; Null => RawTag::P3, "Null";
StringId => (false, 4), "SmallString"; StringId => RawTag::P4, "SmallString";
PrimOp => (false, 5), "PrimOp"; PrimOp => RawTag::P5, "PrimOp";
} }
gc { gc {
i64 => (false, 6), "BigInt"; i64 => RawTag::P6, "BigInt";
NixString => (false, 7), "String"; NixString => RawTag::P7, "String";
AttrSet<'_> => (true, 1), "AttrSet"; AttrSet<'_> => RawTag::N1, "AttrSet";
List<'_> => (true, 2), "List"; List<'_> => RawTag::N2, "List";
Thunk<'_> => (true, 3), "Thunk"; Thunk<'_> => RawTag::N3, "Thunk";
Closure<'_> => (true, 4), "Closure"; Closure<'_> => RawTag::N4, "Closure";
PrimOpApp<'_> => (true, 5), "PrimOpApp"; PrimOpApp<'_> => RawTag::N5, "PrimOpApp";
} }
} }
@@ -132,7 +132,7 @@ define_value_types! {
/// NaN-boxed value fitting in 8 bytes. /// NaN-boxed value fitting in 8 bytes.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(transparent)] #[repr(transparent)]
pub(crate) struct Value<'gc> { pub struct Value<'gc> {
raw: RawBox, raw: RawBox,
_marker: PhantomData<Gc<'gc, ()>>, _marker: PhantomData<Gc<'gc, ()>>,
} }
@@ -167,16 +167,15 @@ impl<'gc> Value<'gc> {
} }
} }
/// Returns the `(negative, val)` tag, or `None` for a float.
#[inline(always)] #[inline(always)]
fn tag(self) -> Option<(bool, u8)> { const fn tag(self) -> Option<RawTag> {
self.raw.tag().map(|t| t.neg_val()) self.raw.tag()
} }
} }
impl<'gc> Value<'gc> { impl<'gc> Value<'gc> {
#[inline] #[inline]
pub(crate) fn new_float(val: f64) -> Self { pub fn new_float(val: f64) -> Self {
Self { Self {
raw: RawBox::from_float(val), raw: RawBox::from_float(val),
_marker: PhantomData, _marker: PhantomData,
@@ -184,24 +183,24 @@ impl<'gc> Value<'gc> {
} }
#[inline] #[inline]
pub(crate) fn new_inline<T: InlineStorable>(val: T) -> Self { pub fn new_inline<T: InlineStorable>(val: T) -> Self {
Self::from_raw_value(RawValue::store( Self::from_raw_value(RawValue::store(
unsafe { RawTag::new_unchecked(T::TAG.0, T::TAG.1) }, T::TAG,
val, val,
)) ))
} }
#[inline] #[inline]
pub(crate) fn new_gc<T: GcStorable>(gc: Gc<'gc, T>) -> Self { pub fn new_gc<T: GcStorable>(gc: Gc<'gc, T>) -> Self {
let ptr = Gc::as_ptr(gc); let ptr = Gc::as_ptr(gc);
Self::from_raw_value(RawValue::store( Self::from_raw_value(RawValue::store(
unsafe { RawTag::new_unchecked(T::TAG.0, T::TAG.1) }, T::TAG,
ptr, ptr,
)) ))
} }
#[inline] #[inline]
pub(crate) fn make_int(val: i64, mc: &Mutation<'gc>) -> Self { pub fn make_int(val: i64, mc: &Mutation<'gc>) -> Self {
if val >= i32::MIN as i64 && val <= i32::MAX as i64 { if val >= i32::MIN as i64 && val <= i32::MAX as i64 {
Value::new_inline(val as i32) Value::new_inline(val as i32)
} else { } else {
@@ -212,24 +211,24 @@ impl<'gc> Value<'gc> {
impl<'gc> Value<'gc> { impl<'gc> Value<'gc> {
#[inline] #[inline]
pub(crate) fn is_float(self) -> bool { pub fn is_float(self) -> bool {
self.raw.is_float() self.raw.is_float()
} }
#[inline] #[inline]
pub(crate) fn is<T: Storable>(self) -> bool { pub fn is<T: Storable>(self) -> bool {
self.tag() == Some(T::TAG) self.tag() == Some(T::TAG)
} }
} }
impl<'gc> Value<'gc> { impl<'gc> Value<'gc> {
#[inline] #[inline]
pub(crate) fn as_float(self) -> Option<f64> { pub fn as_float(self) -> Option<f64> {
self.raw.float().copied() self.raw.float().copied()
} }
#[inline] #[inline]
pub(crate) fn as_inline<T: InlineStorable>(self) -> Option<T> { pub fn as_inline<T: InlineStorable>(self) -> Option<T> {
if self.is::<T>() { if self.is::<T>() {
Some(unsafe { Some(unsafe {
let rv = self.raw.value().unwrap_unchecked(); let rv = self.raw.value().unwrap_unchecked();
@@ -241,7 +240,7 @@ impl<'gc> Value<'gc> {
} }
#[inline] #[inline]
pub(crate) fn as_gc<T: GcStorable>(self) -> Option<Gc<'gc, T>> { pub fn as_gc<T: GcStorable>(self) -> Option<Gc<'gc, T>> {
if self.is::<T>() { if self.is::<T>() {
Some(unsafe { Some(unsafe {
let rv = self.raw.value().unwrap_unchecked(); let rv = self.raw.value().unwrap_unchecked();
@@ -254,7 +253,7 @@ impl<'gc> Value<'gc> {
} }
#[inline] #[inline]
pub(crate) fn as_num(self) -> Option<NixNum> { pub fn as_num(self) -> Option<NixNum> {
if let Some(i) = self.as_inline::<i32>() { if let Some(i) = self.as_inline::<i32>() {
Some(NixNum::Int(i as i64)) Some(NixNum::Int(i as i64))
} else if let Some(gc_i) = self.as_gc::<i64>() { } else if let Some(gc_i) = self.as_gc::<i64>() {
@@ -265,13 +264,69 @@ impl<'gc> Value<'gc> {
} }
#[inline] #[inline]
pub(crate) fn restrict(self) -> Result<StrictValue<'gc>, Gc<'gc, Thunk<'gc>>> { pub fn restrict(self) -> Result<StrictValue<'gc>, Gc<'gc, Thunk<'gc>>> {
if let Some(thunk) = self.as_gc::<Thunk<'gc>>() { if let Some(thunk) = self.as_gc::<Thunk<'gc>>() {
Err(thunk) Err(thunk)
} else { } else {
Ok(StrictValue(self)) Ok(StrictValue(self))
} }
} }
#[inline]
pub fn ty(self) -> NixType {
if self.is_float() {
NixType::Float
} else if self.is::<i32>() || self.is::<i64>() {
NixType::Int
} else if self.is::<bool>() {
NixType::Bool
} else if self.is::<Null>() {
NixType::Null
} else if self.is::<StringId>() {
NixType::String
} else if self.is::<PrimOp>() {
NixType::PrimOp
} else if self.is::<NixString>() {
NixType::String
} else if self.is::<AttrSet>() {
NixType::AttrSet
} else if self.is::<List>() {
NixType::List
} else if self.is::<Thunk>() {
NixType::Thunk
} else if self.is::<Closure>() {
NixType::Closure
} else if self.is::<PrimOpApp>() {
NixType::PrimOpApp
} else {
unreachable!("value has no recognized type tag")
}
}
#[inline]
pub(crate) fn expect_inline<T: InlineStorable>(self) -> Result<T, NixType> {
self.as_inline::<T>().ok_or_else(|| self.ty())
}
#[inline]
pub(crate) fn expect_gc<T: GcStorable>(self) -> Result<Gc<'gc, T>, NixType> {
self.as_gc::<T>().ok_or_else(|| self.ty())
}
#[inline]
pub(crate) fn expect_num(self) -> Result<NixNum, NixType> {
self.as_num().ok_or_else(|| self.ty())
}
#[inline]
pub(crate) fn expect_bool(self) -> Result<bool, NixType> {
self.as_inline::<bool>().ok_or_else(|| self.ty())
}
#[inline]
pub(crate) fn expect_float(self) -> Result<f64, NixType> {
self.as_float().ok_or_else(|| self.ty())
}
} }
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
@@ -550,8 +605,9 @@ pub(crate) struct PrimOpApp<'gc> {
pub(crate) args: SmallVec<[Value<'gc>; 2]>, pub(crate) args: SmallVec<[Value<'gc>; 2]>,
} }
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default, Collect)]
#[repr(transparent)] #[repr(transparent)]
#[collect(no_drop)]
pub(crate) struct StrictValue<'gc>(Value<'gc>); pub(crate) struct StrictValue<'gc>(Value<'gc>);
impl<'gc> StrictValue<'gc> { impl<'gc> StrictValue<'gc> {
@@ -575,9 +631,43 @@ impl fmt::Debug for StrictValue<'_> {
} }
} }
unsafe impl<'gc> Collect<'gc> for StrictValue<'gc> { #[derive(Clone, Copy, Debug, PartialEq, Eq, Collect)]
const NEEDS_TRACE: bool = true; #[collect(require_static)]
fn trace<T: gc_arena::collect::Trace<'gc>>(&self, cc: &mut T) { pub(crate) enum NixType {
self.0.trace(cc); Int,
Float,
Bool,
Null,
String,
AttrSet,
List,
Thunk,
Closure,
PrimOp,
PrimOpApp,
}
impl NixType {
pub fn display(self) -> &'static str {
use NixType::*;
match self {
Int => "an integer",
Float => "a float",
Bool => "a boolean",
Null => "null",
String => "a string",
AttrSet => "a set",
List => "a list",
Thunk => "a thunk",
Closure => "a function",
PrimOp => "a built-in function",
PrimOpApp => "a partially applied built-in function",
}
}
}
impl std::fmt::Display for NixType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.display())
} }
} }