From ff9afd0cc18e9292c30ad807b01553b0cf678f57 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 17 May 2025 18:31:36 +0800 Subject: [PATCH] feat: better builtins implementaion get rid of circular references --- flake.nix | 1 + src/bin/repl.rs | 13 ++-- src/builtins/mod.rs | 14 ++-- src/bytecode.rs | 2 +- src/compile.rs | 2 +- src/ir.rs | 14 ++-- src/lib.rs | 3 +- src/ty/common.rs | 2 - src/ty/internal/attrset.rs | 130 +++++++------------------------------ src/ty/internal/cnst.rs | 4 +- src/ty/internal/func.rs | 23 ++++--- src/ty/internal/mod.rs | 80 ++++++++++++----------- src/ty/internal/primop.rs | 18 +++-- src/ty/public/cnst.rs | 6 +- src/ty/public/mod.rs | 6 +- src/vm/env.rs | 31 +++++---- src/vm/jit.rs | 19 +++--- src/vm/mod.rs | 57 +++++++++------- src/vm/test.rs | 10 +-- 19 files changed, 191 insertions(+), 244 deletions(-) diff --git a/flake.nix b/flake.nix index 4233d1e..18f6f42 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,7 @@ "rustc" "rustfmt" "rust-analyzer" + "miri" ]) llvm_18 libffi diff --git a/src/bin/repl.rs b/src/bin/repl.rs index b4229e5..6e3cf57 100644 --- a/src/bin/repl.rs +++ b/src/bin/repl.rs @@ -1,12 +1,12 @@ -use itertools::Itertools; use inkwell::context::Context; +use itertools::Itertools; use rustyline::error::ReadlineError; use rustyline::{DefaultEditor, Result}; use nixjit::compile::compile; -use nixjit::ir::downgrade; -use nixjit::vm::{run, JITContext}; use nixjit::error::Error; +use nixjit::ir::downgrade; +use nixjit::vm::{JITContext, run}; macro_rules! unwrap { ($e:expr) => { @@ -32,7 +32,12 @@ fn main() -> Result<()> { rl.add_history_entry(expr.as_str())?; let root = rnix::Root::parse(&expr); if !root.errors().is_empty() { - println!("{}", Error::ParseError(root.errors().iter().map(|err| err.to_string()).join(";"))); + println!( + "{}", + Error::ParseError( + root.errors().iter().map(|err| err.to_string()).join(";") + ) + ); continue; } let expr = root.tree().expr().unwrap(); diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 75f3db2..e391317 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,6 +1,8 @@ use std::rc::Rc; -use crate::ty::internal::{Const, PrimOp, RecAttrSet, Value}; +use rpds::HashTrieMap; + +use crate::ty::internal::{AttrSet, Const, PrimOp, Value}; use crate::vm::{Env, VM}; pub fn env<'vm>(vm: &'vm VM) -> Rc> { @@ -41,18 +43,18 @@ pub fn env<'vm>(vm: &'vm VM) -> Rc> { }), ]; - let builtins_env = Rc::new(Env::empty()); - let map = builtins_env.clone().new_rec(); + let mut map = HashTrieMap::new(); 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)); + map.insert_mut(vm.new_sym(primop.name), Value::PrimOp(primop)); } - let builtins = Value::RecAttrSet(RecAttrSet::from_inner(map.clone()).into()); - map.insert(vm.new_sym("builtins"), builtins.clone()); + let attrs: Rc<_> = AttrSet::from_inner(map).into(); + let mut builtins = Value::AttrSet(attrs); + builtins.push_attr(vm.new_sym("builtins"), Value::Builtins); env.insert(vm.new_sym("builtins"), builtins); env diff --git a/src/bytecode.rs b/src/bytecode.rs index 45c1bfe..5dd06be 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -114,5 +114,5 @@ pub struct Program { pub funcs: Slice, pub symbols: Vec, pub symmap: HashMap, - pub consts: Box<[Const]> + pub consts: Box<[Const]>, } diff --git a/src/compile.rs b/src/compile.rs index d833972..1000701 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -23,7 +23,7 @@ pub fn compile(downgraded: ir::Downgraded) -> Program { .collect(), symbols: downgraded.symbols, symmap: downgraded.symmap, - consts: downgraded.consts + consts: downgraded.consts, } } diff --git a/src/ir.rs b/src/ir.rs index ed2203d..39727f3 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -164,7 +164,9 @@ impl DowngradeContext { } else { self.constmap.insert(cnst.clone(), self.consts.len()); self.consts.push(cnst); - Const { idx: self.consts.len() - 1 } + Const { + idx: self.consts.len() - 1, + } } } @@ -425,9 +427,7 @@ impl Downgrade for ast::Path { let parts = self .parts() .map(|part| match part { - ast::InterpolPart::Literal(lit) => ctx.new_const(lit.to_string().into()) - .ir() - .ok(), + ast::InterpolPart::Literal(lit) => ctx.new_const(lit.to_string().into()).ir().ok(), ast::InterpolPart::Interpolation(interpol) => { interpol.expr().unwrap().downgrade(ctx) } @@ -472,7 +472,7 @@ impl Downgrade for ast::Literal { match self.kind() { ast::LiteralKind::Integer(int) => ctx.new_const(int.value().unwrap().into()), ast::LiteralKind::Float(float) => ctx.new_const(float.value().unwrap().into()), - ast::LiteralKind::Uri(uri) => ctx.new_const(uri.to_string().into()) + ast::LiteralKind::Uri(uri) => ctx.new_const(uri.to_string().into()), } .ir() .ok() @@ -754,8 +754,8 @@ fn downgrade_attrpathvalue( let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?; let value = value.value().unwrap().downgrade(ctx)?; let value = match value { - x @ Ir::Const(_) | x @ Ir::Var(_) => x, - x => ctx.new_thunk(x).ir() + x @ Ir::Const(_) => x, + x => ctx.new_thunk(x).ir(), }; attrs.insert(path, value) } diff --git a/src/lib.rs b/src/lib.rs index 6d3dc87..e03e267 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,10 @@ #![cfg_attr(test, feature(test))] - #![allow(dead_code)] mod builtins; mod bytecode; -mod ty; mod stack; +mod ty; pub mod compile; pub mod error; diff --git a/src/ty/common.rs b/src/ty/common.rs index 055f481..c958fe7 100644 --- a/src/ty/common.rs +++ b/src/ty/common.rs @@ -2,7 +2,6 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; use derive_more::Constructor; - #[derive(Clone, Debug, PartialEq, Constructor, Hash)] pub struct Catchable { msg: String, @@ -13,4 +12,3 @@ impl Display for Catchable { write!(f, "", self.msg) } } - diff --git a/src/ty/internal/attrset.rs b/src/ty/internal/attrset.rs index d06ea2d..121ac20 100644 --- a/src/ty/internal/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -1,11 +1,13 @@ -use std::rc::Rc; use std::collections::HashSet; +use std::rc::Rc; use derive_more::Constructor; +use itertools::Itertools; use rpds::HashTrieMap; use crate::error::Result; use crate::vm::{Env, VM}; + use super::super::public as p; use super::Value; @@ -27,7 +29,7 @@ impl<'vm> AttrSet<'vm> { } pub fn push_attr(&mut self, sym: usize, val: Value<'vm>) { - if self.data.get_mut(&sym).is_some() { + if self.data.get(&sym).is_some() { todo!() } self.data.insert_mut(sym, val); @@ -42,17 +44,12 @@ impl<'vm> AttrSet<'vm> { } pub fn capture(&mut self, env: &Rc>) { - self - .data - .iter() - .for_each(|(_, v)| { - match v.clone() { - Value::Thunk(ref thunk) => { - thunk.capture(env.clone()); - } - _ => () - } - }) + self.data.iter().for_each(|(_, v)| match v.clone() { + Value::Thunk(ref thunk) => { + thunk.capture(env.clone()); + } + _ => (), + }) } pub fn update(&mut self, other: &AttrSet<'vm>) { @@ -61,20 +58,18 @@ impl<'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()) - } - } - pub fn as_inner(&self) -> &HashTrieMap> { &self.data } + pub fn from_inner(data: HashTrieMap>) -> Self { + Self { data } + } + pub fn force_deep(&mut self, vm: &'vm VM<'_>) -> Result<()> { let mut map: Vec<_> = self .data - .into_iter() + .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(); for (_, v) in map.iter_mut() { @@ -84,99 +79,20 @@ impl<'vm> AttrSet<'vm> { Ok(()) } - 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, seen))) - .collect(), - )) - } -} - -#[derive(Debug, Constructor, Clone, PartialEq)] -pub struct RecAttrSet<'vm> { - data: Rc>, -} - -impl<'vm> RecAttrSet<'vm> { - pub fn empty() -> Self { - RecAttrSet { - data: Rc::default(), - } - } - - pub fn push_attr_force(&mut self, sym: usize, val: Value<'vm>) { - self.data.insert(sym, val); - } - - pub fn push_attr(&mut self, sym: usize, val: Value<'vm>) { - if self.data.lookup(sym).is_some() { - todo!() - } - self.data.insert(sym, val); - } - - pub fn select(&self, sym: usize) -> Option> { - self.data.lookup(sym) - } - - pub fn has_attr(&self, sym: usize) -> bool { - self.data.lookup(sym).is_some() - } - - 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()) - } - } - - pub fn update_normal(&self, other: &AttrSet<'vm>) -> AttrSet<'vm> { - let map = self - .data - .map - .borrow() - .into_iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(); - let mut new = AttrSet::new(map); - for (k, v) in other.data.iter() { - new.push_attr_force(k.clone(), v.clone()) - } - new - } - - pub fn into_inner(self) -> Rc> { - self.data - } - - pub fn from_inner(data: Rc>) -> Self { - RecAttrSet { data } - } - - pub fn force_deep(&mut self, vm: &'vm VM<'_>) -> Result<()> { - let mut map: Vec<_> = self - .data - .map - .borrow() - .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)?; - *self.data.map.borrow_mut() = map.into_iter().collect(); - Ok(()) + pub fn eq_impl(&self, other: &AttrSet<'vm>, vm: &'vm VM<'_>) -> bool { + self.data.iter().len() == other.data.iter().len() + && std::iter::zip( + self.data.iter().sorted_by_key(|(k, _)| **k), + self.data.iter().sorted_by_key(|(k, _)| **k), + ) + .all(|((_, v1), (_, v2))| v1.eq_impl(v2, vm)) } 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, seen))) + .map(|(&sym, value)| (vm.get_sym(sym), value.to_public(vm, seen))) .collect(), )) } diff --git a/src/ty/internal/cnst.rs b/src/ty/internal/cnst.rs index e47b183..e2ff5ac 100644 --- a/src/ty/internal/cnst.rs +++ b/src/ty/internal/cnst.rs @@ -9,7 +9,7 @@ pub enum Const { Int(i64), Float(f64), String(EcoString), - Null + Null, } impl Hash for Const { @@ -68,6 +68,8 @@ impl PartialEq for Const { (Bool(a), Bool(b)) => a == b, (Int(a), Int(b)) => a == b, (Float(a), Float(b)) => a == b, + (Int(a), Float(b)) => *a as f64 == *b, + (Float(a), Int(b)) => *b as f64 == *a, (String(a), String(b)) => a == b, _ => false, } diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index a305d0a..fa003f7 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -1,8 +1,8 @@ +use std::collections::HashMap; use std::rc::Rc; -use itertools::Itertools; -use rpds::HashTrieMap; use derive_more::Constructor; +use itertools::Itertools; use crate::bytecode::Func as BFunc; use crate::error::Result; @@ -40,13 +40,14 @@ impl From for Param { } } -pub type JITFunc<'vm> = unsafe extern "C" fn(vm: *mut VM<'_>, *mut Env<'vm>, *mut Value<'vm>) -> Value<'vm>; +pub type JITFunc<'vm> = + unsafe extern "C" fn(vm: *mut VM<'_>, *mut Env<'vm>, *mut Value<'vm>) -> Value<'vm>; #[derive(Debug, Clone, Constructor)] pub struct Func<'vm> { pub func: &'vm BFunc, pub env: Rc>, - pub compiled: Option> + pub compiled: Option>, } impl<'vm> Func<'vm> { @@ -56,14 +57,14 @@ impl<'vm> Func<'vm> { let env = Rc::new(self.env.as_ref().clone()); match self.func.param.clone() { - Ident(ident) => env.enter(HashTrieMap::new().insert(ident.into(), arg)), + Ident(ident) => env.enter([(ident.into(), arg)].into_iter()), Formals { formals, ellipsis, alias, } => { let arg = arg.unwrap_attr_set(); - let mut new = HashTrieMap::new(); + let mut new = Vec::with_capacity(formals.len() + alias.iter().len()); if !ellipsis && arg .as_inner() @@ -78,14 +79,16 @@ 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)).into()))) + .or_else(|| { + default.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx)).into())) + }) .unwrap(); - new.insert_mut(formal, arg); + new.push((formal, arg)); } if let Some(alias) = alias { - new.insert_mut(alias.clone().into(), Value::AttrSet(arg)); + new.push((alias.clone().into(), Value::AttrSet(arg))); } - env.enter(new); + env.enter(new.into_iter()); } } diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index a425e89..98fbe0c 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -32,28 +32,43 @@ pub enum Value<'vm> { Thunk(Rc>), ThunkRef(&'vm Thunk<'vm>), AttrSet(Rc>), - RecAttrSet(Rc>), List(Rc>), Catchable(c::Catchable), PrimOp(Rc>), PartialPrimOp(Rc>), Func(Rc>), + Builtins, } impl Hash for Value<'_> { fn hash(&self, state: &mut H) { use Value::*; + std::mem::discriminant(self).hash(state); 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), + Builtins => (), + } + } +} + +impl<'vm> Value<'vm> { + fn eq_impl(&self, other: &Self, vm: &'vm VM<'_>) -> bool { + use Value::*; + match (self, other) { + (Const(a), Const(b)) => a.eq(b), + (AttrSet(a), AttrSet(b)) => a.eq_impl(b, vm), + (List(a), List(b)) => a.eq(b), + (Builtins, AttrSet(attrs)) => attrs.has_attr(vm.new_sym("builtins")), + (AttrSet(attrs), Builtins) => attrs.has_attr(vm.new_sym("builtins")), + _ => false, } } } @@ -65,7 +80,6 @@ pub enum ValueAsRef<'v, 'vm: 'v> { Const(&'v Const), Thunk(&'v Thunk<'vm>), AttrSet(&'v AttrSet<'vm>), - RecAttrSet(&'v RecAttrSet<'vm>), List(&'v List<'vm>), Catchable(&'v c::Catchable), PrimOp(&'v PrimOp<'vm>), @@ -78,7 +92,6 @@ pub enum ValueAsMut<'v, 'vm: 'v> { Const(&'v mut Const), Thunk(&'v Thunk<'vm>), AttrSet(&'v mut AttrSet<'vm>), - RecAttrSet(&'v mut RecAttrSet<'vm>), List(&'v mut List<'vm>), Catchable(&'v mut c::Catchable), PrimOp(&'v mut PrimOp<'vm>), @@ -95,12 +108,12 @@ impl<'v, 'vm: 'v> Value<'vm> { Thunk(x) => R::Thunk(x), ThunkRef(x) => R::Thunk(x), AttrSet(x) => R::AttrSet(x), - RecAttrSet(x) => R::RecAttrSet(x), List(x) => R::List(x), Catchable(x) => R::Catchable(x), PrimOp(x) => R::PrimOp(x), PartialPrimOp(x) => R::PartialPrimOp(x), Func(x) => R::Func(x), + Builtins => unreachable!(), } } @@ -112,12 +125,12 @@ impl<'v, 'vm: 'v> Value<'vm> { Thunk(x) => M::Thunk(x), ThunkRef(x) => M::Thunk(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(Rc::make_mut(x)), PartialPrimOp(x) => M::PartialPrimOp(Rc::make_mut(x)), Func(x) => M::Func(x), + Builtins => unreachable!(), } } } @@ -135,19 +148,19 @@ impl<'vm> Value<'vm> { Thunk(_) => "thunk", ThunkRef(_) => "thunk", AttrSet(_) => "set", - RecAttrSet(_) => "set", List(_) => "list", Catchable(_) => unreachable!(), PrimOp(_) => "lambda", PartialPrimOp(_) => "lambda", Func(_) => "lambda", + Builtins => "set", } } pub fn callable(&self) -> bool { match self { Value::PrimOp(_) | Value::PartialPrimOp(_) | Value::Func(_) => true, - Value::AttrSet(_) | Value::RecAttrSet(_) => todo!(), + Value::AttrSet(_) => todo!(), _ => false, } } @@ -318,8 +331,6 @@ impl<'vm> Value<'vm> { pub fn push_attr(&mut self, sym: usize, val: Self) -> &mut Self { if let Value::AttrSet(attrs) = self { Rc::make_mut(attrs).push_attr(sym, val) - } else if let Value::RecAttrSet(attrs) = self { - Rc::make_mut(attrs).push_attr(sym, val) } else if let Value::Catchable(_) = self { } else if let Value::Catchable(_) = val { *self = val @@ -335,13 +346,6 @@ impl<'vm> Value<'vm> { 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!(), } @@ -352,23 +356,22 @@ impl<'vm> Value<'vm> { Value::AttrSet(attrs) => attrs .select(sym) .ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym)))), - Value::RecAttrSet(attrs) => attrs - .select(sym) - .ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym)))), Value::Catchable(_) => return Ok(self), _ => Err(Error::EvalError(format!( "cannot select from {:?}", self.typename() ))), }?; - *self = val; + if let Value::Builtins = val { + } else { + *self = val; + } Ok(self) } pub fn select_with_default(&mut self, sym: usize, default: Self) -> Result<&mut Self> { let val = match self { Value::AttrSet(attrs) => attrs.select(sym).unwrap_or(default), - Value::RecAttrSet(attrs) => attrs.select(sym).unwrap_or(default), Value::Catchable(_) => return Ok(self), _ => { return Err(Error::EvalError(format!( @@ -377,7 +380,10 @@ impl<'vm> Value<'vm> { ))); } }; - *self = val; + if let Value::Builtins = val { + } else { + *self = val; + } Ok(self) } @@ -385,9 +391,6 @@ impl<'vm> Value<'vm> { if let Value::AttrSet(attrs) = self { let val = VmConst(Const::Bool(attrs.has_attr(sym))); *self = val; - } else if let Value::RecAttrSet(attrs) = self { - let val = VmConst(Const::Bool(attrs.has_attr(sym))); - *self = val; } else if let Value::Catchable(_) = self { } else { *self = VmConst(Const::Bool(false)); @@ -429,28 +432,29 @@ impl<'vm> Value<'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) } pub fn to_public(&self, vm: &'vm VM, seen: &mut HashSet>) -> p::Value { + use self::Value::*; + use p::Value; if seen.contains(self) { - return p::Value::Repeated; + return Value::Repeated; } seen.insert(self.clone()); match self { - 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), - Value::PartialPrimOp(primop) => p::Value::PartialPrimOp(primop.name), - Value::Func(_) => p::Value::Func, + AttrSet(attrs) => attrs.to_public(vm, seen), + List(list) => list.to_public(vm, seen), + Catchable(catchable) => Value::Catchable(catchable.clone()), + Const(cnst) => Value::Const(cnst.clone().into()), + Thunk(_) => Value::Thunk, + ThunkRef(_) => Value::Thunk, + PrimOp(primop) => Value::PrimOp(primop.name), + PartialPrimOp(primop) => Value::PartialPrimOp(primop.name), + Func(_) => Value::Func, + Builtins => Value::Repeated, } } } diff --git a/src/ty/internal/primop.rs b/src/ty/internal/primop.rs index 1ed4d90..c3041dc 100644 --- a/src/ty/internal/primop.rs +++ b/src/ty/internal/primop.rs @@ -2,8 +2,8 @@ use std::rc::Rc; use derive_more::Constructor; -use crate::vm::VM; use crate::error::Result; +use crate::vm::VM; use super::Value; @@ -23,12 +23,16 @@ impl PartialEq for PrimOp<'_> { impl<'vm> PrimOp<'vm> { 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(), - args, - func: self.func, - }.into()).ok() + Value::PartialPrimOp( + PartialPrimOp { + name: self.name, + arity: self.arity - args.len(), + args, + func: self.func, + } + .into(), + ) + .ok() } else if args.len() == self.arity { (self.func)(vm, args) } else { diff --git a/src/ty/public/cnst.rs b/src/ty/public/cnst.rs index f376b00..d5ceca6 100644 --- a/src/ty/public/cnst.rs +++ b/src/ty/public/cnst.rs @@ -13,7 +13,7 @@ pub enum Const { Int(i64), Float(f64), String(EcoString), - Null + Null, } impl Display for Const { @@ -24,7 +24,7 @@ impl Display for Const { Int(i) => write!(f, "{i}"), Float(float) => write!(f, "{float}"), String(s) => write!(f, "{s}"), - Null => write!(f, "null") + Null => write!(f, "null"), } } } @@ -37,7 +37,7 @@ impl From for Const { Int(int) => Const::Int(int), Float(float) => Const::Float(float), String(string) => Const::String(string), - Null => Const::Null + Null => Const::Null, } } } diff --git a/src/ty/public/mod.rs b/src/ty/public/mod.rs index ef183a5..83c6b27 100644 --- a/src/ty/public/mod.rs +++ b/src/ty/public/mod.rs @@ -3,9 +3,9 @@ use std::ops::Deref; use std::sync::LazyLock; use derive_more::{Constructor, IsVariant, Unwrap}; -use rpds::{HashTrieMap, VectorSync}; use ecow::EcoString; use regex::Regex; +use rpds::{HashTrieMap, VectorSync}; use super::common::*; @@ -112,7 +112,7 @@ pub enum Value { Func, PrimOp(&'static str), PartialPrimOp(&'static str), - Repeated + Repeated, } impl Display for Value { @@ -127,7 +127,7 @@ impl Display for Value { Func => write!(f, ""), PrimOp(x) => write!(f, ""), PartialPrimOp(x) => write!(f, ""), - Repeated => write!(f, "") + Repeated => write!(f, ""), } } } diff --git a/src/vm/env.rs b/src/vm/env.rs index 747df11..03f8857 100644 --- a/src/vm/env.rs +++ b/src/vm/env.rs @@ -3,12 +3,12 @@ use std::rc::Rc; use rpds::HashTrieMap; -use crate::ty::internal::Value; +use crate::ty::internal::{AttrSet, Value}; -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, Default)] pub struct Env<'vm> { last: RefCell>>>, - pub map: RefCell>>, + map: RefCell>>, } impl Clone for Env<'_> { @@ -38,10 +38,10 @@ impl<'vm> Env<'vm> { self.map.borrow_mut().insert_mut(symbol, value); } - pub fn enter(&self, new: HashTrieMap>) { + pub fn enter(&self, new: impl Iterator)>) { let mut map = self.map.borrow().clone(); - for (k, v) in new.iter() { - map.insert_mut(k.clone(), v.clone()); + for (k, v) in new { + map.insert_mut(k, v); } let last = Env { last: self.last.clone(), @@ -51,19 +51,22 @@ impl<'vm> Env<'vm> { *self.map.borrow_mut() = map; } - pub fn enter_rec(self: &mut Rc, new: Rc>) { - let last = (*self.last.borrow_mut()).take(); - *self = new; - *self.last.borrow_mut() = last; - } - - pub fn new_rec(self: Rc) -> Rc { + pub fn enter_with(&self, new: Rc>) { + let mut map = self.map.borrow().clone(); + for (k, v) in new.as_inner().iter() { + let v = if let Value::Builtins = v { + Value::AttrSet(new.clone()) + } else { + v.clone() + }; + map.insert_mut(k.clone(), v); + } let last = Env { last: self.last.clone(), map: self.map.clone(), }; *self.last.borrow_mut() = Some(Rc::new(last)); - self.clone() + *self.map.borrow_mut() = map; } pub fn leave(&self) { diff --git a/src/vm/jit.rs b/src/vm/jit.rs index 442b09b..4db9212 100644 --- a/src/vm/jit.rs +++ b/src/vm/jit.rs @@ -1,12 +1,12 @@ use std::pin::Pin; -use inkwell::types::{BasicType, BasicTypeEnum, FunctionType, StructType}; -use inkwell::values::{BasicValueEnum, FunctionValue, IntValue}; -use inkwell::{AddressSpace, OptimizationLevel}; use inkwell::builder::Builder; use inkwell::context::Context; use inkwell::execution_engine::ExecutionEngine; use inkwell::module::Module; +use inkwell::types::{BasicType, BasicTypeEnum, FunctionType, StructType}; +use inkwell::values::{BasicValueEnum, FunctionValue, IntValue}; +use inkwell::{AddressSpace, OptimizationLevel}; use crate::stack::Stack; @@ -21,13 +21,13 @@ pub enum ValueTag { List, Function, Thunk, - Path + Path, } #[repr(C)] pub struct JITValue { tag: ValueTag, - data: u64 + data: u64, } pub struct JITContext<'ctx> { @@ -50,7 +50,10 @@ impl<'ctx> JITContext<'ctx> { let int_type = context.i64_type(); let pointer_type = context.ptr_type(AddressSpace::default()); let value_type = context.struct_type(&[int_type.into(), int_type.into()], false); - let func_type = value_type.fn_type(&[pointer_type.into(), pointer_type.into(), value_type.into()], false); + let func_type = value_type.fn_type( + &[pointer_type.into(), pointer_type.into(), value_type.into()], + false, + ); Pin::new(Box::new(JITContext { execution_engine: module @@ -71,7 +74,5 @@ impl<'ctx> JITContext<'ctx> { self.context.i64_type().const_int(int as u64, false) } - pub fn start_trace(&mut self) { - - } + pub fn start_trace(&mut self) {} } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index 63cca5d..7699de2 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -4,7 +4,7 @@ use std::pin::Pin; use std::rc::Rc; use crate::builtins::env; -use crate::bytecode::{BinOp, OpCode, OpCodes, Program, UnOp, Func as F}; +use crate::bytecode::{BinOp, Func as F, OpCode, OpCodes, Program, UnOp}; use crate::error::*; use crate::ty::internal::*; use crate::ty::public::{self as p, Symbol}; @@ -31,11 +31,13 @@ pub fn run(prog: Program, jit: Pin>>) -> Result { RefCell::new(prog.symbols), RefCell::new(prog.symmap), prog.consts, - jit + jit, ); let env = env(&vm); let mut seen = HashSet::new(); - let value = vm.eval(prog.top_level.into_iter(), env)?.to_public(&vm, &mut seen); + let value = vm + .eval(prog.top_level.into_iter(), env)? + .to_public(&vm, &mut seen); Ok(value) } @@ -46,7 +48,7 @@ pub struct VM<'jit> { symbols: RefCell>, symmap: RefCell>, consts: Box<[Const]>, - jit: Pin>> + jit: Pin>>, } impl<'vm, 'jit: 'vm> VM<'jit> { @@ -58,7 +60,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> { &self.funcs[idx] } - pub fn get_sym(&self, idx: usize) -> Symbol{ + pub fn get_sym(&self, idx: usize) -> Symbol { self.symbols.borrow()[idx].clone().into() } @@ -67,13 +69,19 @@ impl<'vm, 'jit: 'vm> VM<'jit> { if let Some(&idx) = self.symmap.borrow().get(&sym) { idx } else { - self.symmap.borrow_mut().insert(sym.clone(), self.symbols.borrow().len()); + self.symmap + .borrow_mut() + .insert(sym.clone(), self.symbols.borrow().len()); self.symbols.borrow_mut().push(sym); self.symbols.borrow().len() - 1 } } - pub fn eval(&'vm self, opcodes: impl Iterator, env: Rc>) -> Result> { + pub fn eval( + &'vm self, + opcodes: impl Iterator, + env: Rc>, + ) -> Result> { let mut stack = Stack::<_, STACK_SIZE>::new(); let mut iter = opcodes.into_iter(); while let Some(opcode) = iter.next() { @@ -101,12 +109,10 @@ impl<'vm, 'jit: 'vm> VM<'jit> { OpCode::LoadThunk { idx } => { stack.push(Value::Thunk(Thunk::new(self.get_thunk(idx)).into()))? } - OpCode::CaptureEnv => { - match stack.tos()? { - Value::Thunk(thunk) => thunk.capture(env.clone()), - _ => () - } - } + OpCode::CaptureEnv => match stack.tos()? { + Value::Thunk(thunk) => thunk.capture(env.clone()), + _ => (), + }, OpCode::ForceValue => { stack.tos_mut()?.force(self)?; } @@ -181,12 +187,16 @@ impl<'vm, 'jit: 'vm> VM<'jit> { stack.push(Value::AttrSet(AttrSet::empty().into()))?; } OpCode::FinalizeRec => { - env.enter(stack.tos()?.clone().unwrap_attr_set().as_inner().clone()); - stack - .tos_mut()? - .as_mut() - .unwrap_attr_set() - .capture(env); + env.enter( + stack + .tos()? + .clone() + .unwrap_attr_set() + .as_inner() + .iter() + .map(|(k, v)| (k.clone(), v.clone())), + ); + stack.tos_mut()?.as_mut().unwrap_attr_set().capture(env); } OpCode::PushStaticAttr { name } => { let val = stack.pop(); @@ -237,13 +247,12 @@ impl<'vm, 'jit: 'vm> VM<'jit> { stack.tos_mut()?.force(self)?.has_attr(sym); } OpCode::LookUp { sym } => { - stack.push( - env.lookup(sym) - .ok_or_else(|| Error::EvalError(format!("{} not found", self.get_sym(sym))))?, - )?; + stack.push(env.lookup(sym).ok_or_else(|| { + Error::EvalError(format!("{} not found", self.get_sym(sym))) + })?)?; } OpCode::EnterEnv => match stack.pop() { - Value::AttrSet(attrs) => env.enter(attrs.as_inner().clone()), + Value::AttrSet(attrs) => env.enter_with(attrs), _ => unreachable!(), }, diff --git a/src/vm/test.rs b/src/vm/test.rs index fe49255..0407971 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -141,7 +141,7 @@ fn test_attrs() { test_expr( "{ a = 1; }", attrs! { - symbol!("a") => thunk!() + symbol!("a") => int!(1) }, ); test_expr("{ a = 1; }.a", int!(1)); @@ -149,18 +149,18 @@ fn test_attrs() { test_expr( "{ a = { a = 1; }; }.a", attrs! { - symbol!("a") => thunk!() + symbol!("a") => int!(1) }, ); test_expr("{ a.b = 1; }.a.b", int!(1)); test_expr( "{ a.b = 1; a.c = 2; }", - attrs! { symbol!("a") => attrs!{ symbol!("b") => thunk!(), symbol!("c") => thunk!() } }, + attrs! { symbol!("a") => attrs!{ symbol!("b") => int!(1), symbol!("c") => int!(2) } }, ); test_expr("{ a.b = 1; } ? a.b", boolean!(true)); test_expr( "{ a.b = 1; } // { a.c = 2; }", - attrs! { symbol!("a") => attrs!{ symbol!("c") => thunk!() } }, + attrs! { symbol!("a") => attrs!{ symbol!("c") => int!(2) } }, ); } @@ -181,7 +181,7 @@ fn test_let() { test_expr(r#"let a = { a = 1; }; b = "a"; in a.${b}"#, int!(1)); test_expr( r#"let b = "c"; in { a.b = 1; } // { a."a${b}" = 2; }"#, - attrs! { symbol!("a") => attrs!{ symbol!("ac") => thunk!() } }, + attrs! { symbol!("a") => attrs!{ symbol!("ac") => int!(2) } }, ); }