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,
};
use stack::Stack;
mod stack;
struct Scope<'a> {
/* Faster than a hashmap for now? */
idents: Vec<(Ident, Rc<RefMeta>)>,
values: Vec<(Ident, Rc<RefMeta>)>,
parent: Option<&'a Scope<'a>>,
}
impl<'a> Scope<'a> {
fn with_parent(parent: Option<&'a Scope>) -> Self {
Scope {
idents: Vec::new(),
impl<'a> Stack<'a> for Scope<'a> {
type Value = (Ident, Rc<RefMeta>);
type Input = Ident;
type Output = Rc<RefMeta>;
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(_: 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) {
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)]
@ -72,7 +79,7 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
}
Expr::Literal(Literal::Ident(id, ref_stat)) => {
// lookup literal
let Some((rs, used_up)) = scope.find(id) else {
let Some((rs, up_levels)) = scope.find(id) else {
panic!("unfound variable")
};
// increment # of uses
@ -83,7 +90,7 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
stat: rs.clone(),
});
// if we used something external to this scope, note it
if used_up {
if up_levels != 0 {
fs.is_unreturnable.set(true);
rs.is_shared.set(true);
}
@ -162,14 +169,14 @@ enum Stkval {
/* 4b blank ; 8b offset */
Local(u8),
/* 4b up levels ; 8b offset */
Foreign(u8),
Shared(u8, u8),
}
/* 3b type tag */
enum Val {
Stack(Stkval),
/* u16 len, LEN data */
String(String),
/* 1b returnability, insts */
/* 1b returnability, 4b arity, insts */
Func(bool, Vec<Inst>),
/* 1b value */
Bool(bool),
@ -180,12 +187,15 @@ enum Val {
/* ... */
Nil,
}
/* 5b inst type */
enum Inst {
/* ... */
Copy(Val),
/* pop a1? ; pop a2? */
Eq(bool, bool, Val, Val),
Gt(bool, bool, Val, Val),
/* is conditional? ; what condition? */
Skip(bool, bool, i16),
/* is conditional? ; what condition? ; pop result? */
Call(bool, bool, bool, Val),
/* pop a1? ; pop a2 */
@ -218,6 +228,47 @@ enum FSValue {
/// so it can all be cleared once the block is left
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.
///
/// * 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 local stack (vars only used locally)
struct FuncBuild<'a> {
parent: &'a FuncBuild<'a>,
parent: Option<&'a FuncBuild<'a>>,
insts: Vec<Inst>,
shared_stack: Vec<FSValue>,
local_stack: Vec<FSValue>,
shared: FakeStack<'a>,
local: FakeStack<'a>,
}
impl<'a> FuncBuild<'a> {
fn local_find(&mut self, id: Ident) -> Stkval {
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) {
impl FuncBuild<'_> {
fn translate(&mut self, bb: &mut BlockBuild, e: &Expr) {
match e {
_ => 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
}
}