anything above
This commit is contained in:
parent
67e701bc7c
commit
479fd637c3
|
@ -5,6 +5,8 @@ use crate::{
|
||||||
parser::Expr,
|
parser::Expr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub type FuncMeta = Rc<Cell<bool>>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RefMeta {
|
pub struct RefMeta {
|
||||||
pub now: u16,
|
pub now: u16,
|
||||||
|
@ -25,25 +27,28 @@ impl<'a> Scope<'a> {
|
||||||
fn assigned(&mut self, id: Ident) {
|
fn assigned(&mut self, id: Ident) {
|
||||||
self.idents.push((id, Rc::default()));
|
self.idents.push((id, Rc::default()));
|
||||||
}
|
}
|
||||||
fn find(&self, id: &Ident) -> Rc<Cell<u16>> {
|
fn find(&self, id: &Ident) -> (Rc<Cell<u16>>, bool) {
|
||||||
let mut cur = Some(self);
|
let mut cur = Some(self);
|
||||||
|
let mut went_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((_, count)) = scope.idents.iter().rev().find(|i| i.0 == *id) else {
|
||||||
cur = scope.parent;
|
cur = scope.parent;
|
||||||
|
went_up = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
return count.clone();
|
return (count.clone(), went_up);
|
||||||
}
|
}
|
||||||
panic!("undefined variable");
|
panic!("undefined variable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(e: &mut Expr) {
|
pub fn compile(e: &mut Expr) {
|
||||||
|
let fm = FuncMeta::default();
|
||||||
let mut scope = Scope::with_parent(None);
|
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 {
|
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 {
|
||||||
|
@ -54,11 +59,11 @@ fn analyze(scope: &mut Scope, e: &mut Expr) {
|
||||||
scope.assigned(id.clone());
|
scope.assigned(id.clone());
|
||||||
|
|
||||||
// analyse the value
|
// analyse the value
|
||||||
analyze(scope, b);
|
analyze(fm, scope, b);
|
||||||
}
|
}
|
||||||
Expr::Literal(Literal::Ident(id, ref_meta)) => {
|
Expr::Literal(Literal::Ident(id, ref_meta)) => {
|
||||||
// lookup literal
|
// lookup literal
|
||||||
let count = scope.find(id);
|
let (count, went_up) = scope.find(id);
|
||||||
// increment # of uses
|
// increment # of uses
|
||||||
count.update(|c| c + 1);
|
count.update(|c| c + 1);
|
||||||
// set ref meta
|
// set ref meta
|
||||||
|
@ -66,6 +71,10 @@ fn analyze(scope: &mut Scope, e: &mut Expr) {
|
||||||
now: count.get(),
|
now: count.get(),
|
||||||
total: count,
|
total: count,
|
||||||
});
|
});
|
||||||
|
// if we used something external to this scope, note it
|
||||||
|
if went_up {
|
||||||
|
fm.set(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ignore
|
// ignore
|
||||||
Expr::Literal(_) => {}
|
Expr::Literal(_) => {}
|
||||||
|
@ -75,10 +84,13 @@ fn analyze(scope: &mut Scope, e: &mut Expr) {
|
||||||
let mut scope = Scope::with_parent(Some(scope));
|
let mut scope = Scope::with_parent(Some(scope));
|
||||||
// analyze the contents in the new scope
|
// analyze the contents in the new scope
|
||||||
for e in &mut a.exprs {
|
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
|
// functions have their own scope, because they have args
|
||||||
let mut scope = Scope::with_parent(Some(scope));
|
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
|
// now analyze the body in the new scope
|
||||||
analyze(&mut scope, b);
|
analyze(&fm, &mut scope, b);
|
||||||
}
|
}
|
||||||
Expr::If(a, b, c) => {
|
Expr::If(a, b, c) => {
|
||||||
analyze(scope, a);
|
analyze(fm, scope, a);
|
||||||
analyze(scope, b);
|
analyze(fm, scope, b);
|
||||||
if let Some(c) = c {
|
if let Some(c) = c {
|
||||||
analyze(scope, c);
|
analyze(fm, scope, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(a, b) => {
|
Expr::Call(a, b) => {
|
||||||
analyze(scope, a);
|
analyze(fm, scope, a);
|
||||||
for e in b {
|
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::EqualTo(a, b)
|
||||||
| Expr::NotEqualTo(a, b)
|
| Expr::NotEqualTo(a, b)
|
||||||
| Expr::And(a, b)
|
| Expr::And(a, b)
|
||||||
|
@ -125,8 +137,8 @@ fn analyze(scope: &mut Scope, e: &mut Expr) {
|
||||||
| Expr::SubtractAssign(a, b)
|
| Expr::SubtractAssign(a, b)
|
||||||
| Expr::MultiplyAssign(a, b)
|
| Expr::MultiplyAssign(a, b)
|
||||||
| Expr::DivideAssign(a, b) => {
|
| Expr::DivideAssign(a, b) => {
|
||||||
analyze(scope, a);
|
analyze(fm, scope, a);
|
||||||
analyze(scope, b);
|
analyze(fm, scope, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
use std::{fmt, iter::Peekable};
|
use std::{fmt, iter::Peekable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
compiler::FuncMeta,
|
||||||
kind::Kind,
|
kind::Kind,
|
||||||
lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind},
|
lexer::{Associativity, LexError, Literal, Precedence, Token, TokenKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
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),
|
||||||
// Non-literal datatypes
|
// Non-literal datatypes
|
||||||
Block(Block),
|
Block(Block),
|
||||||
Func(Vec<Expr>, Box<Expr>),
|
Func(Vec<Expr>, Box<Expr>, Option<FuncMeta>),
|
||||||
// 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>),
|
||||||
|
@ -46,7 +47,7 @@ pub enum Expr {
|
||||||
DivideAssign(Box<Expr>, Box<Expr>),
|
DivideAssign(Box<Expr>, Box<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub exprs: Vec<Expr>,
|
pub exprs: Vec<Expr>,
|
||||||
}
|
}
|
||||||
|
@ -154,7 +155,7 @@ where
|
||||||
// parse body
|
// parse body
|
||||||
let body = self.parse_expr(prec, in_group)?;
|
let body = self.parse_expr(prec, in_group)?;
|
||||||
// pack
|
// pack
|
||||||
Box::new(Expr::Func(args, body))
|
Box::new(Expr::Func(args, body, None))
|
||||||
}
|
}
|
||||||
// parse if
|
// parse if
|
||||||
Token::If => {
|
Token::If => {
|
||||||
|
|
|
@ -60,12 +60,16 @@ fn fmt_expr(e: &Expr, depth: usize) -> String {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Expr::Func(a, e) => format!(
|
Expr::Func(a, e, func_meta) => 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
|
||||||
|
.as_ref()
|
||||||
|
.map(|fm| format!("@{}", fm.get()))
|
||||||
|
.unwrap_or_default(),
|
||||||
fmt_expr(e, depth)
|
fmt_expr(e, depth)
|
||||||
),
|
),
|
||||||
Expr::Negate(l) => format!("(-{})", fmt_expr(l, depth)),
|
Expr::Negate(l) => format!("(-{})", fmt_expr(l, depth)),
|
||||||
|
|
Loading…
Reference in New Issue