diff --git a/src/compiler.rs b/src/compiler.rs index b514c28..92eaf18 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -5,17 +5,9 @@ use crate::{ parser::Expr, }; -pub type FuncMeta = Rc>; - -#[derive(Debug, Clone)] -pub struct RefMeta { - pub now: u16, - pub total: Rc>, -} - struct Scope<'a> { /* Faster than a hashmap for now? */ - idents: Vec<(Ident, Rc>)>, + idents: Vec<(Ident, Rc)>, parent: Option<&'a Scope<'a>>, } impl<'a> Scope<'a> { @@ -26,31 +18,152 @@ impl<'a> Scope<'a> { } } fn assigned(&mut self, id: Ident) { - self.idents.push((id, Rc::default())); + if self.find(&id).is_none() { + self.idents.push((id, Rc::default())); + } } - fn find(&self, id: &Ident) -> (Rc>, u8) { + fn find(&self, id: &Ident) -> Option<(Rc, bool)> { let mut cur = Some(self); - let mut up_levels = 0; + let mut is_up = false; + while let Some(scope) = cur { - let Some((_, count)) = scope.idents.iter().rev().find(|i| i.0 == *id) else { + let Some((_, fs)) = scope.idents.iter().rev().find(|i| i.0 == *id) else { cur = scope.parent; - up_levels += 1; + is_up = true; continue; }; - return (count.clone(), up_levels); + return Some((fs.clone(), is_up)); } - panic!("undefined variable"); + + None } } -pub fn compile(e: &mut Expr) { - let fm = FuncMeta::default(); - let mut scope = Scope::with_parent(None); - analyze(&fm, &mut scope, e); +#[derive(Debug, Default, Clone)] +pub struct FuncMeta { + pub is_unreturnable: Cell, +} +pub type FuncStat = Rc; + +#[derive(Debug, Clone)] +pub struct RefStat { + pub now: u16, + pub stat: Rc, } -/* 5b up levels, 8b offset */ -struct Stkval(u8, u8); +#[derive(Debug, Default)] +pub struct RefMeta { + pub total: Cell, + pub is_shared: Cell, +} + +fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) { + match e { + Expr::Assign(a, b) => { + let Expr::Literal(Literal::Ident(id, _)) = &**a else { + panic!("invalid assignment"); + }; + + // add to scope + scope.assigned(id.clone()); + + // analyse the value + analyze(fs, scope, b); + } + Expr::Literal(Literal::Ident(id, ref_stat)) => { + // lookup literal + let Some((rs, used_up)) = scope.find(id) else { + panic!("unfound variable") + }; + // increment # of uses + rs.total.update(|c| c + 1); + // set ref meta + *ref_stat = Some(RefStat { + now: rs.total.get(), + stat: rs.clone(), + }); + // if we used something external to this scope, note it + if used_up { + fs.is_unreturnable.set(true); + rs.is_shared.set(true); + } + } + // ignore + Expr::Literal(_) => {} + // for recursion.. + Expr::Block(a) => { + // blocks have their own scope + let mut scope = Scope::with_parent(Some(scope)); + // analyze the contents in the new scope + for e in &mut a.exprs { + analyze(fs, &mut scope, e); + } + } + Expr::Func(a, b, func_stat) => { + // new function new context + let fs = FuncStat::default(); + *func_stat = Some(fs.clone()); + // functions have their own scope, because they have args + let mut scope = Scope::with_parent(Some(scope)); + + // init args + for e in a { + let Expr::Literal(Literal::Ident(id, _)) = e else { + panic!("invalid arg def"); + }; + scope.assigned(id.clone()); + } + + // now analyze the body in the new scope + analyze(&fs, &mut scope, b); + } + Expr::If(a, b, c) => { + analyze(fs, scope, a); + analyze(fs, scope, b); + if let Some(c) = c { + analyze(fs, scope, c); + } + } + Expr::Call(a, b) => { + analyze(fs, scope, a); + for e in b { + analyze(fs, scope, e); + } + } + Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(fs, scope, a), + Expr::EqualTo(a, b) + | Expr::NotEqualTo(a, b) + | Expr::And(a, b) + | Expr::Or(a, b) + | Expr::LessThan(a, b) + | Expr::LessThanOrEqualTo(a, b) + | Expr::GreaterThan(a, b) + | Expr::GreaterThanOrEqualTo(a, b) + | Expr::Add(a, b) + | Expr::Subtract(a, b) + | Expr::Multiply(a, b) + | Expr::Divide(a, b) + | Expr::Exponent(a, b) + | Expr::Modulo(a, b) + | Expr::AddAssign(a, b) // maybe handle these differently? + | Expr::SubtractAssign(a, b) // when error handling is added at least + | Expr::MultiplyAssign(a, b) + | Expr::DivideAssign(a, b) =>{ + analyze(fs, scope, a); + analyze(fs, scope, b); + } + } +} + +// --- translate pass --- // + +/* 1b is up? */ +enum Stkval { + /* 4b blank ; 8b offset */ + Local(u8), + /* 4b up levels ; 8b offset */ + Foreign(u8), +} /* 3b type tag */ enum Val { Stack(Stkval), @@ -93,97 +206,61 @@ enum Inst { Return(Val), } -fn analyze(fm: &FuncMeta, scope: &mut Scope, e: &mut Expr) { - match e { - Expr::Assign(a, b) => { - let Expr::Literal(Literal::Ident(id, _)) = &**a else { - panic!("invalid assignment"); - }; +/// Value on fake stack. +enum FSValue { + Var(Ident), + Any, +} - // add to scope - scope.assigned(id.clone()); +/// 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 {} - // analyse the value - analyze(fm, scope, b); - } - Expr::Literal(Literal::Ident(id, ref_meta)) => { - // lookup literal - let (count, up_levels) = scope.find(id); - // increment # of uses - count.update(|c| c + 1); - // set ref meta - *ref_meta = Some(RefMeta { - now: count.get(), - total: count, - }); - // if we used something external to this scope, note it - if up_levels != 0 { - fm.set(true); - } - } - // ignore - Expr::Literal(_) => {} - // for recursion.. - Expr::Block(a) => { - // blocks have their own scope - let mut scope = Scope::with_parent(Some(scope)); - // analyze the contents in the new scope - for e in &mut a.exprs { - analyze(fm, &mut scope, e); - } - } - Expr::Func(a, b, func_meta) => { - // new function new context - let fm = FuncMeta::default(); - *func_meta = Some(fm.clone()); - // functions have their own scope, because they have args - let mut scope = Scope::with_parent(Some(scope)); +/// Build scope of a function. +/// +/// * Starts with a base block scope that includes any arguments passed +/// * Contains the compiled instructions of all blocks inside it +/// * 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>, + insts: Vec, + shared_stack: Vec, + local_stack: Vec, +} - // init args - for e in a { - let Expr::Literal(Literal::Ident(id, _)) = e else { - panic!("invalid arg def"); - }; - scope.assigned(id.clone()); - } +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 + }; - // now analyze the body in the new scope - analyze(&fm, &mut scope, b); - } - Expr::If(a, b, c) => { - analyze(fm, scope, a); - analyze(fm, scope, b); - if let Some(c) = c { - analyze(fm, scope, c); - } - } - Expr::Call(a, b) => { - analyze(fm, scope, a); - for e in b { - analyze(fm, scope, e); - } - } - Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(fm, scope, a), - Expr::EqualTo(a, b) - | Expr::NotEqualTo(a, b) - | Expr::And(a, b) - | Expr::Or(a, b) - | Expr::LessThan(a, b) - | Expr::LessThanOrEqualTo(a, b) - | Expr::GreaterThan(a, b) - | Expr::GreaterThanOrEqualTo(a, b) - | Expr::Add(a, b) - | Expr::Subtract(a, b) - | Expr::Multiply(a, b) - | Expr::Divide(a, b) - | Expr::Exponent(a, b) - | Expr::Modulo(a, b) - | Expr::AddAssign(a, b) - | Expr::SubtractAssign(a, b) - | Expr::MultiplyAssign(a, b) - | Expr::DivideAssign(a, b) => { - analyze(fm, scope, a); - analyze(fm, scope, b); + Stkval::Local(idx as u8) + } + + fn translate(&mut self, e: &Expr) { + match e { + _ => unimplemented!(), } } } + +pub fn compile(e: &mut Expr) { + let fs = FuncStat::default(); + let mut scope = Scope::with_parent(None); + analyze(&fs, &mut scope, e); + // let mut fg = FuncGen::default(); + // fg.translate(&e); +} diff --git a/src/lexer.rs b/src/lexer.rs index 40f48ac..abf50e3 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -4,7 +4,7 @@ use std::{ num::{ParseFloatError, ParseIntError}, }; -use crate::{compiler::RefMeta, kinds}; +use crate::{compiler::RefStat, kinds}; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Ident(String); @@ -21,7 +21,7 @@ pub enum Literal { Float(f64), Boolean(bool), Nil, - Ident(Ident, Option), + Ident(Ident, Option), } impl fmt::Display for Literal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -30,12 +30,17 @@ impl fmt::Display for Literal { Literal::Integer(n) => write!(f, "{n}"), Literal::Float(n) => write!(f, "{n}"), Literal::Boolean(b) => write!(f, "{b}"), - Literal::Ident(id, ref_meta) => write!( + Literal::Ident(id, ref_stat) => write!( f, "{id}{}", - ref_meta + ref_stat .as_ref() - .map(|rm| format!("@{}/{}", rm.now, rm.total.get())) + .map(|rs| format!( + "@{}{}/{}", + rs.stat.is_shared.get().then_some("sh+").unwrap_or(""), + rs.now, + rs.stat.total.get() + )) .unwrap_or_default() ), Literal::Nil => write!(f, "nil"), diff --git a/src/parser.rs b/src/parser.rs index b4a3ae1..78af584 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use std::{fmt, iter::Peekable}; use crate::{ - compiler::FuncMeta, + compiler::FuncStat, kind::Kind, lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind}, }; @@ -15,7 +15,7 @@ pub enum Expr { Literal(Literal), // Non-literal datatypes Block(Block), - Func(Vec, Box, Option), + Func(Vec, Box, Option), // Control flow If(Box, Box, Option>), Return(Box), diff --git a/src/parser/util.rs b/src/parser/util.rs index 818dbf0..c27ecc4 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -60,15 +60,19 @@ fn fmt_expr(e: &Expr, depth: usize) -> String { } result } - Expr::Func(a, e, func_meta) => format!( + Expr::Func(a, e, func_stat) => format!( "(func({}){} ({}))", a.iter() .map(|e| fmt_expr(e, depth)) .collect::>() .join(", "), - func_meta + func_stat .as_ref() - .map(|fm| format!("@{}", fm.get())) + .map(|fm| fm + .is_unreturnable + .get() + .then_some("@UNRET") + .unwrap_or("@OK")) .unwrap_or_default(), fmt_expr(e, depth) ),