unify stack
This commit is contained in:
parent
fb61028d37
commit
ea9614a903
131
src/compiler.rs
131
src/compiler.rs
|
@ -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!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue