diff --git a/src/compiler.rs b/src/compiler.rs index 3f1187a..0738ffe 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -5,6 +5,8 @@ use crate::{ parser::Expr, }; +pub type FuncMeta = Rc>; + #[derive(Debug, Clone)] pub struct RefMeta { pub now: u16, @@ -25,25 +27,28 @@ impl<'a> Scope<'a> { fn assigned(&mut self, id: Ident) { self.idents.push((id, Rc::default())); } - fn find(&self, id: &Ident) -> Rc> { + fn find(&self, id: &Ident) -> (Rc>, bool) { let mut cur = Some(self); + let mut went_up = false; while let Some(scope) = cur { let Some((_, count)) = scope.idents.iter().rev().find(|i| i.0 == *id) else { cur = scope.parent; + went_up = true; continue; }; - return count.clone(); + return (count.clone(), went_up); } panic!("undefined variable"); } } pub fn compile(e: &mut Expr) { + let fm = FuncMeta::default(); let mut scope = Scope::with_parent(None); - analyze(&mut scope, e); + analyze(&fm, &mut scope, e); } -fn analyze(scope: &mut Scope, e: &mut Expr) { +fn analyze(fm: &FuncMeta, scope: &mut Scope, e: &mut Expr) { match e { Expr::Assign(a, b) => { let Expr::Literal(Literal::Ident(id, _)) = &**a else { @@ -54,11 +59,11 @@ fn analyze(scope: &mut Scope, e: &mut Expr) { scope.assigned(id.clone()); // analyse the value - analyze(scope, b); + analyze(fm, scope, b); } Expr::Literal(Literal::Ident(id, ref_meta)) => { // lookup literal - let count = scope.find(id); + let (count, went_up) = scope.find(id); // increment # of uses count.update(|c| c + 1); // set ref meta @@ -66,6 +71,10 @@ fn analyze(scope: &mut Scope, e: &mut Expr) { now: count.get(), total: count, }); + // if we used something external to this scope, note it + if went_up { + fm.set(true); + } } // ignore Expr::Literal(_) => {} @@ -75,10 +84,13 @@ fn analyze(scope: &mut Scope, e: &mut Expr) { let mut scope = Scope::with_parent(Some(scope)); // analyze the contents in the new scope for e in &mut a.exprs { - analyze(&mut scope, e); + analyze(fm, &mut scope, e); } } - Expr::Func(a, b) => { + 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)); @@ -91,22 +103,22 @@ fn analyze(scope: &mut Scope, e: &mut Expr) { } // now analyze the body in the new scope - analyze(&mut scope, b); + analyze(&fm, &mut scope, b); } Expr::If(a, b, c) => { - analyze(scope, a); - analyze(scope, b); + analyze(fm, scope, a); + analyze(fm, scope, b); if let Some(c) = c { - analyze(scope, c); + analyze(fm, scope, c); } } Expr::Call(a, b) => { - analyze(scope, a); + analyze(fm, scope, a); for e in b { - analyze(scope, e); + analyze(fm, scope, e); } } - Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(scope, a), + 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) @@ -125,8 +137,8 @@ fn analyze(scope: &mut Scope, e: &mut Expr) { | Expr::SubtractAssign(a, b) | Expr::MultiplyAssign(a, b) | Expr::DivideAssign(a, b) => { - analyze(scope, a); - analyze(scope, b); + analyze(fm, scope, a); + analyze(fm, scope, b); } } } diff --git a/src/parser.rs b/src/parser.rs index d7a8505..016ec84 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,20 +1,21 @@ use std::{fmt, iter::Peekable}; use crate::{ + compiler::FuncMeta, kind::Kind, lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind}, }; pub mod util; -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum Expr { // Data and variables Assign(Box, Box), Literal(Literal), // Non-literal datatypes Block(Block), - Func(Vec, Box), + Func(Vec, Box, Option), // Control flow If(Box, Box, Option>), Return(Box), @@ -46,7 +47,7 @@ pub enum Expr { DivideAssign(Box, Box), } -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default)] pub struct Block { pub exprs: Vec, } @@ -154,7 +155,7 @@ where // parse body let body = self.parse_expr(prec, in_group)?; // pack - Box::new(Expr::Func(args, body)) + Box::new(Expr::Func(args, body, None)) } // parse if Token::If => { diff --git a/src/parser/util.rs b/src/parser/util.rs index 33324da..818dbf0 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -60,12 +60,16 @@ fn fmt_expr(e: &Expr, depth: usize) -> String { } result } - Expr::Func(a, e) => format!( - "(func({}) ({}))", + Expr::Func(a, e, func_meta) => format!( + "(func({}){} ({}))", a.iter() .map(|e| fmt_expr(e, depth)) .collect::>() .join(", "), + func_meta + .as_ref() + .map(|fm| format!("@{}", fm.get())) + .unwrap_or_default(), fmt_expr(e, depth) ), Expr::Negate(l) => format!("(-{})", fmt_expr(l, depth)),