talc/talc-lang/src/optimize.rs

239 lines
4.6 KiB
Rust
Raw Normal View History

2024-11-12 15:40:51 -05:00
use core::panic;
use crate::{
2024-12-23 23:46:05 -05:00
parser::ast::{CatchBlock, Expr, ExprKind, LValue, LValueKind, ListItem, TableItem},
2024-11-12 15:40:51 -05:00
value::Value,
vm,
};
impl Expr {
fn value(&self) -> Option<&Value> {
if let ExprKind::Literal(v) = &self.kind {
Some(v)
} else {
None
}
}
}
fn expr_take(e: &mut Expr) -> Expr {
std::mem::replace(e, ExprKind::Literal(Value::Nil).span(e.span))
}
#[derive(Clone, Copy, Debug)]
struct OptState {
ret: bool,
}
impl OptState {
#[inline]
2024-11-14 14:16:33 -05:00
const fn empty() -> Self {
2024-11-12 15:40:51 -05:00
Self { ret: false }
}
#[inline]
2024-11-14 14:16:33 -05:00
const fn ret(ret: bool) -> Self {
2024-11-12 15:40:51 -05:00
Self { ret }
}
}
pub fn optimize(body: &mut Expr) {
let state = OptState::ret(true);
optimize_ex_with(body, state);
}
#[inline]
fn optimize_ex(expr: &mut Expr) {
optimize_ex_with(expr, OptState::empty());
}
fn optimize_ex_with(expr: &mut Expr, state: OptState) {
let span = expr.span;
match &mut expr.kind {
ExprKind::Literal(_) => (),
ExprKind::Ident(_) => (),
2024-12-30 23:56:53 -05:00
ExprKind::Var(_) => (),
ExprKind::Global(_) => (),
2024-11-12 15:40:51 -05:00
ExprKind::UnaryOp(o, e) => {
optimize_ex(e);
if let Some(a) = e.value() {
if let Ok(v) = vm::unary_op(*o, a.clone()) {
*expr = ExprKind::Literal(v).span(span);
}
}
}
ExprKind::BinaryOp(o, l, r) => {
optimize_ex(l);
optimize_ex(r);
if let (Some(a), Some(b)) = (l.value(), r.value()) {
if let Ok(v) = vm::binary_op(*o, a.clone(), b.clone()) {
*expr = ExprKind::Literal(v).span(span);
}
}
}
ExprKind::Assign(_, l, r) => {
optimize_lv(l);
optimize_ex(r);
}
ExprKind::FnDef(_, _, e) => {
optimize_ex_with(e, OptState::ret(true));
}
ExprKind::Index(l, r) => {
optimize_ex(l);
optimize_ex(r);
}
ExprKind::FnCall(f, xs) => {
optimize_ex(f);
for e in &mut *xs {
optimize_ex(e);
}
if state.ret {
*expr = ExprKind::TailCall(Box::new(expr_take(f)), std::mem::take(xs))
.span(span);
}
}
ExprKind::AssocFnCall(f, a, xs) => {
optimize_ex(f);
for e in &mut *xs {
optimize_ex(e);
}
if state.ret {
*expr =
ExprKind::AssocTailCall(Box::new(expr_take(f)), *a, std::mem::take(xs))
.span(span);
}
}
ExprKind::Pipe(l, r) => {
optimize_ex(l);
optimize_ex(r);
}
ExprKind::Block(xs) => {
let len = xs.len();
if len > 1 {
for e in &mut xs[..len - 1] {
optimize_ex(e);
}
}
if let Some(e) = xs.last_mut() {
optimize_ex_with(e, state);
}
}
ExprKind::List(xs) => {
for e in xs {
2024-12-23 23:46:05 -05:00
match e {
ListItem::Item(e) => optimize_ex(e),
ListItem::Interpolate(e) => optimize_ex(e),
}
2024-11-12 15:40:51 -05:00
}
}
ExprKind::Table(t) => {
2024-12-23 23:46:05 -05:00
for e in t {
match e {
TableItem::Pair(k, v) => {
optimize_ex(k);
optimize_ex(v);
}
TableItem::Interpolate(ext) => {
optimize_ex(ext);
}
}
2024-11-12 15:40:51 -05:00
}
}
ExprKind::Return(e) => {
if let Some(e) = e {
optimize_ex_with(e, OptState::ret(true));
}
}
ExprKind::Break(e) => {
if let Some(e) = e {
optimize_ex(e);
}
}
ExprKind::Continue => (),
ExprKind::And(l, r) => {
optimize_ex(l);
optimize_ex(r);
if let Some(v) = l.value() {
if v.truthy() {
*expr = expr_take(r);
} else {
*expr = expr_take(l);
}
}
}
ExprKind::Or(l, r) => {
optimize_ex(l);
optimize_ex(r);
if let Some(v) = l.value() {
if v.truthy() {
*expr = expr_take(l);
} else {
*expr = expr_take(r);
}
}
}
ExprKind::If(c, t, e) => {
optimize_ex(c);
optimize_ex_with(t, state);
if let Some(e) = e {
optimize_ex_with(e, state);
}
if let Some(v) = c.value() {
if v.truthy() {
*expr = expr_take(t);
} else if let Some(e) = e {
*expr = expr_take(e);
} else {
*expr = ExprKind::Literal(Value::Nil).span(span);
}
}
}
ExprKind::While(c, b) => {
optimize_ex(c);
optimize_ex(b);
if let Some(v) = c.value() {
if !v.truthy() {
*expr = ExprKind::Literal(Value::Nil).span(span);
}
}
}
ExprKind::For(_, i, b) => {
optimize_ex(i);
optimize_ex(b);
}
ExprKind::Lambda(_, b) => {
optimize_ex_with(b, OptState::ret(true));
}
ExprKind::Try(b, cx) => {
optimize_ex_with(b, state);
for c in cx {
optimize_cb(c);
}
}
ExprKind::TailCall(..) | ExprKind::AssocTailCall(..) => {
panic!("cannot optimize expression generated by optimizer")
}
}
}
2024-11-14 14:16:33 -05:00
fn optimize_lv(e: &mut LValue) {
2024-11-12 15:40:51 -05:00
match &mut e.kind {
LValueKind::Ident(_) => (),
2024-12-30 23:56:53 -05:00
LValueKind::Var(_) => (),
LValueKind::Global(_) => (),
2024-11-12 15:40:51 -05:00
LValueKind::Index(l, r) => {
optimize_ex(l);
optimize_ex(r);
}
2024-12-30 23:56:53 -05:00
LValueKind::List(ls, _) => {
for l in ls {
optimize_lv(l);
}
}
2024-11-12 15:40:51 -05:00
}
}
2024-11-14 14:16:33 -05:00
fn optimize_cb(e: &mut CatchBlock) {
2024-11-12 15:40:51 -05:00
optimize_ex(&mut e.body);
}