This commit is contained in:
minish 2025-09-20 00:09:47 -04:00
parent c954e5af13
commit 1a0c93f26a
Signed by: min
SSH Key Fingerprint: SHA256:mf+pUTmK92Y57BuCjlkBdd82LqztTfDCQIUp0fCKABc
4 changed files with 31 additions and 17 deletions

View File

@ -1,12 +1,18 @@
use std::cell::Cell;
use std::{cell::Cell, rc::Rc};
use crate::{
lexer::{Ident, Literal},
parser::Expr,
};
#[derive(Debug, Clone)]
pub struct RefMeta {
now: u16,
total: Rc<Cell<u16>>,
}
struct Scope<'a> {
idents: Vec<(Ident, Cell<u16>)>,
idents: Vec<(Ident, Rc<Cell<u16>>)>,
parent: Option<&'a Scope<'a>>,
}
impl<'a> Scope<'a> {
@ -17,16 +23,16 @@ impl<'a> Scope<'a> {
}
}
fn assigned(&mut self, id: Ident) {
self.idents.push((id, Cell::default()));
self.idents.push((id, Default::default()));
}
fn find(&self, id: &Ident) -> &Cell<u16> {
fn find(&self, id: &Ident) -> Rc<Cell<u16>> {
let mut cur = Some(self);
while let Some(scope) = cur {
let Some((_, count)) = scope.idents.iter().rev().find(|i| i.0 == *id) else {
cur = scope.parent;
continue;
};
return count;
return count.clone();
}
panic!("undefined variable");
}
@ -35,12 +41,13 @@ impl<'a> Scope<'a> {
pub fn compile(mut e: Expr) {
let mut scope = Scope::with_parent(None);
analyze(&mut scope, &mut e);
println!("{e:?}");
}
fn analyze(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, _)) = &**a else {
panic!("invalid assignment");
};
@ -50,14 +57,21 @@ fn analyze(scope: &mut Scope, e: &mut Expr) {
// analyse the value
analyze(scope, b);
}
Expr::Literal(Literal::Ident(id), _) => {
Expr::Literal(Literal::Ident(id, ref_meta)) => {
// lookup literal
let count = scope.find(id);
// increment # of uses
count.update(|c| c + 1);
println!("ref {id} #{}", count.get());
// set ref meta
let now = count.get();
*ref_meta = Some(RefMeta {
now: count.get(),
total: count,
});
println!("ref {id} #{now}");
}
// ignore
Expr::Literal(_, _) => {}
Expr::Literal(_) => {}
// for recursion..
Expr::Block(a) => {
// blocks have their own scope
@ -73,7 +87,7 @@ fn analyze(scope: &mut Scope, e: &mut Expr) {
// init args
for e in a {
let Expr::Literal(Literal::Ident(id), _) = e else {
let Expr::Literal(Literal::Ident(id, _)) = e else {
panic!("invalid arg def");
};
scope.assigned(id.clone());

View File

@ -4,7 +4,7 @@ use std::{
num::{ParseFloatError, ParseIntError},
};
use crate::kinds;
use crate::{compiler::RefMeta, kinds};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Ident(String);
@ -21,7 +21,7 @@ pub enum Literal {
Float(f64),
Boolean(bool),
Nil,
Ident(Ident),
Ident(Ident, Option<RefMeta>),
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -30,7 +30,7 @@ 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) => write!(f, "{id}"),
Literal::Ident(id, _) => write!(f, "{id}"),
Literal::Nil => write!(f, "nil"),
}
}
@ -229,7 +229,7 @@ where
"true" => Token::Literal(Literal::Boolean(true)),
"false" => Token::Literal(Literal::Boolean(false)),
"nil" => Token::Literal(Literal::Nil),
_ => Token::Literal(Literal::Ident(Ident(word))),
_ => Token::Literal(Literal::Ident(Ident(word), Default::default())),
}
}

View File

@ -11,7 +11,7 @@ pub mod util;
pub enum Expr {
// Data and variables
Assign(Box<Expr>, Box<Expr>),
Literal(Literal, u16),
Literal(Literal),
// Non-literal datatypes
Block(Block),
Func(Vec<Expr>, Box<Expr>),
@ -122,7 +122,7 @@ where
fn parse_expr(&mut self, min_prec: Precedence, in_group: bool) -> Result<Box<Expr>> {
let mut lhs = match self.try_next()? {
// literal
Token::Literal(lit) => Box::new(Expr::Literal(lit, 0)),
Token::Literal(lit) => Box::new(Expr::Literal(lit)),
// start of group
Token::ParenOpen => {

View File

@ -23,7 +23,7 @@ fn fmt_expr(e: &Expr, depth: usize) -> String {
Expr::SubtractAssign(l, r) => fmt_binop(l, r, "-=", depth),
Expr::MultiplyAssign(l, r) => fmt_binop(l, r, "*=", depth),
Expr::DivideAssign(l, r) => fmt_binop(l, r, "/=", depth),
Expr::Literal(l, _) => l.to_string(),
Expr::Literal(l) => l.to_string(),
Expr::Call(l, r) => {
let mut result = fmt_expr(l, depth);
result.push('(');