more compiler work
This commit is contained in:
parent
559d4c29ed
commit
fb61028d37
299
src/compiler.rs
299
src/compiler.rs
|
@ -5,17 +5,9 @@ use crate::{
|
||||||
parser::Expr,
|
parser::Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type FuncMeta = Rc<Cell<bool>>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RefMeta {
|
|
||||||
pub now: u16,
|
|
||||||
pub total: Rc<Cell<u16>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Scope<'a> {
|
struct Scope<'a> {
|
||||||
/* Faster than a hashmap for now? */
|
/* Faster than a hashmap for now? */
|
||||||
idents: Vec<(Ident, Rc<Cell<u16>>)>,
|
idents: Vec<(Ident, Rc<RefMeta>)>,
|
||||||
parent: Option<&'a Scope<'a>>,
|
parent: Option<&'a Scope<'a>>,
|
||||||
}
|
}
|
||||||
impl<'a> Scope<'a> {
|
impl<'a> Scope<'a> {
|
||||||
|
@ -26,31 +18,152 @@ impl<'a> Scope<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn assigned(&mut self, id: Ident) {
|
fn assigned(&mut self, id: Ident) {
|
||||||
|
if self.find(&id).is_none() {
|
||||||
self.idents.push((id, Rc::default()));
|
self.idents.push((id, Rc::default()));
|
||||||
}
|
}
|
||||||
fn find(&self, id: &Ident) -> (Rc<Cell<u16>>, u8) {
|
}
|
||||||
|
fn find(&self, id: &Ident) -> Option<(Rc<RefMeta>, bool)> {
|
||||||
let mut cur = Some(self);
|
let mut cur = Some(self);
|
||||||
let mut up_levels = 0;
|
let mut is_up = false;
|
||||||
|
|
||||||
while let Some(scope) = cur {
|
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;
|
cur = scope.parent;
|
||||||
up_levels += 1;
|
is_up = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
return (count.clone(), up_levels);
|
return Some((fs.clone(), is_up));
|
||||||
}
|
}
|
||||||
panic!("undefined variable");
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(e: &mut Expr) {
|
#[derive(Debug, Default, Clone)]
|
||||||
let fm = FuncMeta::default();
|
pub struct FuncMeta {
|
||||||
let mut scope = Scope::with_parent(None);
|
pub is_unreturnable: Cell<bool>,
|
||||||
analyze(&fm, &mut scope, e);
|
}
|
||||||
|
pub type FuncStat = Rc<FuncMeta>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RefStat {
|
||||||
|
pub now: u16,
|
||||||
|
pub stat: Rc<RefMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5b up levels, 8b offset */
|
#[derive(Debug, Default)]
|
||||||
struct Stkval(u8, u8);
|
pub struct RefMeta {
|
||||||
|
pub total: Cell<u16>,
|
||||||
|
pub is_shared: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
/* 3b type tag */
|
||||||
enum Val {
|
enum Val {
|
||||||
Stack(Stkval),
|
Stack(Stkval),
|
||||||
|
@ -93,97 +206,61 @@ enum Inst {
|
||||||
Return(Val),
|
Return(Val),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze(fm: &FuncMeta, scope: &mut Scope, e: &mut Expr) {
|
/// Value on fake stack.
|
||||||
|
enum FSValue {
|
||||||
|
Var(Ident),
|
||||||
|
Any,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {}
|
||||||
|
|
||||||
|
/// 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<Inst>,
|
||||||
|
shared_stack: Vec<FSValue>,
|
||||||
|
local_stack: Vec<FSValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
Stkval::Local(idx as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn translate(&mut self, e: &Expr) {
|
||||||
match e {
|
match e {
|
||||||
Expr::Assign(a, b) => {
|
_ => unimplemented!(),
|
||||||
let Expr::Literal(Literal::Ident(id, _)) = &**a else {
|
|
||||||
panic!("invalid assignment");
|
|
||||||
};
|
|
||||||
|
|
||||||
// add to scope
|
|
||||||
scope.assigned(id.clone());
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
|
|
||||||
// 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(&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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
15
src/lexer.rs
15
src/lexer.rs
|
@ -4,7 +4,7 @@ use std::{
|
||||||
num::{ParseFloatError, ParseIntError},
|
num::{ParseFloatError, ParseIntError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{compiler::RefMeta, kinds};
|
use crate::{compiler::RefStat, kinds};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Ident(String);
|
pub struct Ident(String);
|
||||||
|
@ -21,7 +21,7 @@ pub enum Literal {
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Nil,
|
Nil,
|
||||||
Ident(Ident, Option<RefMeta>),
|
Ident(Ident, Option<RefStat>),
|
||||||
}
|
}
|
||||||
impl fmt::Display for Literal {
|
impl fmt::Display for Literal {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
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::Integer(n) => write!(f, "{n}"),
|
||||||
Literal::Float(n) => write!(f, "{n}"),
|
Literal::Float(n) => write!(f, "{n}"),
|
||||||
Literal::Boolean(b) => write!(f, "{b}"),
|
Literal::Boolean(b) => write!(f, "{b}"),
|
||||||
Literal::Ident(id, ref_meta) => write!(
|
Literal::Ident(id, ref_stat) => write!(
|
||||||
f,
|
f,
|
||||||
"{id}{}",
|
"{id}{}",
|
||||||
ref_meta
|
ref_stat
|
||||||
.as_ref()
|
.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()
|
.unwrap_or_default()
|
||||||
),
|
),
|
||||||
Literal::Nil => write!(f, "nil"),
|
Literal::Nil => write!(f, "nil"),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{fmt, iter::Peekable};
|
use std::{fmt, iter::Peekable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compiler::FuncMeta,
|
compiler::FuncStat,
|
||||||
kind::Kind,
|
kind::Kind,
|
||||||
lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind},
|
lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind},
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ pub enum Expr {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
// Non-literal datatypes
|
// Non-literal datatypes
|
||||||
Block(Block),
|
Block(Block),
|
||||||
Func(Vec<Expr>, Box<Expr>, Option<FuncMeta>),
|
Func(Vec<Expr>, Box<Expr>, Option<FuncStat>),
|
||||||
// Control flow
|
// Control flow
|
||||||
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
|
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
|
||||||
Return(Box<Expr>),
|
Return(Box<Expr>),
|
||||||
|
|
|
@ -60,15 +60,19 @@ fn fmt_expr(e: &Expr, depth: usize) -> String {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Expr::Func(a, e, func_meta) => format!(
|
Expr::Func(a, e, func_stat) => format!(
|
||||||
"(func({}){} ({}))",
|
"(func({}){} ({}))",
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|e| fmt_expr(e, depth))
|
.map(|e| fmt_expr(e, depth))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", "),
|
.join(", "),
|
||||||
func_meta
|
func_stat
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|fm| format!("@{}", fm.get()))
|
.map(|fm| fm
|
||||||
|
.is_unreturnable
|
||||||
|
.get()
|
||||||
|
.then_some("@UNRET")
|
||||||
|
.unwrap_or("@OK"))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
fmt_expr(e, depth)
|
fmt_expr(e, depth)
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue