wip refactor

This commit is contained in:
minish 2025-09-19 23:50:25 -04:00
parent 355d132ba3
commit 134c5abd0f
Signed by: min
SSH Key Fingerprint: SHA256:mf+pUTmK92Y57BuCjlkBdd82LqztTfDCQIUp0fCKABc
4 changed files with 113 additions and 154 deletions

View File

@ -1,165 +1,122 @@
use std::cell::Cell;
use crate::{ use crate::{
lexer::{Ident, Literal}, lexer::{Ident, Literal},
parser::Expr, parser::Expr,
}; };
type ScopeIdx = usize; struct Scope<'a> {
idents: Vec<(Ident, Cell<u16>)>,
#[derive(Default, Debug)] parent: Option<&'a Scope<'a>>,
struct AnalysisScope {
prev: Option<ScopeIdx>,
next: Vec<ScopeIdx>,
idents: Vec<(Ident, u16)>,
top_level_exprs: Vec<Expr>,
} }
impl<'a> Scope<'a> {
impl AnalysisScope { fn with_parent(parent: Option<&'a Scope>) -> Self {
pub fn new() -> Self { Scope {
Self::default() idents: Vec::new(),
} parent,
fn initialize(&mut self, id: Ident) {
self.idents.push((id, 0));
}
}
#[derive(Default, Debug)]
pub struct Analyzer {
scopes: Vec<AnalysisScope>,
}
impl Analyzer {
pub fn new() -> Self {
Self::default()
}
fn new_scope(&mut self) {
// Get indices
let cur_idx = self.scopes.len().checked_sub(1);
let next_idx = cur_idx.map(|i| i + 1).unwrap_or_default();
// If we have a current scope, add in the new scope's index
if let Some(Some(cur_scope)) = cur_idx.map(|i| self.scopes.get_mut(i)) {
cur_scope.next.push(next_idx);
}
// Create new scope
self.scopes.push(AnalysisScope::new());
let next_scope = self.scopes.get_mut(next_idx).unwrap();
// Tie it back to the current scope (if there is one)
next_scope.prev = cur_idx;
}
fn get_scope(&mut self) -> &mut AnalysisScope {
self.scopes.last_mut().unwrap()
}
fn increment_ident(&mut self, id: &Ident) -> Option<u16> {
let mut cur = self.get_scope();
loop {
// Try to find it
if let Some(count) = cur
.idents
.iter_mut()
.rev()
.find(|(i, _)| id == i)
.map(|(_, c)| c)
{
let old_count = *count;
*count += 1;
return Some(old_count);
}
// Didn't find it so try scope above
if let Some(prev) = cur.prev {
cur = self.scopes.get_mut(prev).unwrap();
} else {
// No more scopes above
return None;
}
} }
} }
fn assigned(&mut self, id: Ident) {
self.idents.push((id, Cell::default()));
}
}
pub fn analyze(&mut self, e: Expr) { pub fn compile(mut e: Expr) {
match e { let mut scope = Scope::with_parent(None);
Expr::Assign(a, b) => { analyze(&mut scope, &mut e);
let Expr::Literal(Literal::Ident(id)) = *a else { }
panic!("invalid assignment");
fn analyze(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(scope, b);
}
Expr::Literal(Literal::Ident(id), _) => {
// lookup literal
let mut cur = &*scope;
loop {
let Some((_, count)) = cur.idents.iter().find(|i| i.0 == *id) else {
if let Some(parent) = cur.parent {
cur = parent;
} else {
panic!("undefined variable");
}
continue;
}; };
count.update(|c| c + 1);
let count = count.get();
println!("ref {id} #{count}");
break;
}
}
// ignore
Expr::Literal(_, _) => {}
// for recursion..
Expr::Block(a) => {
// blocks have their own scope
let mut scope2 = Scope::with_parent(Some(scope));
// analyze the contents in the new scope
for e in &mut a.exprs {
analyze(&mut scope2, e);
}
}
Expr::Func(a, b) => {
// functions have their own scope, because they have args
let mut scope = Scope::with_parent(Some(scope));
// make new counter for ident in our scope // init args
let sc = self.get_scope(); for e in a {
sc.initialize(id); let Expr::Literal(Literal::Ident(id), _) = e else {
panic!("invalid arg def");
};
scope.assigned(id.clone());
}
// analyse the value // now analyze the body in the new scope
self.analyze(*b); analyze(&mut scope, b);
}
Expr::If(a, b, c) => {
analyze(scope, a);
analyze(scope, b);
if let Some(c) = c {
analyze(scope, c);
} }
Expr::Literal(Literal::Ident(id)) => { }
// lookup literal Expr::Call(a, b) => {
self.increment_ident(&id).expect("not found var"); analyze(scope, a);
} for e in b {
// ignore analyze(scope, e);
Expr::Literal(_) => {}
// for recursion..
Expr::Block(a) => {
// blocks have their own scope
self.new_scope();
let sc = self.get_scope();
// analyze the contents in the new scope
sc.top_level_exprs = a.exprs.clone();
for e in a.exprs {
self.analyze(e);
}
}
Expr::Func(a, b) => {
// functions have their own scope, because they have args
self.new_scope();
let new_sc = self.get_scope();
for e in a {
let Expr::Literal(Literal::Ident(id)) = e else {
panic!("invalid arg def");
};
new_sc.initialize(id);
}
// now analyze the body in the new scope
self.analyze(*b);
}
Expr::If(a, b, c) => {
self.analyze(*a);
self.analyze(*b);
if let Some(c) = c {
self.analyze(*c);
}
}
Expr::Call(a, b) => {
self.analyze(*a);
for e in b {
self.analyze(e);
}
}
Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => self.analyze(*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) => {
self.analyze(*a);
self.analyze(*b);
} }
} }
Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(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(scope, a);
analyze(scope, b);
}
} }
} }

