diff --git a/Cargo.lock b/Cargo.lock index 9a86ed5..88979a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,15 +228,14 @@ dependencies = [ ] [[package]] -name = "nix-rs" -version = "0.1.0" +name = "nixjit" +version = "0.0.0" dependencies = [ "anyhow", "crossbeam-channel", "derive_more", "ecow", "itertools", - "num_cpus", "once_cell", "rayon", "rnix", diff --git a/Cargo.toml b/Cargo.toml index 0bd824e..0fda53c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "nix-rs" -version = "0.1.0" +name = "nixjit" +version = "0.0.0" edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -14,6 +14,5 @@ tokio = { version = "1.38", features = [ "full" ] } rpds = "1.1" derive_more = "0.99" crossbeam-channel = "0.5" -num_cpus = "1.0" ecow = "0.2" once_cell = "1.19" diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 2bdaede..7743338 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -3,39 +3,55 @@ use derive_more::Constructor; use super::vm::Env; use super::vm::Symbol; use super::vm::Value; -use crate::bytecode::Const; +use crate::value::Const; pub fn env() -> Env { let mut env = Env::empty(); env.insert(Symbol::from("true"), Value::Const(Const::Bool(true))); env.insert(Symbol::from("false"), Value::Const(Const::Bool(false))); - env.insert(Symbol::from("__add"), Value::PrimOp(PrimOp::new(2, |args| { - let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.add(second) - }))); - env.insert(Symbol::from("__sub"), Value::PrimOp(PrimOp::new(2, |args| { - let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.add(second.neg()) - }))); - env.insert(Symbol::from("__mul"), Value::PrimOp(PrimOp::new(2, |args| { - let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.mul(second) - }))); - env.insert(Symbol::from("__div"), Value::PrimOp(PrimOp::new(2, |args| { - let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.div(second) - }))); - env.insert(Symbol::from("__lessThan"), Value::PrimOp(PrimOp::new(2, |args| { - let [first, second]: [Value; 2] = args.try_into().unwrap(); - first.lt(second) - }))); + env.insert( + Symbol::from("__add"), + Value::PrimOp(PrimOp::new("add", 2, |args| { + let [first, second]: [Value; 2] = args.try_into().unwrap(); + first.add(second) + })), + ); + env.insert( + Symbol::from("__sub"), + Value::PrimOp(PrimOp::new("sub", 2, |args| { + let [first, second]: [Value; 2] = args.try_into().unwrap(); + first.add(second.neg()) + })), + ); + env.insert( + Symbol::from("__mul"), + Value::PrimOp(PrimOp::new("mul", 2, |args| { + let [first, second]: [Value; 2] = args.try_into().unwrap(); + first.mul(second) + })), + ); + env.insert( + Symbol::from("__div"), + Value::PrimOp(PrimOp::new("div", 2, |args| { + let [first, second]: [Value; 2] = args.try_into().unwrap(); + first.div(second) + })), + ); + env.insert( + Symbol::from("__lessThan"), + Value::PrimOp(PrimOp::new("lessThan", 2, |args| { + let [first, second]: [Value; 2] = args.try_into().unwrap(); + first.lt(second) + })), + ); env } #[derive(Debug, Clone, Constructor)] pub struct PrimOp { + name: &'static str, arity: u8, func: fn(Vec) -> Value, } @@ -49,7 +65,12 @@ impl PartialEq for PrimOp { impl PrimOp { pub fn call(self, args: Vec) -> Value { if (args.len() as u8) < self.arity { - Value::PartialPrimOp(PartialPrimOp { arity: self.arity - args.len() as u8, args, func: self.func }) + Value::PartialPrimOp(PartialPrimOp { + name: self.name, + arity: self.arity - args.len() as u8, + args, + func: self.func, + }) } else if args.len() as u8 == self.arity { (self.func)(args) } else { @@ -58,11 +79,12 @@ impl PrimOp { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone)] pub struct PartialPrimOp { + name: &'static str, arity: u8, args: Vec, - func: fn(Vec) -> Value + func: fn(Vec) -> Value, } impl PartialEq for PartialPrimOp { @@ -76,7 +98,12 @@ impl PartialPrimOp { let len = args.len() as u8; self.args.extend(args); if len < self.arity { - Value::PartialPrimOp(PartialPrimOp { arity: self.arity - len, args: self.args, func: self.func }) + Value::PartialPrimOp(PartialPrimOp { + name: self.name, + arity: self.arity - len, + args: self.args, + func: self.func, + }) } else if len == self.arity { (self.func)(self.args) } else { diff --git a/src/bytecode.rs b/src/bytecode.rs index 5e2a659..4fc5279 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -1,11 +1,10 @@ -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use ecow::EcoString; -use anyhow::Error; -use derive_more::{IsVariant, Unwrap}; -use crate::slice::Slice; -use crate::value::Func; +use crate::value::Const; + +type Slice = Box<[T]>; pub type ThunkIdx = usize; pub type ConstIdx = usize; @@ -23,122 +22,6 @@ pub struct Thunk { #[derive(Debug, Clone, Hash)] pub enum Arg {} -#[derive(Debug, Clone, IsVariant, Unwrap)] -pub enum Const { - Bool(bool), - Int(i64), - Float(f64), - String(EcoString), - Func(Func), -} - -impl From for Const { - fn from(value: bool) -> Self { - Const::Bool(value) - } -} - -impl From for Const { - fn from(value: i64) -> Self { - Const::Int(value) - } -} - -impl From for Const { - fn from(value: f64) -> Self { - Const::Float(value) - } -} - -impl From for Const { - fn from(value: EcoString) -> Self { - Const::String(value) - } -} - -impl From for Const { - fn from(value: String) -> Self { - Const::String(value.into()) - } -} - -impl From<&str> for Const { - fn from(value: &str) -> Self { - Const::String(value.into()) - } -} - -impl<'a> TryFrom<&'a Const> for &'a bool { - type Error = Error; - - fn try_from(value: &'a Const) -> Result { - match value { - Const::Bool(b) => Ok(b), - _ => panic!(), - } - } -} -impl<'a> TryFrom<&'a Const> for &'a i64 { - type Error = Error; - - fn try_from(value: &'a Const) -> Result { - match value { - Const::Int(int) => Ok(int), - _ => panic!(), - } - } -} - -impl<'a> TryFrom<&'a Const> for &'a f64 { - type Error = Error; - - fn try_from(value: &'a Const) -> Result { - match value { - Const::Float(float) => Ok(float), - _ => panic!(), - } - } -} - -impl<'a> TryFrom<&'a Const> for &'a str { - type Error = Error; - - fn try_from(value: &'a Const) -> Result { - match value { - Const::String(string) => Ok(string), - _ => panic!(), - } - } -} - -impl PartialEq for Const { - fn eq(&self, other: &Self) -> bool { - use Const::*; - match (self, other) { - (Bool(a), Bool(b)) => a == b, - (Int(a), Int(b)) => a == b, - (Float(a), Float(b)) => a == b, - (String(a), String(b)) => a == b, - _ => false, - } - } -} - -impl Eq for Const {} - -impl Hash for Const { - fn hash(&self, state: &mut H) { - use Const::*; - match self { - Bool(b) => b.hash(state), - Int(int) => int.hash(state), - Float(float) => float.to_bits().hash(state), - String(string) => string.hash(state), - Func(func) => func.hash(state), - } - } -} - #[derive(Debug, Clone, Hash)] pub enum OpCode { /// load a constant onto stack @@ -151,60 +34,58 @@ pub enum OpCode { LoadValue { idx: ThunkIdx }, /// force TOS to value ForceValue, - /// [ ... func, args @ .. ] call func with `arity` numbers of arg + /// [ .. func args @ .. ] consume (`arity` + 2) elements, call `func` with args` of length `arity` + /// Example: __add 1 2 => [ LookUp("__add") Const(1) Const(2) Call(2) ] Call { arity: usize }, - /// assert TOS is true then consume it + /// consume 1 element, assert TOS is true Assert, /// jump forward Jmp { step: usize }, - /// [ ... cond ] if (cond) is true, then jump forward + /// [ .. cond ] consume 1 element, if `cond`` is true, then jump forward JmpIfTrue { step: usize }, - /// [ ... cond ] if (cond) is false, then jump forward + /// [ .. cond ] consume 1 element, if `cond` is false, then jump forward JmpIfFalse { step: usize }, /// push an empty attribute set onto stack AttrSet, /// push an empty recursive attribute set onto stack RecAttrSet, - /// [ ... set, value ] push the static kv pair (name, (value)) into (set) + /// [ .. set value ] consume 1 element, push a static kv pair (`name`, `value`) into `set` PushStaticAttr { name: EcoString }, - /// [ ... set, name, value ] push the dynamic kv pair ((name), (value)) in to (set) + /// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set` PushDynamicAttr, /// push an empty list onto stack List, - /// [ ... list, elem ] push (elem) into (list) + /// [ .. list elem ] consume 1 element, push `elem` into `list` PushElem, - /// [ ... a, b ] perform a binary operation ((a) `op` (b)) - BinOp { op: BinOp }, - /// [ ... a ] perform a unary operation (`op` (a)) - UnOp { op: UnOp }, - /// TODO: + /// [ .. a b ] consume 2 elements, perform a string concatenation `a` + `b` ConcatString, - /// TODO: + /// [ .. a b ] consume 2 elements, perform a binary operation `a` `op` `b` + BinOp { op: BinOp }, + /// [ .. a ] consume 1 element, perform a unary operation `op` `a` + UnOp { op: UnOp }, + /// set TOS to the bool value of whether TOS contains `sym` HasAttr { sym: EcoString }, - /// TODO: + /// [ .. set sym ] consume 2 elements, set TOS to the bool value of whether `set` contains `sym` HasDynamicAttr, - // HasAttr { arity: usize }, - /// TODO: + /// [ .. set ] select `sym` from `set` Select { sym: EcoString }, - // Select { arity: usize }, /// TODO: - SelectDynamic, - // SelectDynamic { arity: usize }, + SelectWithDefault { sym: EcoString }, /// TODO: SelectOrEmpty { sym: EcoString }, /// TODO: - SelectDynamicOrEmpty, + SelectDynamic, /// TODO: - SelectWithDefault { sym: EcoString }, + SelectDynamicOrEmpty, /// TODO: SelectDynamicWithDefault, /// enter the environment of the attribute set at TOS EnterEnv, - /// exit the envrironment + /// exit current envrironment LeaveEnv, /// return a value Ret, - /// no-op + /// no operation NoOp, } diff --git a/src/compile/compile.rs b/src/compile/compile.rs index bc58178..ff9b326 100644 --- a/src/compile/compile.rs +++ b/src/compile/compile.rs @@ -1,4 +1,5 @@ use crate::bytecode::*; +use crate::value::*; use super::ir; @@ -93,6 +94,27 @@ impl Compile for ir::Thunk { impl Compile for ir::Attrs { fn compile(self, comp: &mut Compiler) { + if self.rec { + comp.push(OpCode::AttrSet); + for dynamic in self.dyns.clone() { + dynamic.0.compile(comp); + dynamic.1.compile(comp); + comp.push(OpCode::PushDynamicAttr) + } + comp.push(OpCode::EnterEnv); + comp.push(OpCode::AttrSet); + for stc in self.stcs { + stc.1.compile(comp); + comp.push(OpCode::PushStaticAttr { name: stc.0 }); + } + for dynamic in self.dyns { + dynamic.0.compile(comp); + dynamic.1.compile(comp); + comp.push(OpCode::PushDynamicAttr) + } + comp.push(OpCode::LeaveEnv); + return + } comp.push(OpCode::AttrSet); for stc in self.stcs { stc.1.compile(comp); @@ -106,29 +128,6 @@ impl Compile for ir::Attrs { } } -impl Compile for ir::RecAttrs { - fn compile(self, comp: &mut Compiler) { - comp.push(OpCode::AttrSet); - for dynamic in self.dyns.clone() { - dynamic.0.compile(comp); - dynamic.1.compile(comp); - comp.push(OpCode::PushDynamicAttr) - } - comp.push(OpCode::EnterEnv); - comp.push(OpCode::AttrSet); - for stc in self.stcs { - stc.1.compile(comp); - comp.push(OpCode::PushStaticAttr { name: stc.0 }); - } - for dynamic in self.dyns { - dynamic.0.compile(comp); - dynamic.1.compile(comp); - comp.push(OpCode::PushDynamicAttr) - } - comp.push(OpCode::LeaveEnv); - } -} - impl Compile for ir::List { fn compile(self, comp: &mut Compiler) { comp.push(OpCode::List); @@ -144,8 +143,12 @@ impl Compile for ir::UnOp { use ir::UnOpKind::*; match self.kind { Neg => { - comp.push(OpCode::LookUp { sym: "__sub".into() }); - comp.push(OpCode::Const { value: Const::Int(0) }); + comp.push(OpCode::LookUp { + sym: "__sub".into(), + }); + comp.push(OpCode::Const { + value: Const::Int(0), + }); self.rhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); } @@ -167,13 +170,17 @@ impl Compile for ir::BinOp { comp.push(OpCode::BinOp { op: BinOp::Add }); } Mul => { - comp.push(OpCode::LookUp { sym: "__mul".into() }); + comp.push(OpCode::LookUp { + sym: "__mul".into(), + }); self.lhs.compile(comp); self.rhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); } Div => { - comp.push(OpCode::LookUp { sym: "__div".into() }); + comp.push(OpCode::LookUp { + sym: "__div".into(), + }); self.lhs.compile(comp); self.rhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); @@ -194,7 +201,9 @@ impl Compile for ir::BinOp { comp.push(OpCode::BinOp { op: BinOp::Eq }); } Lt => { - comp.push(OpCode::LookUp { sym: "__lessThan".into() }); + comp.push(OpCode::LookUp { + sym: "__lessThan".into(), + }); self.lhs.compile(comp); self.rhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); @@ -211,7 +220,9 @@ impl Compile for ir::BinOp { } Sub => { - comp.push(OpCode::LookUp { sym: "__sub".into() }); + comp.push(OpCode::LookUp { + sym: "__sub".into(), + }); self.lhs.compile(comp); self.rhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); @@ -229,20 +240,26 @@ impl Compile for ir::BinOp { comp.push(OpCode::UnOp { op: UnOp::Not }); } Gt => { - comp.push(OpCode::LookUp { sym: "__lessThan".into() }); + comp.push(OpCode::LookUp { + sym: "__lessThan".into(), + }); self.rhs.compile(comp); self.lhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); } Leq => { - comp.push(OpCode::LookUp { sym: "__lessThan".into() }); + comp.push(OpCode::LookUp { + sym: "__lessThan".into(), + }); self.rhs.compile(comp); self.lhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); comp.push(OpCode::UnOp { op: UnOp::Not }); } Geq => { - comp.push(OpCode::LookUp { sym: "__lessThan".into() }); + comp.push(OpCode::LookUp { + sym: "__lessThan".into(), + }); self.lhs.compile(comp); self.rhs.compile(comp); comp.push(OpCode::Call { arity: 2 }); @@ -372,19 +389,19 @@ impl Compile for ir::Assert { } impl Compile for ir::Func { - fn compile(self, comp: &mut Compiler) { + fn compile(self, _comp: &mut Compiler) { todo!() } } impl Compile for ir::Call { - fn compile(self, comp: &mut Compiler) { + fn compile(self, _comp: &mut Compiler) { todo!() } } impl Compile for ir::Path { - fn compile(self, comp: &mut Compiler) { + fn compile(self, _comp: &mut Compiler) { todo!() } } diff --git a/src/compile/ir.rs b/src/compile/ir.rs index de13c62..93b9c21 100644 --- a/src/compile/ir.rs +++ b/src/compile/ir.rs @@ -1,17 +1,14 @@ -// TODO: Error Handling - use std::collections::HashMap; -use anyhow::{anyhow, Result}; -use rnix::ast::{self, Expr}; +use anyhow::{Result, anyhow}; use ecow::EcoString; +use rnix::ast::{self, Expr}; -use crate::bytecode::{Const as ByteCodeConst, ConstIdx, Consts, ThunkIdx}; -use crate::slice::Slice; +use crate::bytecode::{ConstIdx, Consts, ThunkIdx}; +use crate::value::Const as Const_; use super::compile::*; use super::env::IrEnv; -use super::symtable::*; pub fn downgrade(expr: Expr) -> Result { let mut state = DowngradeState::new(); @@ -112,8 +109,7 @@ macro_rules! ir { } ir! { - Attrs => { stcs: HashMap, dyns: Vec }, - RecAttrs => { stcs: HashMap, dyns: Vec }, + Attrs => { stcs: HashMap, dyns: Vec, rec: bool }, List => { items: Vec }, HasAttr => { lhs: Box, rhs: Vec }, BinOp => { lhs: Box, rhs: Box, kind: BinOpKind }, @@ -127,7 +123,7 @@ ir! { With => { namespace: Box, expr: Box }, Assert => { assertion: Box, expr: Box }, ConcatStrings => { parts: Vec }, - Const => { value: ByteCodeConst }, + Const => { value: Const_ }, Var => { sym: EcoString }, #[derive(Copy)] Thunk => { idx: ThunkIdx }, @@ -165,23 +161,21 @@ pub struct DowngradeError { } pub struct DowngradeState { - sym_table: SymTable, envs: Vec, thunks: Vec, - consts: Vec, - consts_table: HashMap, + consts: Vec, + consts_table: HashMap, } pub struct Downgraded { pub top_level: Ir, pub consts: Consts, - pub thunks: Slice, + pub thunks: Box<[Ir]>, } impl DowngradeState { fn new() -> DowngradeState { DowngradeState { - sym_table: SymTable::new(), envs: Vec::new(), thunks: Vec::new(), consts: Vec::new(), @@ -214,6 +208,7 @@ impl Attrs { .and_then(|attrs: &mut Attrs| attrs._insert(path, name, value)) } else { let mut attrs = Attrs { + rec: false, stcs: HashMap::new(), dyns: Vec::new(), }; @@ -224,6 +219,7 @@ impl Attrs { } Attr::Strs(string) => { let mut attrs = Attrs { + rec: false, stcs: HashMap::new(), dyns: Vec::new(), }; @@ -233,6 +229,7 @@ impl Attrs { } Attr::Dynamic(dynamic) => { let mut attrs = Attrs { + rec: false, stcs: HashMap::new(), dyns: Vec::new(), }; @@ -317,8 +314,8 @@ pub enum BinOpKind { impl From for BinOpKind { fn from(op: ast::BinOpKind) -> Self { - use ast::BinOpKind as astkind; use BinOpKind::*; + use ast::BinOpKind as astkind; match op { astkind::Concat => Con, astkind::Update => Upd, @@ -366,7 +363,7 @@ pub enum Param { trait Downgrade where - Self: Sized + Self: Sized, { fn downgrade(self, state: &mut DowngradeState) -> Result; } @@ -427,9 +424,11 @@ impl Downgrade for ast::Path { .parts() .into_iter() .map(|part| match part { - ast::InterpolPart::Literal(lit) => Const { value: lit.to_string().into() } - .ir() - .ok(), + ast::InterpolPart::Literal(lit) => Const { + value: lit.to_string().into(), + } + .ir() + .ok(), ast::InterpolPart::Interpolation(interpol) => { interpol.expr().unwrap().downgrade(state) } @@ -455,9 +454,7 @@ impl Downgrade for ast::Str { .normalized_parts() .into_iter() .map(|part| match part { - ast::InterpolPart::Literal(lit) => { - Const { value: lit.into() }.ir().ok() - } + ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(), ast::InterpolPart::Interpolation(interpol) => { interpol.expr().unwrap().downgrade(state) } @@ -472,11 +469,17 @@ impl Downgrade for ast::Str { } impl Downgrade for ast::Literal { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, _state: &mut DowngradeState) -> Result { match self.kind() { - ast::LiteralKind::Integer(int) => Const { value: int.value().unwrap().into() }, - ast::LiteralKind::Float(float) => Const { value: float.value().unwrap().into() }, - ast::LiteralKind::Uri(uri) => Const { value: uri.to_string().into() }, + ast::LiteralKind::Integer(int) => Const { + value: int.value().unwrap().into(), + }, + ast::LiteralKind::Float(float) => Const { + value: float.value().unwrap().into(), + }, + ast::LiteralKind::Uri(uri) => Const { + value: uri.to_string().into(), + }, } .ir() .ok() @@ -486,7 +489,7 @@ impl Downgrade for ast::Literal { impl Downgrade for ast::Ident { fn downgrade(self, _state: &mut DowngradeState) -> Result { Var { - sym: self.to_string().into() + sym: self.to_string().into(), } .ir() .ok() @@ -584,12 +587,7 @@ impl Downgrade for ast::LetIn { let body = self.body().unwrap(); let attrs = downgrade_has_entry(self, true, state)?; let expr = body.downgrade(state)?.boxed(); - Let { - attrs, - expr - } - .ir() - .ok() + Let { attrs, expr }.ir().ok() } } @@ -636,9 +634,7 @@ impl Downgrade for ast::Apply { fn downgrade_param(param: ast::Param, state: &mut DowngradeState) -> Result { match param { - ast::Param::IdentParam(ident) => { - Ok(Param::Ident(ident.to_string().into())) - } + ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())), ast::Param::Pattern(pattern) => downgrade_pattern(pattern, state), } } @@ -677,6 +673,7 @@ fn downgrade_has_entry( ) -> Result { let entires = has_entry.entries(); let mut attrs = Attrs { + rec, stcs: HashMap::new(), dyns: Vec::new(), }; @@ -684,9 +681,7 @@ fn downgrade_has_entry( for entry in entires { match entry { ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, state)?, - ast::Entry::AttrpathValue(value) => { - downgrade_attrpathvalue(value, &mut attrs, state)? - } + ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, state)?, } } @@ -710,7 +705,7 @@ fn downgrade_inherit( _ => return Err(anyhow!("dynamic attributes not allowed in inherit")), }; let expr = from.map_or_else( - || Var { sym: ident.clone() }.ir().ok(), + || Var { sym: ident.clone() }.ir().ok(), |from| { Ok(Select { expr: from.ir().boxed(), @@ -739,9 +734,7 @@ fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result { let parts = parts .into_iter() .map(|part| match part { - ast::InterpolPart::Literal(lit) => { - Const { value: lit.into() }.ir().ok() - } + ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(), ast::InterpolPart::Interpolation(interpol) => { interpol.expr().unwrap().downgrade(state) } diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 76b8ec7..221cca4 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -1,7 +1,6 @@ mod compile; mod env; mod ir; -mod symtable; pub fn compile(expr: &str) -> anyhow::Result { let expr = rnix::Root::parse(expr).tree().expr().unwrap(); diff --git a/src/compile/symtable.rs b/src/compile/symtable.rs deleted file mode 100644 index ec6b921..0000000 --- a/src/compile/symtable.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::collections::HashMap; - -use crate::bytecode::SymIdx; -use crate::slice::Slice; - -// FIXME: don't store syms twice to make it more memory efficient? - -pub struct SymTable { - syms: Vec, - syms_table: HashMap, -} - -impl SymTable { - pub fn new() -> SymTable { - SymTable { - syms: Vec::new(), - syms_table: HashMap::new(), - } - } - - pub fn lookup(&mut self, name: String) -> SymIdx { - if let Some(sym) = self.syms_table.get(&name) { - *sym - } else { - let sym = self.syms.len(); - self.syms.push(name.clone()); - self.syms_table.insert(name, sym); - sym - } - } - - pub fn syms(self) -> Slice { - self.syms.into() - } -} diff --git a/src/lib.rs b/src/lib.rs index 9506c12..91a874f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,5 @@ mod builtins; mod bytecode; mod compile; mod downcast; -mod slice; mod value; mod vm; diff --git a/src/slice.rs b/src/slice.rs deleted file mode 100644 index acd9037..0000000 --- a/src/slice.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub type Slice = Box<[T]>; - diff --git a/src/value/cnst.rs b/src/value/cnst.rs new file mode 100644 index 0000000..dc8c2ca --- /dev/null +++ b/src/value/cnst.rs @@ -0,0 +1,124 @@ +use std::hash::{Hash, Hasher}; + +use anyhow::Error; +use derive_more::{IsVariant, Unwrap}; + +use ecow::EcoString; + +use super::Func; + +#[derive(Debug, Clone, IsVariant, Unwrap)] +pub enum Const { + Bool(bool), + Int(i64), + Float(f64), + String(EcoString), + Func(Func), +} + +impl From for Const { + fn from(value: bool) -> Self { + Const::Bool(value) + } +} + +impl From for Const { + fn from(value: i64) -> Self { + Const::Int(value) + } +} + +impl From for Const { + fn from(value: f64) -> Self { + Const::Float(value) + } +} + +impl From for Const { + fn from(value: EcoString) -> Self { + Const::String(value) + } +} + +impl From for Const { + fn from(value: String) -> Self { + Const::String(value.into()) + } +} + +impl From<&str> for Const { + fn from(value: &str) -> Self { + Const::String(value.into()) + } +} + +impl<'a> TryFrom<&'a Const> for &'a bool { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::Bool(b) => Ok(b), + _ => panic!(), + } + } +} +impl<'a> TryFrom<&'a Const> for &'a i64 { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::Int(int) => Ok(int), + _ => panic!(), + } + } +} + +impl<'a> TryFrom<&'a Const> for &'a f64 { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::Float(float) => Ok(float), + _ => panic!(), + } + } +} + +impl<'a> TryFrom<&'a Const> for &'a str { + type Error = Error; + + fn try_from(value: &'a Const) -> Result { + match value { + Const::String(string) => Ok(string), + _ => panic!(), + } + } +} + +impl PartialEq for Const { + fn eq(&self, other: &Self) -> bool { + use Const::*; + match (self, other) { + (Bool(a), Bool(b)) => a == b, + (Int(a), Int(b)) => a == b, + (Float(a), Float(b)) => a == b, + (String(a), String(b)) => a == b, + _ => false, + } + } +} + +impl Eq for Const {} + +impl Hash for Const { + fn hash(&self, state: &mut H) { + use Const::*; + match self { + Bool(b) => b.hash(state), + Int(int) => int.hash(state), + Float(float) => float.to_bits().hash(state), + String(string) => string.hash(state), + Func(func) => func.hash(state), + } + } +} diff --git a/src/value/mod.rs b/src/value/mod.rs index e39d9c7..3f83517 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,12 +1,15 @@ -use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; +use std::fmt::{Debug, Formatter, Result as FmtResult}; use std::ops::Deref; -use std::sync::Arc; use derive_more::{Constructor, IsVariant, Unwrap}; use ecow::EcoString; use rpds::{HashTrieMapSync, VectorSync}; -use crate::bytecode::{Args, Const, OpCodes}; +use crate::bytecode::{Args, OpCodes}; + +mod cnst; + +pub use cnst::Const; #[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)] pub struct Symbol(EcoString); @@ -93,7 +96,7 @@ pub struct List { #[derive(Clone, Debug, PartialEq, Constructor)] pub struct Catchable { - msg: Option + msg: Option, } #[derive(IsVariant, Unwrap, Clone, Debug, PartialEq)] diff --git a/src/vm/env.rs b/src/vm/env.rs index 787f195..0917df0 100644 --- a/src/vm/env.rs +++ b/src/vm/env.rs @@ -3,7 +3,7 @@ use rpds::HashTrieMapSync; use super::value::{Symbol, VmValue}; pub struct Env { - last: Option<*mut Env>, + last: Option>, map: HashTrieMapSync, } @@ -19,7 +19,7 @@ impl Env { if let Some(value) = self.map.get(&symbol) { value.clone() } else { - let last = unsafe { &*self.last.unwrap() }; + let last = self.last.as_ref().unwrap(); last.lookup(symbol) } } @@ -29,19 +29,13 @@ impl Env { } pub fn enter(&mut self, map: HashTrieMapSync) { - let last = std::mem::replace( - self, - Env { - last: None, - map, - }, - ); - self.last = Some(Box::leak(Box::new(last)) as *mut Env); + let last = std::mem::replace(self, Env { last: None, map }); + self.last = Some(Box::new(last)); } pub fn leave(&mut self) { - let last = unsafe { &*self.last.unwrap() }; - self.last = last.last; + let last = std::mem::replace(&mut self.last, None).unwrap(); + let _ = std::mem::replace(&mut self.last, last.last); self.map = last.map.clone(); } } diff --git a/src/vm/stack.rs b/src/vm/stack.rs index 3b9dbd2..d7e302f 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -1,7 +1,7 @@ -use std::mem::{size_of, transmute, MaybeUninit}; +use std::mem::{MaybeUninit, size_of, transmute}; use std::ops::Deref; -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use super::value::VmValue; diff --git a/src/vm/test.rs b/src/vm/test.rs index 4cc9e1c..4153bbb 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -3,7 +3,6 @@ use rpds::{ht_map_sync, vector_sync}; use crate::compile::compile; use crate::value::*; -use crate::bytecode::Const; use super::vm::run; diff --git a/src/vm/value/attrset.rs b/src/vm/value/attrset.rs index dbd99a4..391ad82 100644 --- a/src/vm/value/attrset.rs +++ b/src/vm/value/attrset.rs @@ -12,7 +12,14 @@ pub struct AttrSet { } impl AttrSet { + pub fn push_attr_force(&mut self, sym: Symbol, val: VmValue) { + self.data.insert_mut(sym, val); + } + pub fn push_attr(&mut self, sym: Symbol, val: VmValue) { + if self.data.get(&sym).is_some() { + todo!() + } self.data.insert_mut(sym, val); } @@ -26,7 +33,7 @@ impl AttrSet { pub fn update(mut self, other: AttrSet) -> AttrSet { for (k, v) in other.data.iter() { - self.push_attr(k.clone(), v.clone()) + self.push_attr_force(k.clone(), v.clone()) } self } @@ -41,7 +48,12 @@ impl ToValue for AttrSet { Value::AttrSet(value::AttrSet::new( self.data .iter() - .map(|(sym, value)| (value::Symbol::new(sym.0.clone()), value.clone().to_value(vm))) + .map(|(sym, value)| { + ( + value::Symbol::new(sym.0.clone()), + value.clone().to_value(vm), + ) + }) .collect(), )) } diff --git a/src/vm/value/mod.rs b/src/vm/value/mod.rs index e6d139d..6d3b4ae 100644 --- a/src/vm/value/mod.rs +++ b/src/vm/value/mod.rs @@ -1,12 +1,11 @@ -use derive_more::{Constructor, IsVariant, Unwrap}; use anyhow::Result; +use derive_more::{Constructor, IsVariant, Unwrap}; use ecow::EcoString; use crate::value::*; -use crate::bytecode::Const; -use super::vm::VM; use super::env::Env; +use super::vm::VM; mod attrset; mod list; @@ -40,7 +39,7 @@ pub enum VmValue { List(List), Catchable(crate::value::Catchable), PrimOp(crate::builtins::PrimOp), - PartialPrimOp(crate::builtins::PartialPrimOp) + PartialPrimOp(crate::builtins::PartialPrimOp), } use VmValue::Const as VmConst; @@ -49,7 +48,7 @@ impl VmValue { match self { VmValue::PrimOp(func) => func.call(args), VmValue::PartialPrimOp(func) => func.call(args), - _ => todo!() + _ => todo!(), } } @@ -90,7 +89,7 @@ impl VmValue { (VmConst(Float(a)), VmConst(Int(b))) => a < b as f64, (VmConst(Float(a)), VmConst(Float(b))) => a < b, (VmConst(String(a)), VmConst(String(b))) => a < b, - _ => todo!() + _ => todo!(), })) } @@ -144,7 +143,9 @@ impl VmValue { } pub fn concat_string(&mut self, mut other: VmValue) -> &mut Self { - if let (VmConst(Const::String(a)), VmConst(Const::String(b))) = (self.coerce_to_string(), other.coerce_to_string()) { + if let (VmConst(Const::String(a)), VmConst(Const::String(b))) = + (self.coerce_to_string(), other.coerce_to_string()) + { a.push_str(b.as_str()); } else { todo!() @@ -190,7 +191,9 @@ impl VmValue { if let VmValue::AttrSet(attrs) = self { let val = attrs .select(sym.clone()) - .unwrap_or(VmValue::Catchable(Catchable::new(Some(format!("{sym:?} not found"))))); + .unwrap_or(VmValue::Catchable(Catchable::new(Some(format!( + "{sym:?} not found" + ))))); *self = val; } else { todo!() diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 5f8bdc9..57fb69b 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,13 +1,12 @@ -use anyhow::{anyhow, Result}; +use anyhow::Result; use rpds::{HashTrieMap, HashTrieMapSync, Vector}; -use crate::bytecode::{self, *}; -use crate::slice::*; -use crate::value::{self, Value}; use crate::builtins::env; +use crate::bytecode::{self, *}; +use crate::value::{Const, Value}; use super::env::Env; -use super::stack::{Stack, STACK_SIZE}; +use super::stack::{STACK_SIZE, Stack}; use super::value::{self as vmValue, *}; use super::vmthunk::*; @@ -17,7 +16,7 @@ pub fn run(prog: Program) -> Result { } pub struct VM { - thunks: Slice, + thunks: Box<[VmThunk]>, } impl VM { @@ -26,9 +25,7 @@ impl VM { .into_iter() .map(|bytecode::Thunk { opcodes }| VmThunk::new(opcodes)) .collect(); - VM { - thunks, - } + VM { thunks } } pub fn get_thunk_value(&self, idx: usize, env: &mut Env) -> Result { @@ -77,7 +74,7 @@ impl VM { } } OpCode::Call { arity } => { - let mut args = Vec::with_capacity(arity); + let mut args = Vec::with_capacity(arity); for _ in 0..arity { args.insert(0, stack.pop()?); } @@ -139,9 +136,10 @@ impl VM { .select_with_default(Symbol::new(sym), default.clone()); } OpCode::SelectOrEmpty { sym } => { - stack - .tos_mut()? - .select_with_default(Symbol::new(sym), VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync()))); + stack.tos_mut()?.select_with_default( + Symbol::new(sym), + VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())), + ); } OpCode::SelectDynamic => { let mut val = stack.pop().unwrap(); @@ -160,7 +158,10 @@ impl VM { let mut val = stack.pop().unwrap(); val.coerce_to_string(); let sym = val.unwrap_const().unwrap_string().into(); - stack.tos_mut()?.select_with_default(sym, VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync()))); + stack.tos_mut()?.select_with_default( + sym, + VmValue::AttrSet(AttrSet::new(HashTrieMapSync::new_sync())), + ); } OpCode::HasAttr { sym } => { stack.tos_mut()?.has_attr(Symbol::new(sym)); @@ -185,4 +186,3 @@ impl VM { Ok(0) } } - diff --git a/src/vm/vmthunk.rs b/src/vm/vmthunk.rs index c501529..32c01d4 100644 --- a/src/vm/vmthunk.rs +++ b/src/vm/vmthunk.rs @@ -1,18 +1,18 @@ use std::cell::RefCell; use std::sync::RwLock; -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use derive_more::{IsVariant, Unwrap}; use crate::bytecode::OpCodes; -use super::vm::VM; use super::env::Env; use super::value::VmValue; +use super::vm::VM; pub struct VmThunk { thunk: RefCell<_VmThunk>, - lock: RwLock<()> + lock: RwLock<()>, } #[derive(IsVariant, Unwrap)] @@ -26,7 +26,7 @@ impl VmThunk { pub fn new(opcodes: OpCodes) -> VmThunk { VmThunk { thunk: RefCell::new(_VmThunk::Code(opcodes)), - lock: RwLock::new(()) + lock: RwLock::new(()), } } @@ -37,8 +37,8 @@ impl VmThunk { _VmThunk::Value(value) => return Ok(value.clone()), _VmThunk::SuspendedFrom(from) => { return Err(anyhow!( - "already suspended from {from:p} (infinite recursion encountered)" - )) + "already suspended from {from:p} (infinite recursion encountered)" + )); } _VmThunk::Code(_) => (), } @@ -48,9 +48,13 @@ impl VmThunk { let opcodes = std::mem::replace( &mut *self.thunk.borrow_mut(), _VmThunk::SuspendedFrom(self as *const VmThunk), - ).unwrap_code(); + ) + .unwrap_code(); let value = vm.eval(opcodes, env).unwrap(); - let _ = std::mem::replace(&mut *self.thunk.borrow_mut(), _VmThunk::Value(value.clone())); + let _ = std::mem::replace( + &mut *self.thunk.borrow_mut(), + _VmThunk::Value(value.clone()), + ); Ok(value) } }