factorio-ir 0.5.0

Intermediate representation for factorio-rs Rust-to-Lua Factorio mod transpilation
Documentation
mod expand;
mod expr;
mod extract;

use crate::{
    block::Block,
    expression::Expression,
    function::Function,
    module::{Module, Symbol},
    statement::Statement,
};

use expand::expand_statement;
use expr::optimize_expression;

pub(super) fn optimize_module(module: &mut Module) {
    optimize_block(&mut module.body);
    for symbol in &mut module.symbols {
        optimize_symbol(symbol);
    }
}

fn optimize_symbol(symbol: &mut Symbol) {
    optimize_statement_inplace(&mut symbol.statement);
}

fn optimize_block(block: &mut Block) {
    block.statements = optimize_statements(std::mem::take(&mut block.statements));
}

fn optimize_statement_inplace(statement: &mut Statement) {
    match statement {
        Statement::FunctionDecl(function) => optimize_function(function),
        Statement::StructDecl(struct_decl) => {
            for method in &mut struct_decl.methods {
                optimize_function(method);
            }
        }
        Statement::EnumDecl(enum_decl) => {
            for method in &mut enum_decl.methods {
                optimize_function(method);
            }
            for (_, value) in &mut enum_decl.constants {
                optimize_expression(value);
            }
        }
        Statement::VariableDecl { value, .. }
        | Statement::Return(Some(value))
        | Statement::Expr(value) => optimize_expression(value),
        Statement::Assignment { target, value } => {
            optimize_expression(target);
            optimize_expression(value);
        }
        Statement::Conditional {
            condition,
            then_block,
            else_block,
        } => {
            optimize_expression(condition);
            *then_block = optimize_statements(std::mem::take(then_block));
            *else_block = optimize_statements(std::mem::take(else_block));
        }
        Statement::Return(None)
        | Statement::Continue
        | Statement::Break
        | Statement::RawLua { .. }
        | Statement::SourceOrigin { .. } => {}
        Statement::ForIn { iter, body, .. } => {
            optimize_expression(iter);
            *body = optimize_statements(std::mem::take(body));
        }
        Statement::ForNumeric {
            start, limit, body, ..
        } => {
            optimize_expression(start);
            optimize_expression(limit);
            *body = optimize_statements(std::mem::take(body));
        }
        Statement::While { condition, body } => {
            optimize_expression(condition);
            *body = optimize_statements(std::mem::take(body));
        }
    }
}

fn optimize_function(function: &mut Function) {
    optimize_block(&mut function.body);
    if let Some(filter) = &mut function.event_filter {
        optimize_expression(filter);
    }
}

fn optimize_statements(statements: Vec<Statement>) -> Vec<Statement> {
    let mut out = Vec::with_capacity(statements.len());
    let mut hoist_counter = 0u32;
    for statement in statements {
        out.extend(expand_statement(statement, &mut hoist_counter));
    }
    out
}

const fn is_simple_assign_target(target: &Expression) -> bool {
    matches!(
        target,
        Expression::Identifier(_)
            | Expression::FieldAccess { .. }
            | Expression::Index { .. }
            | Expression::QualifiedPath { .. }
    )
}