unify stack

This commit is contained in:
minish 2025-10-06 14:01:10 -04:00
parent fb61028d37
commit ea9614a903
Signed by: min
SSH Key Fingerprint: SHA256:mf+pUTmK92Y57BuCjlkBdd82LqztTfDCQIUp0fCKABc
2 changed files with 124 additions and 49 deletions

View File

@ -5,38 +5,45 @@ use crate::{
parser::Expr, parser::Expr,
}; };
use stack::Stack;
mod stack;
struct Scope<'a> { struct Scope<'a> {
/* Faster than a hashmap for now? */ values: Vec<(Ident, Rc<RefMeta>)>,
idents: Vec<(Ident, Rc<RefMeta>)>,
parent: Option<&'a Scope<'a>>, parent: Option<&'a Scope<'a>>,
} }
impl<'a> Scope<'a> { impl<'a> Stack<'a> for Scope<'a> {
fn with_parent(parent: Option<&'a Scope>) -> Self { type Value = (Ident, Rc<RefMeta>);
Scope { type Input = Ident;
idents: Vec::new(), type Output = Rc<RefMeta>;
fn with_parent(parent: Option<&'a Self>) -> Self {
Self {
values: Vec::new(),
parent, parent,
} }
} }
fn parent(&self) -> Option<&'a Self> {
self.parent
}
fn values(&self) -> &Vec<Self::Value> {
&self.values
}
fn values_mut(&mut self) -> &mut Vec<Self::Value> {
&mut self.values
}
fn find_map(_: usize, value: &Self::Value, input: &Self::Input) -> Option<Self::Output> {
(value.0 == *input).then_some(value.1.clone())
}
}
impl Scope<'_> {
fn assigned(&mut self, id: Ident) { fn assigned(&mut self, id: Ident) {
if self.find(&id).is_none() { if self.find(&id).is_none() {
self.idents.push((id, Rc::default())); self.push((id, Rc::default()));
} }
} }
fn find(&self, id: &Ident) -> Option<(Rc<RefMeta>, bool)> {
let mut cur = Some(self);
let mut is_up = false;
while let Some(scope) = cur {
let Some((_, fs)) = scope.idents.iter().rev().find(|i| i.0 == *id) else {
cur = scope.parent;
is_up = true;
continue;
};
return Some((fs.clone(), is_up));
}
None
}
} }
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@ -72,7 +79,7 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
} }
Expr::Literal(Literal::Ident(id, ref_stat)) => { Expr::Literal(Literal::Ident(id, ref_stat)) => {
// lookup literal // lookup literal
let Some((rs, used_up)) = scope.find(id) else { let Some((rs, up_levels)) = scope.find(id) else {
panic!("unfound variable") panic!("unfound variable")
}; };
// increment # of uses // increment # of uses
@ -83,7 +90,7 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
stat: rs.clone(), stat: rs.clone(),
}); });
// if we used something external to this scope, note it // if we used something external to this scope, note it
if used_up { if up_levels != 0 {
fs.is_unreturnable.set(true); fs.is_unreturnable.set(true);
rs.is_shared.set(true); rs.is_shared.set(true);
} }
@ -162,14 +169,14 @@ enum Stkval {
/* 4b blank ; 8b offset */ /* 4b blank ; 8b offset */
Local(u8), Local(u8),
/* 4b up levels ; 8b offset */ /* 4b up levels ; 8b offset */
Foreign(u8), Shared(u8, u8),
} }
/* 3b type tag */ /* 3b type tag */
enum Val { enum Val {
Stack(Stkval), Stack(Stkval),
/* u16 len, LEN data */ /* u16 len, LEN data */
String(String), String(String),
/* 1b returnability, insts */ /* 1b returnability, 4b arity, insts */
Func(bool, Vec<Inst>), Func(bool, Vec<Inst>),
/* 1b value */ /* 1b value */
Bool(bool), Bool(bool),
@ -180,12 +187,15 @@ enum Val {
/* ... */ /* ... */
Nil, Nil,
} }
/* 5b inst type */
enum Inst { enum Inst {
/* ... */ /* ... */
Copy(Val), Copy(Val),
/* pop a1? ; pop a2? */ /* pop a1? ; pop a2? */
Eq(bool, bool, Val, Val), Eq(bool, bool, Val, Val),
Gt(bool, bool, Val, Val), Gt(bool, bool, Val, Val),
/* is conditional? ; what condition? */
Skip(bool, bool, i16),
/* is conditional? ; what condition? ; pop result? */ /* is conditional? ; what condition? ; pop result? */
Call(bool, bool, bool, Val), Call(bool, bool, bool, Val),
/* pop a1? ; pop a2 */ /* pop a1? ; pop a2 */
@ -218,6 +228,47 @@ enum FSValue {
/// so it can all be cleared once the block is left /// so it can all be cleared once the block is left
struct BlockBuild {} struct BlockBuild {}
/// A stack that keeps track of values during translation.
/// (Local or shared)
struct FakeStack<'a> {
values: Vec<FSValue>,
parent: Option<&'a FakeStack<'a>>,
}
impl<'a> Stack<'a> for FakeStack<'a> {
type Value = FSValue;
type Input = Ident;
type Output = usize;
fn with_parent(parent: Option<&'a Self>) -> Self {
Self {
values: Vec::new(),
parent,
}
}
fn parent(&self) -> Option<&'a Self> {
self.parent
}
fn values(&self) -> &Vec<Self::Value> {
&self.values
}
fn values_mut(&mut self) -> &mut Vec<Self::Value> {
&mut self.values
}
fn find_map(index: usize, value: &Self::Value, input: &Self::Input) -> Option<Self::Output> {
matches!(value, FSValue::Var(x) if x == input).then_some(index)
}
}
impl FakeStack<'_> {
fn get(&mut self, id: Ident) -> (usize, u16) {
self.find(&id).unwrap_or_else(|| {
let i = self.values().len();
self.push(FSValue::Var(id));
(i, 0)
})
}
}
/// Build scope of a function. /// Build scope of a function.
/// ///
/// * Starts with a base block scope that includes any arguments passed /// * Starts with a base block scope that includes any arguments passed
@ -225,32 +276,14 @@ struct BlockBuild {}
/// * Keeps track of its own shared stack (contains vars that higher functions access) /// * Keeps track of its own shared stack (contains vars that higher functions access)
/// * Keeps track of its own local stack (vars only used locally) /// * Keeps track of its own local stack (vars only used locally)
struct FuncBuild<'a> { struct FuncBuild<'a> {
parent: &'a FuncBuild<'a>, parent: Option<&'a FuncBuild<'a>>,
insts: Vec<Inst>, insts: Vec<Inst>,
shared_stack: Vec<FSValue>, shared: FakeStack<'a>,
local_stack: Vec<FSValue>, local: FakeStack<'a>,
} }
impl<'a> FuncBuild<'a> { impl FuncBuild<'_> {
fn local_find(&mut self, id: Ident) -> Stkval { fn translate(&mut self, bb: &mut BlockBuild, e: &Expr) {
let idx = if let Some((idx, _)) = self
.local_stack
.iter()
.enumerate()
.rev()
.find(|(_, v)| matches!(v, FSValue::Var(x) if *x == id))
{
idx
} else {
let idx = self.local_stack.len();
self.local_stack.push(FSValue::Var(id));
idx
};
Stkval::Local(idx as u8)
}
fn translate(&mut self, e: &Expr) {
match e { match e {
_ => unimplemented!(), _ => unimplemented!(),
} }

42
src/compiler/stack.rs Normal file
View File

@ -0,0 +1,42 @@
pub trait Stack<'a>
where
Self: 'a,
{
type Value;
type Input;
type Output;
fn with_parent(parent: Option<&'a Self>) -> Self;
fn parent(&self) -> Option<&'a Self>;
fn values(&self) -> &Vec<Self::Value>;
fn values_mut(&mut self) -> &mut Vec<Self::Value>;
fn find_map(index: usize, value: &Self::Value, input: &Self::Input) -> Option<Self::Output>;
fn push(&mut self, value: Self::Value) {
self.values_mut().push(value);
}
fn find(&self, input: &Self::Input) -> Option<(Self::Output, u16)> {
let mut cur = Some(self);
let mut up_levels = 0;
while let Some(stack) = cur {
let Some(output) = stack
.values()
.iter()
.enumerate()
.rev()
.find_map(|(index, value)| Self::find_map(index, value, input))
else {
cur = stack.parent();
up_levels += 1;
continue;
};
return Some((output, up_levels));
}
None
}
}