View File

@ -10,15 +10,17 @@ mod parser;
fn main() { fn main() {
let script = std::fs::read_to_string("./start.lf").unwrap(); let script = std::fs::read_to_string("./start.lf").unwrap();
let lexer = Lexer::new(script.chars()); let lexer = Lexer::new(script.chars());
let mut parser = Parser::new(lexer.map(Result::unwrap)); let mut parser = Parser::new(lexer.map(Result::unwrap));
let start = Instant::now(); let start = Instant::now();
let block = parser.parse().unwrap(); let block = parser.parse().unwrap();
println!("Parse took {:?}", start.elapsed()); println!("Parse took {:?}", start.elapsed());
let e = parser::Expr::Block(block); let e = parser::Expr::Block(block);
parser::util::display(&e); parser::util::display(&e);
let start = Instant::now(); let start = Instant::now();
let mut analysis = compiler::Analyzer::new(); compiler::compile(e);
analysis.analyze(e);
println!("Analysis took {:?}", start.elapsed()); println!("Analysis took {:?}", start.elapsed());
println!("{analysis:?}");
} }

View File

@ -11,7 +11,7 @@ pub mod util;
pub enum Expr { pub enum Expr {
// Data and variables // Data and variables
Assign(Box<Expr>, Box<Expr>), Assign(Box<Expr>, Box<Expr>),
Literal(Literal), Literal(Literal, u16),
// Non-literal datatypes // Non-literal datatypes
Block(Block), Block(Block),
Func(Vec<Expr>, Box<Expr>), Func(Vec<Expr>, Box<Expr>),
@ -122,7 +122,7 @@ where
fn parse_expr(&mut self, min_prec: Precedence, in_group: bool) -> Result<Box<Expr>> { fn parse_expr(&mut self, min_prec: Precedence, in_group: bool) -> Result<Box<Expr>> {
let mut lhs = match self.try_next()? { let mut lhs = match self.try_next()? {
// literal // literal
Token::Literal(lit) => Box::new(Expr::Literal(lit)), Token::Literal(lit) => Box::new(Expr::Literal(lit, 0)),
// start of group // start of group
Token::ParenOpen => { 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::SubtractAssign(l, r) => fmt_binop(l, r, "-=", depth),
Expr::MultiplyAssign(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::DivideAssign(l, r) => fmt_binop(l, r, "/=", depth),
Expr::Literal(l) => l.to_string(), Expr::Literal(l, _) => l.to_string(),
Expr::Call(l, r) => { Expr::Call(l, r) => {
let mut result = fmt_expr(l, depth); let mut result = fmt_expr(l, depth);
result.push('('); result.push('(');