feat: SCC analysis (thunk capture WIP)
This commit is contained in:
@@ -14,7 +14,7 @@ use super::super::public as p;
|
||||
use super::Value;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Constructor, Clone, PartialEq)]
|
||||
#[derive(Constructor, Clone, PartialEq, Debug)]
|
||||
pub struct AttrSet {
|
||||
data: HashMap<EcoString, Value>,
|
||||
}
|
||||
@@ -61,7 +61,7 @@ impl AttrSet {
|
||||
let item = item?;
|
||||
let Some(Value::AttrSet(attrs)) = data.get(&item) else {
|
||||
return Err(Error::EvalError(format!(
|
||||
"{} not found",
|
||||
"attribute {} not found",
|
||||
Symbol::from(item)
|
||||
)));
|
||||
};
|
||||
@@ -73,7 +73,10 @@ impl AttrSet {
|
||||
.ok_or_else(|| Error::EvalError(format!("{} not found", Symbol::from(last))))
|
||||
}
|
||||
|
||||
pub fn has_attr(&self, mut path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<bool> {
|
||||
pub fn has_attr(
|
||||
&self,
|
||||
mut path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
||||
) -> Result<bool> {
|
||||
let mut data = &self.data;
|
||||
let last = path.nth_back(0).unwrap();
|
||||
for item in path {
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::ty::public as p;
|
||||
|
||||
use super::Value;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct List {
|
||||
data: EcoVec<Value>,
|
||||
}
|
||||
@@ -57,15 +57,6 @@ impl List {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn capture(&mut self, env: &Weak<VmEnv>) {
|
||||
self.data.iter().for_each(|v| {
|
||||
if let Value::Thunk(ref thunk) = v.clone() {
|
||||
todo!()
|
||||
// thunk.capture_env_weak(env.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> EcoVec<Value> {
|
||||
self.data
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::cell::RefCell;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -30,17 +29,19 @@ pub enum EnvRef {
|
||||
Weak(VmEnvWeak),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ThunkRef {
|
||||
pub idx: usize,
|
||||
pub env: Option<EnvRef>,
|
||||
// pub env: Option<EnvRef>,
|
||||
}
|
||||
|
||||
impl ThunkRef {
|
||||
pub fn new(idx: usize) -> Self {
|
||||
ThunkRef { idx, env: None }
|
||||
ThunkRef {
|
||||
idx, /* env: None */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn capture(&mut self, env: EnvRef) {
|
||||
let _ = self.env.insert(env);
|
||||
}
|
||||
@@ -49,9 +50,9 @@ impl ThunkRef {
|
||||
replace_with_or_abort(&mut self.env, |env| {
|
||||
env.map(|env| EnvRef::Strong(env.upgraded()))
|
||||
});
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
/*
|
||||
impl EnvRef {
|
||||
pub fn upgraded(self) -> VmEnv {
|
||||
match self {
|
||||
@@ -59,9 +60,9 @@ impl EnvRef {
|
||||
EnvRef::Strong(strong) => strong,
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
#[derive(IsVariant, Unwrap, Clone)]
|
||||
#[derive(IsVariant, Unwrap, Clone, Debug)]
|
||||
pub enum Value {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
@@ -74,7 +75,8 @@ pub enum Value {
|
||||
Catchable(EcoString),
|
||||
PrimOp(Rc<PrimOp>),
|
||||
PartialPrimOp(Rc<PartialPrimOp>),
|
||||
Func(ThunkRef),
|
||||
Func(usize),
|
||||
PartialFunc(usize, Vec<Value>),
|
||||
}
|
||||
|
||||
impl Hash for Value {
|
||||
@@ -133,7 +135,8 @@ pub enum ValueAsRef<'v> {
|
||||
Catchable(&'v str),
|
||||
PrimOp(&'v PrimOp),
|
||||
PartialPrimOp(&'v PartialPrimOp),
|
||||
Func(&'v ThunkRef),
|
||||
Func(usize),
|
||||
PartialFunc(usize, &'v Vec<Value>),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
@@ -152,7 +155,8 @@ impl Value {
|
||||
Catchable(x) => R::Catchable(x),
|
||||
PrimOp(x) => R::PrimOp(x),
|
||||
PartialPrimOp(x) => R::PartialPrimOp(x),
|
||||
Func(x) => R::Func(x),
|
||||
Func(x) => R::Func(*x),
|
||||
PartialFunc(x, args) => R::PartialFunc(*x, args),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +180,7 @@ impl Value {
|
||||
PrimOp(_) => "lambda",
|
||||
PartialPrimOp(_) => "lambda",
|
||||
Func(_) => "lambda",
|
||||
PartialFunc(..) => "lambda",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,24 +192,85 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&mut self, arg: Self, engine: &mut Engine) -> Result<()> {
|
||||
pub fn call(&mut self, args: Vec<Self>, engine: &mut Engine, env: &mut VmEnv) -> Result<()> {
|
||||
use Value::*;
|
||||
if matches!(arg, Value::Catchable(_)) {
|
||||
*self = arg;
|
||||
return Ok(());
|
||||
for arg in args.iter() {
|
||||
if matches!(arg, Value::Catchable(_)) {
|
||||
*self = arg.clone();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
*self = match self {
|
||||
PrimOp(func) => func.call(arg, engine),
|
||||
PartialPrimOp(func) => func.call(arg, engine),
|
||||
Func(func) => {
|
||||
let mut env = func.env.take().unwrap().upgraded().clone();
|
||||
env.enter_arg(arg);
|
||||
let val = engine.eval_thunk(func.idx, &mut env);
|
||||
env.pop_arg();
|
||||
val
|
||||
PrimOp(func) => func.call(args, engine),
|
||||
PartialPrimOp(func) => func.call(args, engine),
|
||||
PartialFunc(idx, old) => {
|
||||
let idx = *idx;
|
||||
let len = args.len() + old.len();
|
||||
env.enter_args(std::mem::take(old));
|
||||
env.enter_cache_level(|env| {
|
||||
let mut args = args.into_iter().peekable();
|
||||
env.enter_arg(args.next().unwrap());
|
||||
let mut ret = engine.eval_thunk(idx, env)?;
|
||||
while args.peek().is_some() {
|
||||
match ret {
|
||||
Value::Func(func) => {
|
||||
env.enter_arg(args.next().unwrap());
|
||||
ret = engine.eval_thunk(func, env)?;
|
||||
}
|
||||
Value::PrimOp(primop) => {
|
||||
ret = primop.call(args.collect(), engine)?;
|
||||
break;
|
||||
}
|
||||
Value::PartialPrimOp(mut primop) => {
|
||||
ret = primop.call(args.collect(), engine)?;
|
||||
break;
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
let args = env.pop_args(len);
|
||||
if let Value::Func(idx) = ret {
|
||||
ret = Value::PartialFunc(idx, args)
|
||||
} else if let Value::PartialFunc(_, old) = &mut ret {
|
||||
old.extend(args);
|
||||
}
|
||||
ret.ok()
|
||||
})
|
||||
}
|
||||
&mut Func(idx) => {
|
||||
let len = args.len();
|
||||
let mut args = args.into_iter().peekable();
|
||||
env.enter_cache_level(|env| {
|
||||
env.enter_arg(args.next().unwrap());
|
||||
let mut ret = engine.eval_thunk(idx, env)?;
|
||||
while args.peek().is_some() {
|
||||
match ret {
|
||||
Value::Func(func) => {
|
||||
env.enter_arg(args.next().unwrap());
|
||||
ret = engine.eval_thunk(func, env)?;
|
||||
}
|
||||
Value::PrimOp(primop) => {
|
||||
ret = primop.call(args.collect(), engine)?;
|
||||
break;
|
||||
}
|
||||
Value::PartialPrimOp(mut primop) => {
|
||||
ret = primop.call(args.collect(), engine)?;
|
||||
break;
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
let args = env.pop_args(len);
|
||||
if let Value::Func(idx) = ret {
|
||||
ret = Value::PartialFunc(idx, args)
|
||||
} else if let Value::PartialFunc(_, old) = &mut ret {
|
||||
old.extend(args);
|
||||
}
|
||||
ret.ok()
|
||||
})
|
||||
}
|
||||
Catchable(_) => return Ok(()),
|
||||
_ => todo!(),
|
||||
other => todo!("{}", other.typename()),
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -421,7 +487,10 @@ impl Value {
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn has_attr(&mut self, path: impl DoubleEndedIterator<Item = Result<EcoString>>) -> Result<()> {
|
||||
pub fn has_attr(
|
||||
&mut self,
|
||||
path: impl DoubleEndedIterator<Item = Result<EcoString>>,
|
||||
) -> Result<()> {
|
||||
if let Value::AttrSet(attrs) = self {
|
||||
let val = Value::Bool(attrs.has_attr(path)?);
|
||||
*self = val;
|
||||
@@ -441,15 +510,17 @@ impl Value {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn force(&mut self, engine: &mut Engine) -> Result<&mut Self> {
|
||||
pub fn force(&mut self, engine: &mut Engine, env: &mut VmEnv) -> Result<&mut Self> {
|
||||
if let Value::Thunk(thunk) = self {
|
||||
unsafe {
|
||||
let old = std::ptr::read(thunk);
|
||||
let mut env = old.env.unwrap().upgraded();
|
||||
std::ptr::write(
|
||||
self,
|
||||
engine.eval_thunk(old.idx, &mut env)?,
|
||||
);
|
||||
match env.lookup_cache(old.idx, |env| engine.eval_thunk(old.idx, env)) {
|
||||
Ok(ok) => std::ptr::write(self, ok),
|
||||
Err(err) => {
|
||||
std::ptr::write(self, Self::Null);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(self)
|
||||
@@ -480,6 +551,7 @@ impl Value {
|
||||
PrimOp(primop) => Value::PrimOp(primop.name),
|
||||
PartialPrimOp(primop) => Value::PartialPrimOp(primop.name),
|
||||
Func(_) => Value::Func,
|
||||
PartialFunc(..) => Value::Func,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,14 @@ impl PartialEq for PrimOp {
|
||||
}
|
||||
|
||||
impl PrimOp {
|
||||
pub fn call(&self, arg: Value, ctx: &Engine) -> Result<Value> {
|
||||
let mut args = Vec::with_capacity(self.arity);
|
||||
args.push(arg);
|
||||
if self.arity > 1 {
|
||||
pub fn call(&self, args: Vec<Value>, ctx: &Engine) -> Result<Value> {
|
||||
if args.len() > self.arity {
|
||||
todo!()
|
||||
}
|
||||
if self.arity > args.len() {
|
||||
Value::PartialPrimOp(Rc::new(PartialPrimOp {
|
||||
name: self.name,
|
||||
arity: self.arity - 1,
|
||||
arity: self.arity - args.len(),
|
||||
args,
|
||||
func: self.func,
|
||||
}))
|
||||
@@ -38,7 +39,7 @@ impl PrimOp {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PartialPrimOp {
|
||||
pub name: &'static str,
|
||||
arity: usize,
|
||||
@@ -53,12 +54,15 @@ impl PartialEq for PartialPrimOp {
|
||||
}
|
||||
|
||||
impl PartialPrimOp {
|
||||
pub fn call(self: &mut Rc<Self>, arg: Value, ctx: &Engine) -> Result<Value> {
|
||||
pub fn call(self: &mut Rc<Self>, args: Vec<Value>, ctx: &Engine) -> Result<Value> {
|
||||
if self.arity < args.len() {
|
||||
todo!()
|
||||
}
|
||||
let func = self.func;
|
||||
let Some(ret) = ({
|
||||
let self_mut = Rc::make_mut(self);
|
||||
self_mut.args.push(arg);
|
||||
self_mut.arity -= 1;
|
||||
self_mut.arity -= args.len();
|
||||
self_mut.args.extend(args);
|
||||
if self_mut.arity == 0 {
|
||||
Some(func(std::mem::take(&mut self_mut.args), ctx))
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user