feat: stash
This commit is contained in:
@@ -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::<Value>();
|
||||
@@ -12,6 +11,12 @@ pub struct Stack<const CAP: usize> {
|
||||
top: usize,
|
||||
}
|
||||
|
||||
macro_rules! into {
|
||||
($e:expr) => {
|
||||
unsafe { transmute($e) }
|
||||
};
|
||||
}
|
||||
|
||||
impl<const CAP: usize> Stack<CAP> {
|
||||
pub fn new() -> Self {
|
||||
Stack {
|
||||
@@ -27,51 +32,34 @@ impl<const CAP: usize> Stack<CAP> {
|
||||
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<Value> {
|
||||
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<const CAP: usize> Stack<CAP> {
|
||||
impl<const CAP: usize> Deref for Stack<CAP> {
|
||||
type Target = [Value];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { transmute(&self.items[0..self.top]) }
|
||||
into!(&self.items[0..self.top])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
55
src/vm/vm.rs
55
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<Env>,
|
||||
) -> Result<usize> {
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user