feat: SCC analysis (thunk capture WIP)

This commit is contained in:
2025-06-17 11:53:54 +08:00
parent b2d2490327
commit 7f6848c9e5
19 changed files with 501 additions and 458 deletions

View File

@@ -6,14 +6,14 @@ use hashbrown::HashMap;
use crate::stack::Stack;
use crate::ty::internal::{EnvRef, Value};
use crate::error::{Error, Result};
#[derive(Clone)]
pub struct VmEnv {
let_: Rc<RefCell<Stack<Vec<Value>, 1000>>>,
with: Rc<With>,
args: Rc<RefCell<Stack<Value, 1000>>>,
new: bool,
pub id: usize,
cache: Vec<HashMap<usize, Value>>,
with: Vec<Rc<HashMap<EcoString, Value>>>,
args: Vec<Value>,
pub args_len: usize,
}
#[derive(Clone)]
@@ -41,104 +41,71 @@ pub enum Type {
impl VmEnv {
pub fn new() -> Self {
Self {
let_: Rc::default(),
with: With {
map: None,
last: None,
}
.into(),
args: Rc::default(),
new: false,
id: 0,
cache: Vec::from([HashMap::new()]),
with: Vec::new(),
args: Vec::new(),
args_len: 0,
}
}
pub fn lookup_let(&self, level: usize, idx: usize) -> Value {
self.let_.borrow()[level][idx].clone()
pub fn enter_cache_level<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
self.cache.push(HashMap::new());
let ret = f(self);
self.cache.pop();
ret
}
pub fn pop_cache_level(&mut self) {
self.cache.pop();
}
pub fn insert_cache(&mut self, idx: usize, val: Value) {
self.cache.last_mut().unwrap().insert(idx, val);
}
pub fn lookup_cache(&mut self, idx: usize, f: impl FnOnce(&mut VmEnv) -> Result<Value>) -> Result<Value> {
for level in self.cache.iter().rev() {
if let Some(ret) = level.get(&idx) {
return ret.clone().ok();
}
}
let val = f(self)?;
self.cache.last_mut().unwrap().insert(idx, val.clone());
val.ok()
}
pub fn lookup_arg(&self, level: usize) -> Value {
self.args.borrow()[level].clone()
self.args[self.args.len() - level - 1].clone()
}
pub fn lookup_with(&self, symbol: &EcoString) -> Option<Value> {
self.with.lookup(symbol)
}
pub fn has_with(&self) -> bool {
self.with.map.is_some()
}
pub fn enter_let(&mut self, mut map: Vec<Value>) {
if Rc::strong_count(&self.let_) > 1 {
self.let_ = Rc::new_cyclic(|weak| {
let weak = VmEnvWeak {
let_: weak.clone(),
with: Rc::downgrade(&self.with),
args: Rc::downgrade(&self.args),
new: self.new,
id: self.id,
};
map.iter_mut().for_each(|val| {
if let Value::Thunk(thunk) = val {
thunk.capture(EnvRef::Weak(weak.clone()));
}
});
let new = self.let_.as_ref().clone();
new.borrow_mut().push(map).unwrap();
new
})
} else {
let weak = self.downgrade();
map.iter_mut().for_each(|val| {
if let Value::Thunk(thunk) = val {
thunk.capture(EnvRef::Weak(weak.clone()));
}
});
let _ = self.let_.borrow_mut().push(map);
for with in self.with.iter().rev() {
if let Some(ret) = with.get(symbol) {
return Some(ret.clone());
}
}
None
}
pub fn enter_arg(&mut self, val: Value) {
if Rc::strong_count(&self.args) > 1 {
self.args = Rc::new(self.args.as_ref().clone());
}
self.args.borrow_mut().push(val).unwrap()
pub fn enter_arg(&mut self, arg: Value) {
self.args.push(arg)
}
pub fn pop_let(&mut self) {
if Rc::strong_count(&self.let_) > 1 {
self.let_ = Rc::new(self.let_.as_ref().clone());
}
self.let_.borrow_mut().pop();
pub fn pop_args(&mut self, len: usize) -> Vec<Value> {
self.args.split_off(self.args.len() - len)
}
pub fn pop_arg(&mut self) {
if Rc::strong_count(&self.args) > 1 {
self.args = Rc::new(self.args.as_ref().clone());
}
self.args.borrow_mut().pop();
pub fn enter_args(&mut self, args: Vec<Value>) {
self.args.extend(args);
}
#[must_use]
pub fn enter_with(&self, map: Rc<HashMap<EcoString, Value>>) -> Self {
Self {
let_: self.let_.clone(),
with: self.with.clone().enter(map),
args: self.args.clone(),
new: self.new,
id: self.id + 1,
}
pub fn pop_with(&mut self) {
self.with.pop();
}
pub fn downgrade(&self) -> VmEnvWeak {
VmEnvWeak {
let_: Rc::downgrade(&self.let_),
with: Rc::downgrade(&self.with),
args: Rc::downgrade(&self.args),
id: self.id,
new: self.new,
}
pub fn enter_with(&mut self, map: Rc<HashMap<EcoString, Value>>) {
self.with.push(map)
}
}
@@ -157,15 +124,3 @@ impl With {
})
}
}
impl VmEnvWeak {
pub fn upgrade(&self) -> VmEnv {
VmEnv {
let_: self.let_.upgrade().unwrap(),
with: self.with.upgrade().unwrap(),
args: self.args.upgrade().unwrap(),
id: self.id,
new: self.new,
}
}
}