From 6bc5646a03aafcc6812204c1198d6ab2085e6059 Mon Sep 17 00:00:00 2001 From: min Date: Mon, 6 Oct 2025 17:18:42 -0400 Subject: [PATCH] wip codegen --- src/compiler.rs | 132 +++++++++++++++++++++++++++++++----------- src/compiler/stack.rs | 6 ++ src/lexer.rs | 4 +- src/main.rs | 6 +- 4 files changed, 109 insertions(+), 39 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 2a48e96..18403ef 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -39,10 +39,13 @@ impl<'a> Stack<'a> for Scope<'a> { } } impl Scope<'_> { - fn assigned(&mut self, id: Ident) { - if self.find(&id).is_none() { - self.push((id, Rc::default())); - } + fn assigned(&mut self, id: Ident) -> Rc { + let Some((rm, _)) = self.find(&id) else { + let rm: Rc = Rc::default(); + self.push((id, rm.clone())); + return rm; + }; + rm } } @@ -55,7 +58,7 @@ pub type FuncStat = Rc; #[derive(Debug, Clone)] pub struct RefStat { pub now: u16, - pub stat: Rc, + pub meta: Rc, } #[derive(Debug, Default)] @@ -67,32 +70,35 @@ pub struct RefMeta { fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) { match e { Expr::Assign(a, b) => { - let Expr::Literal(Literal::Ident(id, _)) = &**a else { + let Expr::Literal(Literal::Ident(id, ref_stat)) = &mut **a else { panic!("invalid assignment"); }; // add to scope - scope.assigned(id.clone()); + let rm = scope.assigned(id.clone()); + + // add ref stat + *ref_stat = Some(RefStat { now: rm.total.get(), meta: rm }); // analyse the value analyze(fs, scope, b); } Expr::Literal(Literal::Ident(id, ref_stat)) => { // lookup literal - let Some((rs, up_levels)) = scope.find(id) else { + let Some((rm, up_levels)) = scope.find(id) else { panic!("unfound variable") }; // increment # of uses - rs.total.update(|c| c + 1); + rm.total.update(|c| c + 1); // set ref meta *ref_stat = Some(RefStat { - now: rs.total.get(), - stat: rs.clone(), + now: rm.total.get(), + meta: rm.clone(), }); // if we used something external to this scope, note it if up_levels != 0 { fs.is_unreturnable.set(true); - rs.is_shared.set(true); + rm.is_shared.set(true); } } // ignore @@ -165,15 +171,17 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) { // --- translate pass --- // /* 1b is up? */ -enum Stkval { +#[derive(Debug, PartialEq, Eq)] +pub enum Stkval { /* 4b blank ; 8b offset */ Local(u8), /* 4b up levels ; 8b offset */ Shared(u8, u8), } /* 3b type tag */ -enum Val { - Stack(Stkval), +#[derive(Debug)] +pub enum Val { + Stack(Stkval, bool), /* u16 len, LEN data */ String(String), /* 1b returnability, 4b arity, insts */ @@ -188,7 +196,8 @@ enum Val { Nil, } /* 5b inst type */ -enum Inst { +#[derive(Debug)] +pub enum Inst { /* ... */ Copy(Val), /* pop a1? ; pop a2? */ @@ -217,17 +226,12 @@ enum Inst { } /// Value on fake stack. +#[derive(Debug)] enum FSValue { Var(Ident), Any, } -/// Build scope of a block. -/// -/// Keeps track of where on the stack a block started, -/// 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> { @@ -259,15 +263,6 @@ impl<'a> Stack<'a> for FakeStack<'a> { 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. /// @@ -297,8 +292,75 @@ impl<'a> FuncBuild<'a> { } } - fn translate(&mut self, bb: &mut BlockBuild, e: &Expr) { + fn find(&mut self, id: &Ident) -> Stkval { + self.shared + .find(id) + .map(|(count, up_levels)| Stkval::Shared(up_levels as u8, count as u8)) + .or_else(|| self.local.find(id).map(|(c, _)| Stkval::Local(c as u8))) + .unwrap() + } + + fn push_any(&mut self) -> Stkval { + // println!("PUSHING ANY TO {:?}", self.local.values()); + let i = self.local.height(); + self.local.push(FSValue::Any); + Stkval::Local(i as u8) + } + + fn is_drop(&mut self, v: &Val) -> bool { + if let Val::Stack(Stkval::Local(i), true) = v { + self.local.pop(*i as usize); + true + } else { + false + } + } + fn is_drop2(&mut self, v1: &Val, v2: &Val) -> (bool, bool) { + (self.is_drop(v1), self.is_drop(v2)) + } + + fn translate(&mut self, e: Expr, unused: bool) -> Val { + // println!("{e:?}\n\n"); match e { + /* organisational */ + Expr::Block(mut b) => { + let last = b.exprs.pop(); + for e in b.exprs { + self.translate(e, false); + } + // yield last expr + last.map_or(Val::Nil, |e| self.translate(e, false)) + } + /* 1 to 1 literals */ + Expr::Literal(Literal::Boolean(b)) => Val::Bool(b), + Expr::Literal(Literal::Float(f)) => Val::Float64(f), + Expr::Literal(Literal::Integer(i)) => Val::Int64(i), + Expr::Literal(Literal::Nil) => Val::Nil, + Expr::Literal(Literal::String(s)) => Val::String(s), + /* ident */ + Expr::Literal(Literal::Ident(id, Some(rs))) => { + Val::Stack(self.find(&id), rs.now == rs.meta.total.get()) + } + /* math */ + Expr::Add(l, r) => { + let (v1, v2) = (self.translate(*l, false), self.translate(*r, false)); + let (a1, a2) = self.is_drop2(&v1, &v2); + + self.insts.push(Inst::Add(a1, a2, v1, v2)); + Val::Stack(self.push_any(), true) + } + Expr::Assign(l, r) => { + let Expr::Literal(Literal::Ident(id, Some(ref_stat))) = *l else { + unreachable!() + }; + + let unused = ref_stat.now == ref_stat.meta.total.get(); + let val = self.translate(*r, unused); + if !unused { + self.local.push(FSValue::Var(id)); + } + val + } _ => unimplemented!(), } } @@ -310,9 +372,9 @@ pub fn analysis_demo(e: &mut Expr) { let mut scope = Scope::with_parent(None); analyze(&fs, &mut scope, e); } -pub fn translation_demo(e: &Expr) { +pub fn translation_demo(e: Expr) -> Vec { // translation pass let mut fb = FuncBuild::new_root(); - let mut bb = BlockBuild {}; - fb.translate(&mut bb, e); + fb.translate(e, true); + fb.insts } diff --git a/src/compiler/stack.rs b/src/compiler/stack.rs index 594db71..b744059 100644 --- a/src/compiler/stack.rs +++ b/src/compiler/stack.rs @@ -17,6 +17,12 @@ where fn push(&mut self, value: Self::Value) { self.values_mut().push(value); } + fn pop(&mut self, index: usize) { + self.values_mut().remove(index); + } + fn height(&self) -> usize { + self.values().len() + } fn find(&self, input: &Self::Input) -> Option<(Self::Output, u16)> { let mut cur = Some(self); diff --git a/src/lexer.rs b/src/lexer.rs index abf50e3..ae1cabf 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -37,9 +37,9 @@ impl fmt::Display for Literal { .as_ref() .map(|rs| format!( "@{}{}/{}", - rs.stat.is_shared.get().then_some("sh+").unwrap_or(""), + rs.meta.is_shared.get().then_some("sh+").unwrap_or(""), rs.now, - rs.stat.total.get() + rs.meta.total.get() )) .unwrap_or_default() ), diff --git a/src/main.rs b/src/main.rs index ca17fa9..7ed295a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,9 @@ fn main() { parser::util::display(&e); let start = Instant::now(); - compiler::translation_demo(&mut e); + let insts = compiler::translation_demo(e); println!("Translation took {:?}", start.elapsed()); - parser::util::display(&e); + for i in insts { + println!("=> {i:?}"); + } }