better analysis?
This commit is contained in:
parent
cd88afcb98
commit
bf6e540e1c
|
|
@ -67,7 +67,7 @@ pub struct RefMeta {
|
||||||
pub is_shared: Cell<bool>,
|
pub is_shared: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
|
fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr, gets_captured: bool) {
|
||||||
match e {
|
match e {
|
||||||
Expr::Assign(a, b) => {
|
Expr::Assign(a, b) => {
|
||||||
let Expr::Literal(Literal::Ident(id, ref_stat)) = &mut **a else {
|
let Expr::Literal(Literal::Ident(id, ref_stat)) = &mut **a else {
|
||||||
|
|
@ -78,38 +78,55 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
|
||||||
let rm = scope.assigned(id.clone());
|
let rm = scope.assigned(id.clone());
|
||||||
|
|
||||||
// add ref stat
|
// add ref stat
|
||||||
*ref_stat = Some(RefStat { now: rm.total.get(), meta: rm });
|
*ref_stat = Some(RefStat {
|
||||||
|
now: rm.total.get(),
|
||||||
|
meta: rm,
|
||||||
|
});
|
||||||
|
|
||||||
// analyse the value
|
// analyse the value
|
||||||
analyze(fs, scope, b);
|
analyze(fs, scope, b, true);
|
||||||
}
|
}
|
||||||
Expr::Literal(Literal::Ident(id, ref_stat)) => {
|
Expr::Literal(Literal::Ident(id, ref_stat)) => {
|
||||||
// lookup literal
|
// lookup ident
|
||||||
let Some((rm, up_levels)) = scope.find(id) else {
|
let Some((rm, up_levels)) = scope.find(id) else {
|
||||||
panic!("unfound variable")
|
panic!("unfound variable")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// the var got used, so the compiler will gen code for it
|
||||||
|
// it is okay to count
|
||||||
|
if gets_captured {
|
||||||
// increment # of uses
|
// increment # of uses
|
||||||
rm.total.update(|c| c + 1);
|
rm.total.update(|c| c + 1);
|
||||||
// set ref meta
|
|
||||||
*ref_stat = Some(RefStat {
|
|
||||||
now: rm.total.get(),
|
|
||||||
meta: rm.clone(),
|
|
||||||
});
|
|
||||||
// if we used something external to this scope, note it
|
// if we used something external to this scope, note it
|
||||||
if up_levels != 0 {
|
if up_levels != 0 {
|
||||||
fs.is_unreturnable.set(true);
|
fs.is_unreturnable.set(true);
|
||||||
rm.is_shared.set(true);
|
rm.is_shared.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set ref meta
|
||||||
|
*ref_stat = Some(RefStat {
|
||||||
|
now: rm.total.get(),
|
||||||
|
meta: rm.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
// 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
|
||||||
let mut scope = Scope::with_parent(Some(scope));
|
let mut scope = Scope::with_parent(Some(scope));
|
||||||
|
// last is treated differently
|
||||||
|
let last = a.exprs.pop();
|
||||||
// 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(fs, &mut scope, e);
|
analyze(fs, &mut scope, e, false);
|
||||||
|
}
|
||||||
|
// analyze last
|
||||||
|
if let Some(mut last) = last {
|
||||||
|
analyze(fs, &mut scope, &mut last, gets_captured);
|
||||||
|
a.exprs.push(last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Func(a, b, func_stat) => {
|
Expr::Func(a, b, func_stat) => {
|
||||||
|
|
@ -128,22 +145,22 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// now analyze the body in the new scope
|
// now analyze the body in the new scope
|
||||||
analyze(&fs, &mut scope, b);
|
analyze(&fs, &mut scope, b, true);
|
||||||
}
|
}
|
||||||
Expr::If(a, b, c) => {
|
Expr::If(a, b, c) => {
|
||||||
analyze(fs, scope, a);
|
analyze(fs, scope, a, true);
|
||||||
analyze(fs, scope, b);
|
analyze(fs, scope, b, gets_captured);
|
||||||
if let Some(c) = c {
|
if let Some(c) = c {
|
||||||
analyze(fs, scope, c);
|
analyze(fs, scope, c, gets_captured);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(a, b) => {
|
Expr::Call(a, b) => {
|
||||||
analyze(fs, scope, a);
|
analyze(fs, scope, a, true);
|
||||||
for e in b {
|
for e in b {
|
||||||
analyze(fs, scope, e);
|
analyze(fs, scope, e, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(fs, scope, a),
|
Expr::Return(a) | Expr::Negate(a) | Expr::Not(a) => analyze(fs, scope, a, true),
|
||||||
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,13 +174,16 @@ fn analyze(fs: &FuncStat, scope: &mut Scope, e: &mut Expr) {
|
||||||
| Expr::Multiply(a, b)
|
| Expr::Multiply(a, b)
|
||||||
| Expr::Divide(a, b)
|
| Expr::Divide(a, b)
|
||||||
| Expr::Exponent(a, b)
|
| Expr::Exponent(a, b)
|
||||||
| Expr::Modulo(a, b)
|
| Expr::Modulo(a, b) => {
|
||||||
| Expr::AddAssign(a, b) // maybe handle these differently?
|
analyze(fs, scope, a, gets_captured);
|
||||||
| Expr::SubtractAssign(a, b) // when error handling is added at least
|
analyze(fs, scope, b, gets_captured);
|
||||||
|
}
|
||||||
|
Expr::AddAssign(a, b)
|
||||||
|
| Expr::SubtractAssign(a, b)
|
||||||
| Expr::MultiplyAssign(a, b)
|
| Expr::MultiplyAssign(a, b)
|
||||||
| Expr::DivideAssign(a, b) => {
|
| Expr::DivideAssign(a, b) => {
|
||||||
analyze(fs, scope, a);
|
analyze(fs, scope, a, true);
|
||||||
analyze(fs, scope, b);
|
analyze(fs, scope, b, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -410,17 +430,16 @@ impl<'a> FuncBuild<'a> {
|
||||||
// if this isn't getting used for computation OR referenced,
|
// if this isn't getting used for computation OR referenced,
|
||||||
// just continue translation without adding to stack
|
// just continue translation without adding to stack
|
||||||
if !(do_compute || gets_referenced) {
|
if !(do_compute || gets_referenced) {
|
||||||
// do_compute would be false anyway
|
// do_compute doesn't matter for literals
|
||||||
self.translate(*r, false, false)
|
self.translate(*r, true, false)
|
||||||
} else {
|
} else {
|
||||||
// get val
|
// get val
|
||||||
let val = match *r {
|
let val = match *r {
|
||||||
// the var's value is a literal
|
// the var's value is a literal
|
||||||
// do_compute doesn't matter so leave it as false
|
// if the var gets used as a var, yield to stack
|
||||||
// if the var gets used as a var, we yield to stack
|
|
||||||
// otherwise just return the literal
|
// otherwise just return the literal
|
||||||
Expr::Literal(lit) => {
|
Expr::Literal(lit) => {
|
||||||
self.translate(Expr::Literal(lit), false, gets_referenced)
|
self.translate(Expr::Literal(lit), true, gets_referenced)
|
||||||
}
|
}
|
||||||
|
|
||||||
// value is an expr
|
// value is an expr
|
||||||
|
|
@ -494,7 +513,7 @@ pub fn analysis_demo(e: &mut Expr) {
|
||||||
// analysis pass
|
// analysis pass
|
||||||
let fs = FuncStat::default();
|
let fs = FuncStat::default();
|
||||||
let mut scope = Scope::with_parent(None);
|
let mut scope = Scope::with_parent(None);
|
||||||
analyze(&fs, &mut scope, e);
|
analyze(&fs, &mut scope, e, false);
|
||||||
}
|
}
|
||||||
pub fn translation_demo(e: Expr) -> Vec<Inst> {
|
pub fn translation_demo(e: Expr) -> Vec<Inst> {
|
||||||
// translation pass
|
// translation pass
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue