diff --git a/src/compiler.rs b/src/compiler.rs index 92eaf18..5404e41 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -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)>, + values: Vec<(Ident, Rc)>, 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); + type Input = Ident; + type Output = Rc; + + 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.values + } + fn values_mut(&mut self) -> &mut Vec { + &mut self.values + } + + fn find_map(_: usize, value: &Self::Value, input: &Self::Input) -> Option { + (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, 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), /* 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, + 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.values + } + fn values_mut(&mut self) -> &mut Vec { + &mut self.values + } + + fn find_map(index: usize, value: &Self::Value, input: &Self::Input) -> Option { + 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, - shared_stack: Vec, - local_stack: Vec, + 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!(), } diff --git a/src/compiler/stack.rs b/src/compiler/stack.rs new file mode 100644 index 0000000..594db71 --- /dev/null +++ b/src/compiler/stack.rs @@ -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; + fn values_mut(&mut self) -> &mut Vec; + + fn find_map(index: usize, value: &Self::Value, input: &Self::Input) -> Option; + + 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 + } +}