wip refactor
This commit is contained in:
parent
355d132ba3
commit
134c5abd0f
151
src/compiler.rs
151
src/compiler.rs
|
@ -1,144 +1,102 @@
|
||||||
|
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) {
|
fn assigned(&mut self, id: Ident) {
|
||||||
self.idents.push((id, 0));
|
self.idents.push((id, Cell::default()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
pub fn compile(mut e: Expr) {
|
||||||
pub struct Analyzer {
|
let mut scope = Scope::with_parent(None);
|
||||||
scopes: Vec<AnalysisScope>,
|
analyze(&mut scope, &mut e);
|
||||||
}
|
|
||||||
impl Analyzer {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_scope(&mut self) {
|
fn analyze(scope: &mut Scope, e: &mut Expr) {
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn analyze(&mut self, e: Expr) {
|
|
||||||
match e {
|
match e {
|
||||||
Expr::Assign(a, b) => {
|
Expr::Assign(a, b) => {
|
||||||
let Expr::Literal(Literal::Ident(id)) = *a else {
|
let Expr::Literal(Literal::Ident(id), _) = &**a else {
|
||||||
panic!("invalid assignment");
|
panic!("invalid assignment");
|
||||||
};
|
};
|
||||||
|
|
||||||
// make new counter for ident in our scope
|
// add to scope
|
||||||
let sc = self.get_scope();
|
scope.assigned(id.clone());
|
||||||
sc.initialize(id);
|
|
||||||
|
|
||||||
// analyse the value
|
// analyse the value
|
||||||
self.analyze(*b);
|
analyze(scope, b);
|
||||||
}
|
}
|
||||||
Expr::Literal(Literal::Ident(id)) => {
|
Expr::Literal(Literal::Ident(id), _) => {
|
||||||
// lookup literal
|
// lookup literal
|
||||||
self.increment_ident(&id).expect("not found var");
|
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
|
// ignore
|
||||||
Expr::Literal(_) => {}
|
Expr::Literal(_, _) => {}
|
||||||
// for recursion..
|
// for recursion..
|
||||||
Expr::Block(a) => {
|
Expr::Block(a) => {
|
||||||
// blocks have their own scope
|
// blocks have their own scope
|
||||||
self.new_scope();
|
let mut scope2 = Scope::with_parent(Some(scope));
|
||||||
let sc = self.get_scope();
|
|
||||||
// analyze the contents in the new scope
|
// analyze the contents in the new scope
|
||||||
sc.top_level_exprs = a.exprs.clone();
|
for e in &mut a.exprs {
|
||||||
for e in a.exprs {
|
analyze(&mut scope2, e);
|
||||||
self.analyze(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Func(a, b) => {
|
Expr::Func(a, b) => {
|
||||||
// functions have their own scope, because they have args
|
// functions have their own scope, because they have args
|
||||||
self.new_scope();
|
let mut scope = Scope::with_parent(Some(scope));
|
||||||
let new_sc = self.get_scope();
|
|
||||||
|
|
||||||
|
// init args
|
||||||
for e in a {
|
for e in a {
|
||||||
let Expr::Literal(Literal::Ident(id)) = e else {
|
let Expr::Literal(Literal::Ident(id), _) = e else {
|
||||||
panic!("invalid arg def");
|
panic!("invalid arg def");
|
||||||
};
|
};
|
||||||
new_sc.initialize(id);
|
scope.assigned(id.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// now analyze the body in the new scope
|
// now analyze the body in the new scope
|
||||||
self.analyze(*b);
|
analyze(&mut scope, b);
|
||||||
}
|
}
|
||||||
Expr::If(a, b, c) => {
|
Expr::If(a, b, c) => {
|
||||||
self.analyze(*a);
|
analyze(scope, a);
|
||||||
self.analyze(*b);
|
analyze(scope, b);
|
||||||
if let Some(c) = c {
|
if let Some(c) = c {
|
||||||
self.analyze(*c);
|
analyze(scope, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(a, b) => {
|
Expr::Call(a, b) => {
|
||||||
self.analyze(*a);
|
analyze(scope, a);
|
||||||
for e in b {
|
for e in b {
|
||||||
self.analyze(e);
|
analyze(scope, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => self.analyze(*a),
|
Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(scope, a),
|
||||||
Expr::EqualTo(a, b)
|
Expr::EqualTo(a, b)
|
||||||
| Expr::NotEqualTo(a, b)
|
| Expr::NotEqualTo(a, b)
|
||||||
| Expr::And(a, b)
|
| Expr::And(a, b)
|
||||||
|
@ -157,9 +115,8 @@ impl Analyzer {
|
||||||
| Expr::SubtractAssign(a, b)
|
| Expr::SubtractAssign(a, b)
|
||||||
| Expr::MultiplyAssign(a, b)
|
| Expr::MultiplyAssign(a, b)
|
||||||
| Expr::DivideAssign(a, b) => {
|
| Expr::DivideAssign(a, b) => {
|
||||||
self.analyze(*a);
|
analyze(scope, a);
|
||||||
self.analyze(*b);
|
analyze(scope, b);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:?}");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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('(');
|
||||||
|
|
Loading…
Reference in New Issue