From 8480e0891b3cc51d533d3216ed69462495e152d1 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 17 May 2025 15:18:16 +0800 Subject: [PATCH] feat(value): less clone --- src/builtins/mod.rs | 11 ++-- src/ir.rs | 8 ++- src/ty/common.rs | 2 +- src/ty/internal/attrset.rs | 37 ++++------- src/ty/internal/func.rs | 4 +- src/ty/internal/list.rs | 26 ++++---- src/ty/internal/mod.rs | 127 +++++++++++++++++++++++-------------- src/ty/internal/primop.rs | 39 ++++++------ src/ty/public/mod.rs | 2 + src/vm/mod.rs | 25 ++++---- 10 files changed, 154 insertions(+), 127 deletions(-) diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 374c359..75f3db2 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,7 +1,6 @@ -use std::cell::RefCell; use std::rc::Rc; -use crate::ty::internal::{_Thunk, Const, PrimOp, RecAttrSet, Thunk, Value}; +use crate::ty::internal::{Const, PrimOp, RecAttrSet, Value}; use crate::vm::{Env, VM}; pub fn env<'vm>(vm: &'vm VM) -> Rc> { @@ -45,17 +44,15 @@ pub fn env<'vm>(vm: &'vm VM) -> Rc> { let builtins_env = Rc::new(Env::empty()); let map = builtins_env.clone().new_rec(); for primop in primops { + let primop = Rc::new(primop); env.insert( vm.new_sym(format!("__{}", primop.name)), Value::PrimOp(primop.clone()), ); map.insert(vm.new_sym(primop.name), Value::PrimOp(primop)); } - let builtins = Value::RecAttrSet(RecAttrSet::from_inner(map.clone())); - let thunk = Thunk { - thunk: Rc::new(RefCell::new(_Thunk::Value(Box::new(builtins.clone())))), - }; - map.insert(vm.new_sym("builtins"), Value::Thunk(thunk)); + let builtins = Value::RecAttrSet(RecAttrSet::from_inner(map.clone()).into()); + map.insert(vm.new_sym("builtins"), builtins.clone()); env.insert(vm.new_sym("builtins"), builtins); env diff --git a/src/ir.rs b/src/ir.rs index 82f9b52..ed2203d 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -685,7 +685,7 @@ fn downgrade_inherit( }; for attr in inherit.attrs() { let ident = match downgrade_attr(attr, ctx)? { - Attr::Str(ident) => ctx.new_sym(ident.to_string()), + Attr::Str(ident) => ident, _ => { return Err(Error::DowngradeError( "dynamic attributes not allowed in inherit".to_string(), @@ -753,5 +753,9 @@ fn downgrade_attrpathvalue( ) -> Result<()> { let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?; let value = value.value().unwrap().downgrade(ctx)?; - attrs.insert(path, ctx.new_thunk(value).ir()) + let value = match value { + x @ Ir::Const(_) | x @ Ir::Var(_) => x, + x => ctx.new_thunk(x).ir() + }; + attrs.insert(path, value) } diff --git a/src/ty/common.rs b/src/ty/common.rs index 657fa34..055f481 100644 --- a/src/ty/common.rs +++ b/src/ty/common.rs @@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; use derive_more::Constructor; -#[derive(Clone, Debug, PartialEq, Constructor)] +#[derive(Clone, Debug, PartialEq, Constructor, Hash)] pub struct Catchable { msg: String, } diff --git a/src/ty/internal/attrset.rs b/src/ty/internal/attrset.rs index 9ca0b9f..d06ea2d 100644 --- a/src/ty/internal/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -1,4 +1,5 @@ use std::rc::Rc; +use std::collections::HashSet; use derive_more::Constructor; use rpds::HashTrieMap; @@ -6,7 +7,7 @@ use rpds::HashTrieMap; use crate::error::Result; use crate::vm::{Env, VM}; use super::super::public as p; -use super::{ToPublic, Value}; +use super::Value; #[repr(C)] #[derive(Debug, Constructor, Clone, PartialEq)] @@ -54,22 +55,16 @@ impl<'vm> AttrSet<'vm> { }) } - pub fn update(mut self, other: AttrSet<'vm>) -> AttrSet<'vm> { + pub fn update(&mut self, other: &AttrSet<'vm>) { for (k, v) in other.data.iter() { self.push_attr_force(k.clone(), v.clone()) } - self } - pub fn update_rec(mut self, other: RecAttrSet<'vm>) -> AttrSet<'vm> { + pub fn update_rec(&mut self, other: &RecAttrSet<'vm>) { for (k, v) in other.data.map.borrow().iter() { self.push_attr_force(k.clone(), v.clone()) } - self - } - - pub fn into_inner(self) -> HashTrieMap> { - self.data } pub fn as_inner(&self) -> &HashTrieMap> { @@ -82,21 +77,18 @@ impl<'vm> AttrSet<'vm> { .into_iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(); - map.iter_mut() - .map(|(_, v)| v.force_deep(vm).map(|_| ())) - .find(|v| v.is_err()) - .map_or(Ok(()), |err| err)?; + for (_, v) in map.iter_mut() { + v.force_deep(vm)?; + } self.data = map.into_iter().collect(); Ok(()) } -} -impl ToPublic for AttrSet<'_> { - fn to_public(self, vm: &VM) -> p::Value { + pub fn to_public(&self, vm: &'vm VM, seen: &mut HashSet>) -> p::Value { p::Value::AttrSet(p::AttrSet::new( self.data .iter() - .map(|(&sym, value)| (vm.get_sym(sym), value.clone().to_public(vm))) + .map(|(&sym, value)| (vm.get_sym(sym), value.clone().to_public(vm, seen))) .collect(), )) } @@ -133,14 +125,13 @@ impl<'vm> RecAttrSet<'vm> { self.data.lookup(sym).is_some() } - pub fn update(mut self, other: RecAttrSet<'vm>) -> RecAttrSet<'vm> { + pub fn update(&mut self, other: RecAttrSet<'vm>) { for (k, v) in other.data.map.borrow().iter() { self.push_attr_force(k.clone(), v.clone()) } - self } - pub fn update_normal(self, other: AttrSet<'vm>) -> AttrSet<'vm> { + pub fn update_normal(&self, other: &AttrSet<'vm>) -> AttrSet<'vm> { let map = self .data .map @@ -178,16 +169,14 @@ impl<'vm> RecAttrSet<'vm> { *self.data.map.borrow_mut() = map.into_iter().collect(); Ok(()) } -} -impl ToPublic for RecAttrSet<'_> { - fn to_public(self, vm: &VM) -> p::Value { + pub fn to_public(&self, vm: &'vm VM, seen: &mut HashSet>) -> p::Value { p::Value::AttrSet(p::AttrSet::new( self.data .map .borrow() .iter() - .map(|(&sym, value)| (vm.get_sym(sym), value.clone().to_public(vm))) + .map(|(&sym, value)| (vm.get_sym(sym), value.clone().to_public(vm, seen))) .collect(), )) } diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index 0910268..a305d0a 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -50,7 +50,7 @@ pub struct Func<'vm> { } impl<'vm> Func<'vm> { - pub fn call(self, vm: &'vm VM<'_>, arg: Value<'vm>) -> Result> { + pub fn call(&self, vm: &'vm VM<'_>, arg: Value<'vm>) -> Result> { use Param::*; let env = Rc::new(self.env.as_ref().clone()); @@ -78,7 +78,7 @@ impl<'vm> Func<'vm> { let formal = formal.clone().into(); let arg = arg .select(formal) - .or_else(|| default.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx))))) + .or_else(|| default.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx)).into()))) .unwrap(); new.insert_mut(formal, arg); } diff --git a/src/ty/internal/list.rs b/src/ty/internal/list.rs index 6f9cd5f..9dff84b 100644 --- a/src/ty/internal/list.rs +++ b/src/ty/internal/list.rs @@ -1,21 +1,23 @@ +use std::collections::HashSet; + use derive_more::Constructor; -use rpds::VectorSync; +use rpds::Vector; use crate::error::Result; use crate::ty::public as p; use crate::vm::VM; -use super::{ToPublic, Value}; +use super::Value; #[derive(Debug, Constructor, Clone, PartialEq)] pub struct List<'vm> { - data: VectorSync>, + data: Vector>, } impl<'vm> List<'vm> { pub fn empty() -> Self { List { - data: VectorSync::new_sync(), + data: Vector::new(), } } @@ -23,30 +25,26 @@ impl<'vm> List<'vm> { self.data.push_back_mut(elem); } - pub fn concat(mut self, other: List<'vm>) -> List<'vm> { + pub fn concat(&mut self, other: &List<'vm>) { for elem in other.data.iter() { self.data.push_back_mut(elem.clone()); } - self } pub fn force_deep(&mut self, vm: &'vm VM<'_>) -> Result<()> { let mut vec: Vec<_> = self.data.iter().cloned().collect(); - vec.iter_mut() - .map(|v| v.force_deep(vm).map(|_| ())) - .find(|v| v.is_err()) - .map_or(Ok(()), |err| err)?; + for v in vec.iter_mut() { + v.force_deep(vm)?; + } self.data = vec.into_iter().collect(); Ok(()) } -} -impl ToPublic for List<'_> { - fn to_public(self, vm: &VM) -> p::Value { + pub fn to_public(&self, vm: &'vm VM, seen: &mut HashSet>) -> p::Value { p::Value::List(p::List::new( self.data .iter() - .map(|value| value.clone().to_public(vm)) + .map(|value| value.clone().to_public(vm, seen)) .collect(), )) } diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index 718da3f..a425e89 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -1,5 +1,7 @@ use std::cell::OnceCell; use std::cell::RefCell; +use std::collections::HashSet; +use std::hash::Hash; use std::rc::Rc; use derive_more::{IsVariant, Unwrap}; @@ -27,17 +29,37 @@ pub use primop::*; #[derive(Debug, IsVariant, Unwrap, Clone, PartialEq)] pub enum Value<'vm> { Const(Const), - Thunk(Thunk<'vm>), + Thunk(Rc>), ThunkRef(&'vm Thunk<'vm>), - AttrSet(AttrSet<'vm>), - RecAttrSet(RecAttrSet<'vm>), - List(List<'vm>), + AttrSet(Rc>), + RecAttrSet(Rc>), + List(Rc>), Catchable(c::Catchable), - PrimOp(PrimOp<'vm>), - PartialPrimOp(PartialPrimOp<'vm>), - Func(Func<'vm>), + PrimOp(Rc>), + PartialPrimOp(Rc>), + Func(Rc>), } +impl Hash for Value<'_> { + fn hash(&self, state: &mut H) { + use Value::*; + match self { + Const(x) => x.hash(state), + Thunk(x) => (x.as_ref() as *const self::Thunk).hash(state), + ThunkRef(x) => (*x as *const self::Thunk).hash(state), + AttrSet(x) => (x.as_ref() as *const self::AttrSet).hash(state), + RecAttrSet(x) => (x.as_ref() as *const self::RecAttrSet).hash(state), + List(x) => (x.as_ref() as *const self::List).hash(state), + Catchable(x) => x.hash(state), + PrimOp(x) => (x.as_ref() as *const self::PrimOp).hash(state), + PartialPrimOp(x) => (x.as_ref() as *const self::PartialPrimOp).hash(state), + Func(x) => (x.as_ref() as *const self::Func).hash(state), + } + } +} + +impl Eq for Value<'_> {} + #[derive(Debug, IsVariant, Unwrap, Clone, PartialEq)] pub enum ValueAsRef<'v, 'vm: 'v> { Const(&'v Const), @@ -89,12 +111,12 @@ impl<'v, 'vm: 'v> Value<'vm> { Const(x) => M::Const(x), Thunk(x) => M::Thunk(x), ThunkRef(x) => M::Thunk(x), - AttrSet(x) => M::AttrSet(x), - RecAttrSet(x) => M::RecAttrSet(x), - List(x) => M::List(x), + AttrSet(x) => M::AttrSet(Rc::make_mut(x)), + RecAttrSet(x) => M::RecAttrSet(Rc::make_mut(x)), + List(x) => M::List(Rc::make_mut(x)), Catchable(x) => M::Catchable(x), - PrimOp(x) => M::PrimOp(x), - PartialPrimOp(x) => M::PartialPrimOp(x), + PrimOp(x) => M::PrimOp(Rc::make_mut(x)), + PartialPrimOp(x) => M::PartialPrimOp(Rc::make_mut(x)), Func(x) => M::Func(x), } } @@ -130,13 +152,14 @@ impl<'vm> Value<'vm> { } } - pub fn call(self, vm: &'vm VM<'_>, args: Vec) -> Result { + pub fn call(&self, vm: &'vm VM<'_>, args: Vec) -> Result { use Value::*; match self { PrimOp(func) => func.call(vm, args), PartialPrimOp(func) => func.call(vm, args), - mut func @ Value::Func(_) => { + func @ Value::Func(_) => { let mut iter = args.into_iter(); + let mut func = func.clone(); while let Some(arg) = iter.next() { func = match func { PrimOp(func) => { @@ -151,7 +174,7 @@ impl<'vm> Value<'vm> { } func.ok() } - x @ Catchable(_) => x.ok(), + x @ Catchable(_) => x.clone().ok(), _ => todo!(), } } @@ -247,7 +270,10 @@ impl<'vm> Value<'vm> { use Const::*; Ok(match (self, other) { (_, VmConst(Int(0))) => return Err(Error::EvalError("division by zero".to_string())), - (_, VmConst(Float(0.))) => return Err(Error::EvalError("division by zero".to_string())), (VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a / b)), + (_, VmConst(Float(0.))) => { + return Err(Error::EvalError("division by zero".to_string())); + } + (VmConst(Int(a)), VmConst(Int(b))) => VmConst(Int(a / b)), (VmConst(Int(a)), VmConst(Float(b))) => VmConst(Float(a as f64 / b)), (VmConst(Float(a)), VmConst(Int(b))) => VmConst(Float(a / b as f64)), (VmConst(Float(a)), VmConst(Float(b))) => VmConst(Float(a / b)), @@ -268,7 +294,7 @@ impl<'vm> Value<'vm> { pub fn push(&mut self, elem: Self) -> &mut Self { if let Value::List(list) = self { - list.push(elem); + Rc::make_mut(list).push(elem); } else if let Value::Catchable(_) = self { } else if let Value::Catchable(_) = elem { *self = elem; @@ -280,7 +306,10 @@ impl<'vm> Value<'vm> { pub fn concat(self, other: Self) -> Self { match (self, other) { - (Value::List(a), Value::List(b)) => Value::List(a.concat(b)), + (Value::List(mut a), Value::List(b)) => { + Rc::make_mut(&mut a).concat(b.as_ref()); + Value::List(a) + } (x @ Value::Catchable(_), _) | (_, x @ Value::Catchable(_)) => x, _ => todo!(), } @@ -288,9 +317,9 @@ impl<'vm> Value<'vm> { pub fn push_attr(&mut self, sym: usize, val: Self) -> &mut Self { if let Value::AttrSet(attrs) = self { - attrs.push_attr(sym, val) + Rc::make_mut(attrs).push_attr(sym, val) } else if let Value::RecAttrSet(attrs) = self { - attrs.push_attr(sym, val) + Rc::make_mut(attrs).push_attr(sym, val) } else if let Value::Catchable(_) = self { } else if let Value::Catchable(_) = val { *self = val @@ -302,22 +331,30 @@ impl<'vm> Value<'vm> { pub fn update(self, other: Self) -> Self { match (self, other) { - (Value::AttrSet(a), Value::AttrSet(b)) => Value::AttrSet(a.update(b)), - (Value::RecAttrSet(a), Value::AttrSet(b)) => Value::AttrSet(a.update_normal(b)), - (Value::AttrSet(a), Value::RecAttrSet(b)) => Value::AttrSet(a.update_rec(b)), + (Value::AttrSet(mut a), Value::AttrSet(b)) => { + Rc::make_mut(&mut a).update(b.as_ref()); + Value::AttrSet(a) + } + (Value::RecAttrSet(a), Value::AttrSet(b)) => { + Value::AttrSet(a.update_normal(b.as_ref()).into()) + } + (Value::AttrSet(mut a), Value::RecAttrSet(b)) => { + Rc::make_mut(&mut a).update_rec(b.as_ref()); + Value::AttrSet(a) + } (x @ Value::Catchable(_), _) | (_, x @ Value::Catchable(_)) => x, _ => todo!(), } } - pub fn select(&mut self, sym: usize) -> Result<&mut Self> { + pub fn select(&mut self, sym: usize, vm: &'vm VM<'_>) -> Result<&mut Self> { let val = match self { Value::AttrSet(attrs) => attrs .select(sym) - .ok_or_else(|| Error::EvalError(format!("{sym:?} not found"))), + .ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym)))), Value::RecAttrSet(attrs) => attrs .select(sym) - .ok_or_else(|| Error::EvalError(format!("{sym:?} not found"))), + .ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym)))), Value::Catchable(_) => return Ok(self), _ => Err(Error::EvalError(format!( "cannot select from {:?}", @@ -390,23 +427,25 @@ impl<'vm> Value<'vm> { let _ = value.force_deep(vm)?; *self = value; } - Value::List(list) => list.force_deep(vm)?, - Value::AttrSet(attrs) => attrs.force_deep(vm)?, - Value::RecAttrSet(attrs) => attrs.force_deep(vm)?, + Value::List(list) => Rc::make_mut(list).force_deep(vm)?, + Value::AttrSet(attrs) => Rc::make_mut(attrs).force_deep(vm)?, + Value::RecAttrSet(attrs) => Rc::make_mut(attrs).force_deep(vm)?, _ => (), } Ok(self) } -} -impl ToPublic for Value<'_> { - fn to_public(self, vm: &VM) -> p::Value { + pub fn to_public(&self, vm: &'vm VM, seen: &mut HashSet>) -> p::Value { + if seen.contains(self) { + return p::Value::Repeated; + } + seen.insert(self.clone()); match self { - Value::AttrSet(attrs) => attrs.to_public(vm), - Value::RecAttrSet(attrs) => attrs.to_public(vm), - Value::List(list) => list.to_public(vm), - Value::Catchable(catchable) => p::Value::Catchable(catchable), - Value::Const(cnst) => p::Value::Const(cnst.into()), + Value::AttrSet(attrs) => attrs.to_public(vm, seen), + Value::RecAttrSet(attrs) => attrs.to_public(vm, seen), + Value::List(list) => list.to_public(vm, seen), + Value::Catchable(catchable) => p::Value::Catchable(catchable.clone()), + Value::Const(cnst) => p::Value::Const(cnst.clone().into()), Value::Thunk(_) => p::Value::Thunk, Value::ThunkRef(_) => p::Value::Thunk, Value::PrimOp(primop) => p::Value::PrimOp(primop.name), @@ -416,26 +455,22 @@ impl ToPublic for Value<'_> { } } -pub trait ToPublic { - fn to_public(self, vm: &VM) -> p::Value; -} - #[derive(Debug, Clone)] pub struct Thunk<'vm> { - pub thunk: Rc>>, + pub thunk: RefCell<_Thunk<'vm>>, } #[derive(Debug, IsVariant, Unwrap, Clone)] pub enum _Thunk<'vm> { Code(&'vm OpCodes, OnceCell>>), SuspendedFrom(*const Thunk<'vm>), - Value(Box>), + Value(Value<'vm>), } impl<'vm> Thunk<'vm> { pub fn new(opcodes: &'vm OpCodes) -> Self { Thunk { - thunk: Rc::new(RefCell::new(_Thunk::Code(opcodes, OnceCell::new()))), + thunk: RefCell::new(_Thunk::Code(opcodes, OnceCell::new())), } } @@ -447,7 +482,7 @@ impl<'vm> Thunk<'vm> { pub fn force(&self, vm: &'vm VM<'_>) -> Result> { match &*self.thunk.borrow() { - _Thunk::Value(value) => return Ok(value.as_ref().clone()), + _Thunk::Value(value) => return Ok(value.clone()), _Thunk::SuspendedFrom(from) => { return Err(Error::EvalError(format!( "thunk {:p} already suspended from {from:p} (infinite recursion encountered)", @@ -471,7 +506,7 @@ impl<'vm> Thunk<'vm> { pub fn value(&'vm self) -> Option> { match &*self.thunk.borrow() { - _Thunk::Value(value) => Some(value.as_ref().clone()), + _Thunk::Value(value) => Some(value.clone()), _ => None, } } diff --git a/src/ty/internal/primop.rs b/src/ty/internal/primop.rs index e16e740..1ed4d90 100644 --- a/src/ty/internal/primop.rs +++ b/src/ty/internal/primop.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use derive_more::Constructor; use crate::vm::VM; @@ -8,7 +10,7 @@ use super::Value; #[derive(Debug, Clone, Constructor)] pub struct PrimOp<'vm> { pub name: &'static str, - arity: u8, + arity: usize, func: fn(&'vm VM<'_>, Vec>) -> Result>, } @@ -19,15 +21,15 @@ impl PartialEq for PrimOp<'_> { } impl<'vm> PrimOp<'vm> { - pub fn call(self, vm: &'vm VM<'_>, args: Vec>) -> Result> { - if (args.len() as u8) < self.arity { + pub fn call(&self, vm: &'vm VM<'_>, args: Vec>) -> Result> { + if (args.len()) < self.arity { Value::PartialPrimOp(PartialPrimOp { name: self.name, - arity: self.arity - args.len() as u8, + arity: self.arity - args.len(), args, func: self.func, - }).ok() - } else if args.len() as u8 == self.arity { + }.into()).ok() + } else if args.len() == self.arity { (self.func)(vm, args) } else { unimplemented!() @@ -38,7 +40,7 @@ impl<'vm> PrimOp<'vm> { #[derive(Debug, Clone)] pub struct PartialPrimOp<'vm> { pub name: &'static str, - arity: u8, + arity: usize, args: Vec>, func: fn(&'vm VM<'_>, Vec>) -> Result>, } @@ -50,18 +52,17 @@ impl PartialEq for PartialPrimOp<'_> { } impl<'vm> PartialPrimOp<'vm> { - pub fn call(mut self, vm: &'vm VM<'_>, args: Vec>) -> Result> { - let len = args.len() as u8; - self.args.extend(args); - if len < self.arity { - Value::PartialPrimOp(PartialPrimOp { - name: self.name, - arity: self.arity - len, - args: self.args, - func: self.func, - }).ok() - } else if len == self.arity { - (self.func)(vm, self.args) + pub fn call(self: &Rc, vm: &'vm VM<'_>, args: Vec>) -> Result> { + let len = args.len(); + let mut self_clone = self.clone(); + let self_mut = Rc::make_mut(&mut self_clone); + self_mut.args.extend(args); + self_mut.arity -= len; + if self_mut.arity > 0 { + Value::PartialPrimOp(self_clone).ok() + } else if self_mut.arity == 0 { + let args = std::mem::replace(&mut self_mut.args, Vec::new()); + (self.func)(vm, args) } else { unimplemented!() } diff --git a/src/ty/public/mod.rs b/src/ty/public/mod.rs index d328f0c..ef183a5 100644 --- a/src/ty/public/mod.rs +++ b/src/ty/public/mod.rs @@ -112,6 +112,7 @@ pub enum Value { Func, PrimOp(&'static str), PartialPrimOp(&'static str), + Repeated } impl Display for Value { @@ -126,6 +127,7 @@ impl Display for Value { Func => write!(f, ""), PrimOp(x) => write!(f, ""), PartialPrimOp(x) => write!(f, ""), + Repeated => write!(f, "") } } } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index d549329..63cca5d 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::pin::Pin; use std::rc::Rc; @@ -34,9 +34,9 @@ pub fn run(prog: Program, jit: Pin>>) -> Result { jit ); let env = env(&vm); - let temp = vm.eval(prog.top_level.into_iter(), env)?; - let temp = temp.to_public(&vm); - Ok(temp) + let mut seen = HashSet::new(); + let value = vm.eval(prog.top_level.into_iter(), env)?.to_public(&vm, &mut seen); + Ok(value) } #[derive(Constructor)] @@ -99,7 +99,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { OpCode::Illegal => panic!("illegal opcode"), OpCode::Const { idx } => stack.push(Value::Const(self.consts[idx].clone()))?, OpCode::LoadThunk { idx } => { - stack.push(Value::Thunk(Thunk::new(self.get_thunk(idx))))? + stack.push(Value::Thunk(Thunk::new(self.get_thunk(idx)).into()))? } OpCode::CaptureEnv => { match stack.tos()? { @@ -132,7 +132,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { } OpCode::Func { idx } => { let func = self.get_func(idx); - stack.push(Value::Func(Func::new(func, env.clone(), None)))?; + stack.push(Value::Func(Func::new(func, env.clone(), None).into()))?; } OpCode::UnOp { op } => { use UnOp::*; @@ -171,17 +171,17 @@ impl<'vm, 'jit: 'vm> VM<'jit> { todo!() } OpCode::List => { - stack.push(Value::List(List::empty()))?; + stack.push(Value::List(List::empty().into()))?; } OpCode::PushElem => { let elem = stack.pop(); stack.tos_mut()?.push(elem); } OpCode::AttrSet => { - stack.push(Value::AttrSet(AttrSet::empty()))?; + stack.push(Value::AttrSet(AttrSet::empty().into()))?; } OpCode::FinalizeRec => { - env.enter(stack.tos()?.clone().unwrap_attr_set().into_inner()); + env.enter(stack.tos()?.clone().unwrap_attr_set().as_inner().clone()); stack .tos_mut()? .as_mut() @@ -200,7 +200,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { stack.tos_mut()?.push_attr(sym, val); } OpCode::Select { sym } => { - stack.tos_mut()?.force(self)?.select(sym)?; + stack.tos_mut()?.force(self)?.select(sym, self)?; } OpCode::SelectOrDefault { sym } => { let default = stack.pop(); @@ -214,7 +214,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { val.force(self)?; val.coerce_to_string(); let sym = self.new_sym(val.unwrap_const().unwrap_string()); - stack.tos_mut()?.force(self)?.select(sym)?; + stack.tos_mut()?.force(self)?.select(sym, self)?; } OpCode::SelectDynamicOrDefault => { let default = stack.pop(); @@ -243,7 +243,8 @@ impl<'vm, 'jit: 'vm> VM<'jit> { )?; } OpCode::EnterEnv => match stack.pop() { - Value::AttrSet(attrs) => env.enter(attrs.into_inner()), + Value::AttrSet(attrs) => env.enter(attrs.as_inner().clone()), + _ => unreachable!(), }, OpCode::LeaveEnv => {