From f86c088e97eb3160ad8909307f66af36bbee3ee3 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Sat, 10 May 2025 16:29:55 +0800 Subject: [PATCH] feat: stash --- Cargo.lock | 26 ++++++++++-- Cargo.toml | 19 ++++++--- flake.nix | 16 ++++++++ src/bin/{repl.rs => repl-vm.rs} | 23 +++++++++-- src/{compile => }/compile.rs | 3 +- src/compile/mod.rs | 17 -------- src/downcast.rs | 8 ---- src/error.rs | 13 ++++++ src/{compile => }/ir.rs | 73 ++++++++++++++++----------------- src/jit/codegen.rs | 5 +++ src/jit/mod.rs | 22 ++++++---- src/lib.rs | 14 ++++--- src/ty/internal/attrset.rs | 8 ++-- src/ty/internal/cnst.rs | 45 -------------------- src/ty/internal/func.rs | 6 +-- src/ty/internal/list.rs | 4 +- src/ty/internal/mod.rs | 25 ++++++----- src/ty/public/cnst.rs | 3 +- src/vm/stack.rs | 52 +++++++++-------------- src/vm/test.rs | 4 +- src/vm/vm.rs | 55 ++++++++++++------------- 21 files changed, 222 insertions(+), 219 deletions(-) rename src/bin/{repl.rs => repl-vm.rs} (59%) rename src/{compile => }/compile.rs (99%) delete mode 100644 src/compile/mod.rs delete mode 100644 src/downcast.rs create mode 100644 src/error.rs rename src/{compile => }/ir.rs (93%) create mode 100644 src/jit/codegen.rs diff --git a/Cargo.lock b/Cargo.lock index cf24aaf..bcb95b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ dependencies = [ "libc", "llvm-sys", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -278,7 +278,6 @@ dependencies = [ name = "nixjit" version = "0.0.0" dependencies = [ - "anyhow", "derive_more", "ecow", "inkwell", @@ -287,6 +286,7 @@ dependencies = [ "rnix", "rpds", "rustyline", + "thiserror 2.0.12", ] [[package]] @@ -477,7 +477,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -491,6 +500,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "triomphe" version = "0.1.11" diff --git a/Cargo.toml b/Cargo.toml index 09adaae..9c92dea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,20 +3,29 @@ name = "nixjit" version = "0.0.0" edition = "2024" +[features] +default = ["vm", "jit", "repl"] +vm = [] +jit = ["dep:inkwell"] +repl = ["dep:rustyline"] + +[[bin]] +name = "repl-vm" +required-features = ["vm", "repl"] + [profile.perf] -opt-level = 3 debug = 1 -inherits = "dev" +inherits = "release" [dependencies] rnix = "0.11" -anyhow = "1.0" +thiserror = "2.0" itertools = "0.12" rpds = "1.1" derive_more = { version = "2.0", features = [ "full" ] } ecow = "0.2" regex = "1.11" -inkwell = { version = "0.6.0", features = ["llvm18-1"] } +inkwell = { version = "0.6.0", features = ["llvm18-1"], optional = true } -rustyline = "15.0" +rustyline = { version = "15.0", optional = true } diff --git a/flake.nix b/flake.nix index 17003a8..7689e82 100644 --- a/flake.nix +++ b/flake.nix @@ -23,7 +23,23 @@ "rustfmt" "rust-analyzer" ]) + llvm_18 + libffi + libxml2 + ncurses ]; + LLVM_SYS_181_PREFIX = toString pkgs.llvm_18.dev; + LD_LIBRARY_PATH = let + libs = with pkgs; [ + llvm_18.lib + stdenv.cc.cc.lib + libffi + libxml2 + ncurses + ]; + in + builtins.concatStringsSep ":" (map (lib: "${lib}/lib") libs) + ; }; } ); diff --git a/src/bin/repl.rs b/src/bin/repl-vm.rs similarity index 59% rename from src/bin/repl.rs rename to src/bin/repl-vm.rs index 9e3b0e7..62ae81f 100644 --- a/src/bin/repl.rs +++ b/src/bin/repl-vm.rs @@ -1,7 +1,21 @@ use rustyline::error::ReadlineError; use rustyline::{DefaultEditor, Result}; -use nixjit::*; +use nixjit::compile::compile; +use nixjit::ir::downgrade; +use nixjit::vm::run; + +macro_rules! unwrap { + ($e:expr) => { + match $e { + Ok(ok) => ok, + Err(err) => { + println!("{err}"); + continue; + } + } + }; +} fn main() -> Result<()> { let mut rl = DefaultEditor::new()?; @@ -12,8 +26,11 @@ fn main() -> Result<()> { if expr.trim().is_empty() { continue; } - let prog = compile(expr.as_str()).unwrap(); - println!("{}", run(prog).unwrap()); + let downgraded = unwrap!(downgrade( + rnix::Root::parse(expr.as_str()).tree().expr().unwrap() + )); + let prog = compile(downgraded); + println!("{}", unwrap!(run(prog))); rl.add_history_entry(expr.as_str())?; } Err(ReadlineError::Interrupted) => { diff --git a/src/compile/compile.rs b/src/compile.rs similarity index 99% rename from src/compile/compile.rs rename to src/compile.rs index e731bf9..65aec36 100644 --- a/src/compile/compile.rs +++ b/src/compile.rs @@ -1,8 +1,7 @@ use crate::bytecode::*; +use crate::ir; use crate::ty::internal::Const; -use super::ir; - pub struct Compiler { opcodes: Vec, } diff --git a/src/compile/mod.rs b/src/compile/mod.rs deleted file mode 100644 index b53f3f8..0000000 --- a/src/compile/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -use itertools::Itertools; - -mod compile; -mod ir; - -pub fn compile(expr: &str) -> anyhow::Result { - let root = rnix::Root::parse(expr); - if !root.errors().is_empty() { - return Err(anyhow::anyhow!( - root.errors().iter().map(|err| err.to_string()).join(";") - )); - } - assert!(root.errors().is_empty()); - let expr = root.tree().expr().unwrap(); - let ir = ir::downgrade(expr)?; - Ok(compile::compile(ir)) -} diff --git a/src/downcast.rs b/src/downcast.rs deleted file mode 100644 index 9a87556..0000000 --- a/src/downcast.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub trait Downcast -where - Self: Sized, -{ - fn downcast_ref(&self) -> Option<&T>; - fn downcast_mut(&mut self) -> Option<&mut T>; - fn downcast(self) -> Result; -} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..cfb760a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,13 @@ +use thiserror::Error; + +pub type Result = core::result::Result; + +#[derive(Error, Debug)] +pub enum Error { + #[error("error occurred during downgrade stage: {0}")] + DowngradeError(String), + #[error("error occurred during evaluation stage: {0}")] + EvalError(String), + #[error("unknown error")] + Unknown, +} diff --git a/src/compile/ir.rs b/src/ir.rs similarity index 93% rename from src/compile/ir.rs rename to src/ir.rs index 47cf446..8121aa9 100644 --- a/src/compile/ir.rs +++ b/src/ir.rs @@ -1,14 +1,13 @@ use std::collections::HashMap; -use anyhow::{Result, anyhow}; use ecow::EcoString; use rnix::ast::{self, Expr}; use crate::bytecode::{ConstIdx, Consts, ThunkIdx}; +use crate::compile::*; +use crate::error::*; use crate::ty::internal as i; -use super::compile::*; - pub fn downgrade(expr: Expr) -> Result { let mut state = DowngradeState::new(); let ir = expr.downgrade(&mut state)?; @@ -19,7 +18,15 @@ pub fn downgrade(expr: Expr) -> Result { }) } -#[macro_export] +trait Downcast +where + Self: Sized, +{ + fn downcast_ref(&self) -> Option<&T>; + fn downcast_mut(&mut self) -> Option<&mut T>; + fn downcast(self) -> core::result::Result; +} + macro_rules! ir { ( $( @@ -30,8 +37,6 @@ macro_rules! ir { ) ,*$(,)? ) => { - use crate::downcast::Downcast; - #[derive(Clone, Debug)] pub enum Ir { $( @@ -73,16 +78,6 @@ macro_rules! ir { } } - impl TryFrom for $ty { - type Error = anyhow::Error; - fn try_from(value: Ir) -> Result { - match value { - Ir::$ty(value) => Ok(value), - _ => Err(anyhow!("")), - } - } - } - impl Downcast<$ty> for Ir { fn downcast_ref(&self) -> Option<&$ty> { match self { @@ -132,12 +127,6 @@ ir! { #[derive(Clone, Debug)] pub struct DynamicAttrPair(pub Ir, pub Ir); -#[derive(Debug)] -pub struct DowngradeError { - errno: u16, - text: String, -} - pub struct DowngradeState { thunks: Vec, consts: Vec, @@ -180,7 +169,9 @@ impl Attrs { .get_mut(&ident) .unwrap() .downcast_mut() - .ok_or(anyhow!(r#""{ident}" already exsists in this set"#)) + .ok_or(Error::DowngradeError(format!( + r#""{ident}" already exsists in this set"# + ))) .and_then(|attrs: &mut Attrs| attrs._insert(path, name, value)) } else { let mut attrs = Attrs { @@ -218,7 +209,9 @@ impl Attrs { match name { Attr::Str(ident) => { if self.stcs.get(&ident).is_some() { - return Err(anyhow!(r#""{ident}" already exsists in this set"#)); + return Err(Error::DowngradeError(format!( + r#""{ident}" already exsists in this set"# + ))); } self.stcs.insert(ident, value); } @@ -349,7 +342,7 @@ impl Downgrade for Expr { match self { Expr::Apply(apply) => apply.downgrade(state), Expr::Assert(assert) => assert.downgrade(state), - Expr::Error(error) => return Err(anyhow!(error.to_string())), + Expr::Error(error) => return Err(Error::DowngradeError(error.to_string())), Expr::IfElse(ifelse) => ifelse.downgrade(state), Expr::Select(select) => select.downgrade(state), Expr::Str(str) => str.downgrade(state), @@ -675,7 +668,11 @@ fn downgrade_inherit( for attr in inherit.attrs() { let ident: EcoString = match downgrade_attr(attr, state)? { Attr::Str(ident) => ident.to_string().into(), - _ => return Err(anyhow!("dynamic attributes not allowed in inherit")), + _ => { + return Err(Error::DowngradeError( + "dynamic attributes not allowed in inherit".to_string(), + )); + } }; let expr = from.map_or_else( || Var { sym: ident.clone() }.ir().ok(), @@ -694,29 +691,31 @@ fn downgrade_inherit( } fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result { + use ast::Attr::*; + use ast::InterpolPart::*; match attr { - ast::Attr::Ident(ident) => Ok(Attr::Str(ident.to_string().into())), - ast::Attr::Str(string) => { + Ident(ident) => Ok(Attr::Str(ident.to_string().into())), + Str(string) => { let parts = string.normalized_parts(); if parts.len() == 1 { - let ast::InterpolPart::Literal(ident) = parts.into_iter().next().unwrap() else { - unreachable!() - }; - Ok(Attr::Str(ident.into())) + match parts.into_iter().next().unwrap() { + Literal(ident) => Ok(Attr::Str(ident.into())), + Interpolation(interpol) => { + Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(state)?)) + } + } } else { let parts = parts .into_iter() .map(|part| match part { - ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(), - ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(state) - } + Literal(lit) => Const { value: lit.into() }.ir().ok(), + Interpolation(interpol) => interpol.expr().unwrap().downgrade(state), }) .collect::>>()?; Ok(Attr::Strs(ConcatStrings { parts })) } } - ast::Attr::Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(state)?)), + Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(state)?)), } } diff --git a/src/jit/codegen.rs b/src/jit/codegen.rs new file mode 100644 index 0000000..01b219d --- /dev/null +++ b/src/jit/codegen.rs @@ -0,0 +1,5 @@ +use super::JITContext; + +pub trait CodeGen { + fn codegen(self, ctx: JITContext); +} diff --git a/src/jit/mod.rs b/src/jit/mod.rs index 1849853..468e83a 100644 --- a/src/jit/mod.rs +++ b/src/jit/mod.rs @@ -1,21 +1,27 @@ +use inkwell::OptimizationLevel; use inkwell::builder::Builder; use inkwell::context::Context; -use inkwell::module::Module; -use inkwell::OptimizationLevel; use inkwell::execution_engine::ExecutionEngine; +use inkwell::module::Module; -pub struct JIT<'ctx> { +mod codegen; + +pub use codegen::CodeGen; + +pub struct JITContext<'ctx> { context: &'ctx Context, module: Module<'ctx>, - builder: Builder<'ctx>, + builder: Builder<'ctx>, execution_engine: ExecutionEngine<'ctx>, } -impl<'ctx> JIT<'ctx> { - pub fn new(context: &Context) -> JIT { +impl<'ctx> JITContext<'ctx> { + pub fn new(context: &Context) -> JITContext { let module = context.create_module("nixjit"); - JIT { - execution_engine: module.create_jit_execution_engine(OptimizationLevel::None).unwrap(), + JITContext { + execution_engine: module + .create_jit_execution_engine(OptimizationLevel::None) + .unwrap(), builder: context.create_builder(), context, module, diff --git a/src/lib.rs b/src/lib.rs index 05cfbe3..09c0095 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,14 @@ mod builtins; mod bytecode; -mod compile; -mod downcast; mod ty; -mod vm; -mod jit; -pub use compile::compile; +pub mod compile; +pub mod error; +pub mod ir; +#[cfg(feature = "jit")] +pub mod jit; +#[cfg(feature = "vm")] +pub mod vm; + pub use ty::public::Value; -pub use vm::run; diff --git a/src/ty/internal/attrset.rs b/src/ty/internal/attrset.rs index 28e27d8..8943c76 100644 --- a/src/ty/internal/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -1,15 +1,15 @@ use std::cell::RefCell; use std::sync::Arc; -use anyhow::Result; use derive_more::Constructor; use rpds::HashTrieMapSync; +use crate::error::Result; +use crate::vm::VM; + use super::super::common::Symbol; use super::super::public as p; - use super::{ToPublic, Value}; -use crate::vm::VM; #[derive(Debug, Constructor, Clone, PartialEq)] pub struct AttrSet { @@ -28,7 +28,7 @@ impl AttrSet { } pub fn push_attr(&mut self, sym: Symbol, val: Value) { - if self.data.get(&sym).is_some() { + if let Some(_) = self.data.get_mut(&sym) { todo!() } self.data.insert_mut(sym, val); diff --git a/src/ty/internal/cnst.rs b/src/ty/internal/cnst.rs index f33f20a..7ee884f 100644 --- a/src/ty/internal/cnst.rs +++ b/src/ty/internal/cnst.rs @@ -1,6 +1,4 @@ -use anyhow::Error; use derive_more::{IsVariant, Unwrap}; - use ecow::EcoString; #[derive(Debug, Clone, IsVariant, Unwrap)] @@ -47,49 +45,6 @@ impl From<&str> for Const { } } -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::*; diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index 6cb7a82..0b0ec4c 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -3,8 +3,8 @@ use itertools::Itertools; use rpds::HashTrieMap; use crate::bytecode::OpCodes; +use crate::error::Result; use crate::ty::internal::{Thunk, Value}; - use crate::vm::{CapturedEnv, VM}; #[derive(Debug, Clone)] @@ -33,7 +33,7 @@ impl Func { } } - pub fn call(self, vm: &VM, arg: Value) -> Value { + pub fn call(self, vm: &VM, arg: Value) -> Result { use Param::*; let env = self.env.released(); @@ -71,7 +71,7 @@ impl Func { } } - vm.eval(self.opcodes, env).unwrap() + vm.eval(self.opcodes, env) } pub fn push_ident_param(&mut self, param: EcoString) { diff --git a/src/ty/internal/list.rs b/src/ty/internal/list.rs index 6cb5e9c..fa5400e 100644 --- a/src/ty/internal/list.rs +++ b/src/ty/internal/list.rs @@ -1,11 +1,11 @@ -use anyhow::Result; use derive_more::Constructor; use rpds::VectorSync; +use crate::error::Result; use crate::ty::public as p; +use crate::vm::VM; use super::{ToPublic, Value}; -use crate::vm::VM; #[derive(Debug, Constructor, Clone, PartialEq)] pub struct List { diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index 4dc6875..7afa5c5 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -1,7 +1,6 @@ use std::cell::RefCell; use std::sync::Arc; -use anyhow::{Result, anyhow}; use derive_more::{IsVariant, Unwrap}; use super::common as c; @@ -11,6 +10,7 @@ use super::public as p; use c::Symbol; use crate::bytecode::OpCodes; +use crate::error::*; use crate::vm::{Env, VM}; mod attrset; @@ -65,9 +65,10 @@ impl Thunk { match &*self.thunk.borrow() { _Thunk::Value(value) => return Ok(value.as_ref().clone()), _Thunk::SuspendedFrom(from) => { - return Err(anyhow!( - "already suspended from {from:p} (infinite recursion encountered)" - )); + return Err(Error::EvalError(format!( + "thunk {:p} already suspended from {from:p} (infinite recursion encountered)", + self as *const Thunk + ))); } _Thunk::Code(_) => (), } @@ -77,9 +78,7 @@ impl Thunk { _Thunk::SuspendedFrom(self as *const Thunk), ) .unwrap_code(); - let value = vm - .eval(opcodes, self.env.borrow().clone().unwrap()) - .unwrap(); + let value = vm.eval(opcodes, self.env.borrow().clone().unwrap())?; let _ = std::mem::replace( &mut *self.thunk.borrow_mut(), _Thunk::Value(value.clone().into()), @@ -199,9 +198,9 @@ impl Value { } } - pub fn call(self, vm: &VM, args: Vec) -> Value { + pub fn call(self, vm: &VM, args: Vec) -> Result { use Value::*; - match self { + Ok(match self { PrimOp(func) => func.call(vm, args), PartialPrimOp(func) => func.call(vm, args), mut func @ Value::Func(_) => { @@ -209,12 +208,12 @@ impl Value { while let Some(arg) = iter.next() { func = match func { PrimOp(func) => { - return func.call(vm, [arg].into_iter().chain(iter).collect()); + return Ok(func.call(vm, [arg].into_iter().chain(iter).collect())); } PartialPrimOp(func) => { - return func.call(vm, [arg].into_iter().chain(iter).collect()); + return Ok(func.call(vm, [arg].into_iter().chain(iter).collect())); } - Func(func) => func.call(vm, arg), + Func(func) => func.call(vm, arg)?, _ => todo!(), } } @@ -222,7 +221,7 @@ impl Value { } x @ Catchable(_) => x, _ => todo!(), - } + }) } pub fn not(self) -> Value { diff --git a/src/ty/public/cnst.rs b/src/ty/public/cnst.rs index 2c95aaa..3b9c69e 100644 --- a/src/ty/public/cnst.rs +++ b/src/ty/public/cnst.rs @@ -1,9 +1,10 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; -use anyhow::Error; use derive_more::{IsVariant, Unwrap}; use ecow::EcoString; +use crate::error::Error; + use super::super::internal as i; #[derive(Debug, Clone, IsVariant, Unwrap)] diff --git a/src/vm/stack.rs b/src/vm/stack.rs index e054c06..7517356 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -1,8 +1,7 @@ -use std::mem::{MaybeUninit, size_of, transmute}; +use std::mem::{MaybeUninit, replace, size_of, transmute}; use std::ops::Deref; -use anyhow::{Result, anyhow}; - +use crate::error::*; use crate::ty::internal::Value; pub const STACK_SIZE: usize = 8 * 1024 / size_of::(); @@ -12,6 +11,12 @@ pub struct Stack { top: usize, } +macro_rules! into { + ($e:expr) => { + unsafe { transmute($e) } + }; +} + impl Stack { pub fn new() -> Self { Stack { @@ -27,51 +32,34 @@ impl Stack { pub fn push(&mut self, item: Value) -> Result<()> { self.items .get_mut(self.top) - .map_or(Err(anyhow!("stack overflow")), |ok| Ok(ok))? + .map_or(Err(Error::EvalError("stack overflow".to_string())), |ok| { + Ok(ok) + })? .write(item); self.top += 1; Ok(()) } - pub fn pop(&mut self) -> Result { + pub fn pop(&mut self) -> Value { self.top -= 1; - let item = self - .items - .get_mut(self.top) - .map_or(Err(anyhow!("stack empty")), |ok| Ok(ok))?; - unsafe { Ok(std::mem::replace(item, MaybeUninit::uninit()).assume_init()) } + let item = self.items.get_mut(self.top).unwrap(); + + unsafe { replace(item, MaybeUninit::uninit()).assume_init() } } pub fn tos(&self) -> Result<&Value> { if self.top == 0 { - Err(anyhow!("")) + panic!("stack empty") } else { - unsafe { Ok(transmute(self.items.get(self.top - 1).unwrap())) } + Ok(into!(&self.items[self.top - 1])) } } pub fn tos_mut(&mut self) -> Result<&mut Value> { if self.top == 0 { - Err(anyhow!("")) + panic!("stack empty") } else { - unsafe { Ok(transmute(self.items.get_mut(self.top - 1).unwrap())) } - } - } - - pub fn with_tos(&self, func: impl Fn(&Value)) -> Result<()> { - if self.top != 0 { - Err(anyhow!("")) - } else { - unsafe { func(transmute(self.items.get(self.top - 1).unwrap())) } - Ok(()) - } - } - pub fn with_tos_mut(&mut self, func: impl Fn(&mut Value)) -> Result<()> { - if self.top != 0 { - Err(anyhow!("")) - } else { - unsafe { func(transmute(self.items.get_mut(self.top - 1).unwrap())) } - Ok(()) + Ok(into!(&mut self.items[self.top - 1])) } } } @@ -79,7 +67,7 @@ impl Stack { impl Deref for Stack { type Target = [Value]; fn deref(&self) -> &Self::Target { - unsafe { transmute(&self.items[0..self.top]) } + into!(&self.items[0..self.top]) } } diff --git a/src/vm/test.rs b/src/vm/test.rs index f6cd871..52d533c 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -2,6 +2,7 @@ use ecow::EcoString; use rpds::{ht_map_sync, vector_sync}; use crate::compile::compile; +use crate::ir::downgrade; use crate::ty::common::Symbol; use crate::ty::public::*; @@ -9,7 +10,8 @@ use super::vm::run; #[inline] fn test_expr(expr: &str, expected: Value) { - let prog = compile(expr).unwrap(); + let downgraded = downgrade(rnix::Root::parse(expr).tree().expr().unwrap()).unwrap(); + let prog = compile(downgraded); dbg!(&prog); assert_eq!(run(prog).unwrap(), expected); } diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 527dbdd..676cb1f 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,9 +1,8 @@ use std::sync::Arc; -use anyhow::{Result, anyhow}; - use crate::builtins::env; use crate::bytecode::{self, BinOp, OpCode, OpCodes, Program, Thunks, UnOp}; +use crate::error::*; use crate::ty::common::Symbol; use crate::ty::internal::*; use crate::ty::public as p; @@ -44,10 +43,8 @@ impl VM { } assert_eq!(stack.len(), 1); let mut ret = stack.pop(); - if let Ok(ref mut value) = ret { - value.force(self)?; - } - ret + ret.force(self)?; + Ok(ret) } #[inline] @@ -58,7 +55,7 @@ impl VM { env: Arc, ) -> Result { match opcode { - OpCode::Illegal => return Err(anyhow!("illegal opcode")), + OpCode::Illegal => panic!("illegal opcode"), OpCode::Const { value } => stack.push(Value::Const(value))?, OpCode::LoadThunk { idx } => { self.thunks[idx].capture(env); @@ -72,23 +69,23 @@ impl VM { } OpCode::Jmp { step } => return Ok(step), OpCode::JmpIfTrue { step } => { - if let Value::Const(Const::Bool(true)) = stack.pop()? { + if let Value::Const(Const::Bool(true)) = stack.pop() { return Ok(step); } } OpCode::JmpIfFalse { step } => { - if let Value::Const(Const::Bool(false)) = stack.pop()? { + if let Value::Const(Const::Bool(false)) = stack.pop() { return Ok(step); } } OpCode::Call { arity } => { let mut args = Vec::with_capacity(arity); for _ in 0..arity { - args.insert(0, stack.pop()?); + args.insert(0, stack.pop()); } - let mut func = stack.pop()?; + let mut func = stack.pop(); func.force(self)?; - stack.push(func.call(self, args))?; + stack.push(func.call(self, args)?)?; } OpCode::Func { idx } => { stack.push(Value::Func(Func::new( @@ -125,7 +122,7 @@ impl VM { } OpCode::UnOp { op } => { use UnOp::*; - let mut value = stack.pop()?; + let mut value = stack.pop(); value.force(self)?; stack.push(match op { Not => value.not(), @@ -133,8 +130,8 @@ impl VM { } OpCode::BinOp { op } => { use BinOp::*; - let mut rhs = stack.pop()?; - let mut lhs = stack.pop()?; + let mut rhs = stack.pop(); + let mut lhs = stack.pop(); lhs.force(self)?; rhs.force(self)?; stack.push(match op { @@ -147,7 +144,7 @@ impl VM { })?; } OpCode::ConcatString => { - let mut rhs = stack.pop()?; + let mut rhs = stack.pop(); rhs.force(self)?; stack.tos_mut()?.concat_string(rhs); } @@ -158,7 +155,7 @@ impl VM { stack.push(Value::List(List::empty()))?; } OpCode::PushElem => { - let elem = stack.pop()?; + let elem = stack.pop(); stack.tos_mut()?.push(elem); } OpCode::AttrSet => { @@ -169,13 +166,13 @@ impl VM { stack.push(Value::RecAttrSet(RecAttrSet::new(new)))?; } OpCode::PushStaticAttr { name } => { - let val = stack.pop()?; + let val = stack.pop(); stack.tos_mut()?.push_attr(Symbol::new(name), val); } OpCode::PushDynamicAttr => { - let val = stack.pop()?; - let mut sym = stack.pop().unwrap(); - sym.coerce_to_string(); + let val = stack.pop(); + let mut sym = stack.pop(); + sym.force(self)?.coerce_to_string(); let sym = sym.unwrap_const().unwrap_string().into(); stack.tos_mut()?.push_attr(sym, val); } @@ -183,22 +180,22 @@ impl VM { stack.tos_mut()?.force(self)?.select(Symbol::new(sym)); } OpCode::SelectOrDefault { sym } => { - let default = stack.pop()?; + let default = stack.pop(); stack .tos_mut()? .force(self)? .select_with_default(Symbol::new(sym), default); } OpCode::SelectDynamic => { - let mut val = stack.pop().unwrap(); + let mut val = stack.pop(); val.force(self)?; val.coerce_to_string(); let sym = val.unwrap_const().unwrap_string().into(); stack.tos_mut()?.force(self)?.select(sym); } OpCode::SelectDynamicOrDefault => { - let default = stack.pop()?; - let mut val = stack.pop().unwrap(); + let default = stack.pop(); + let mut val = stack.pop(); val.force(self)?; val.coerce_to_string(); let sym = val.unwrap_const().unwrap_string().into(); @@ -211,7 +208,7 @@ impl VM { stack.tos_mut()?.force(self)?.has_attr(Symbol::new(sym)); } OpCode::HasDynamicAttr => { - let mut val = stack.pop().unwrap(); + let mut val = stack.pop(); val.coerce_to_string(); let sym = val.unwrap_const().unwrap_string().into(); stack.tos_mut()?.force(self)?.has_attr(sym); @@ -219,10 +216,10 @@ impl VM { OpCode::LookUp { sym } => { stack.push( env.lookup(Symbol::new(sym.clone())) - .ok_or(anyhow!(r#""{sym}" not found"#))?, + .ok_or(Error::EvalError(format!(r#""{sym}" not found"#)))?, )?; } - OpCode::EnterEnv => match stack.pop()? { + OpCode::EnterEnv => match stack.pop() { Value::AttrSet(attrs) => env.enter(attrs.into_inner()), Value::RecAttrSet(attrs) => env.enter(attrs.into_inner()), _ => unreachable!(), @@ -231,7 +228,7 @@ impl VM { env.leave(); } OpCode::Assert => { - if !stack.pop()?.unwrap_const().unwrap_bool() { + if !stack.pop().unwrap_const().unwrap_bool() { todo!() } }