factorio-ir 0.5.0

Intermediate representation for factorio-rs Rust-to-Lua Factorio mod transpilation
Documentation
use crate::{expression::Expression, statement::Statement};

pub(super) fn replace_ident_in_statement(statement: &mut Statement, name: &str, with: &Expression) {
    match statement {
        Statement::VariableDecl { value, .. }
        | Statement::Return(Some(value))
        | Statement::Expr(value) => replace_ident_in_expr(value, name, with),
        Statement::Assignment { target, value } => {
            replace_ident_in_expr(target, name, with);
            replace_ident_in_expr(value, name, with);
        }
        Statement::Conditional {
            condition,
            then_block,
            else_block,
        } => {
            replace_ident_in_expr(condition, name, with);
            for s in then_block {
                replace_ident_in_statement(s, name, with);
            }
            for s in else_block {
                replace_ident_in_statement(s, name, with);
            }
        }
        Statement::ForIn { iter, body, .. } => {
            replace_ident_in_expr(iter, name, with);
            for s in body {
                replace_ident_in_statement(s, name, with);
            }
        }
        Statement::ForNumeric {
            start, limit, body, ..
        } => {
            replace_ident_in_expr(start, name, with);
            replace_ident_in_expr(limit, name, with);
            for s in body {
                replace_ident_in_statement(s, name, with);
            }
        }
        Statement::While { condition, body } => {
            replace_ident_in_expr(condition, name, with);
            for s in body {
                replace_ident_in_statement(s, name, with);
            }
        }
        Statement::FunctionDecl(function) => {
            if function.params.iter().any(|p| p.name == name) {
                return;
            }
            for s in &mut function.body.statements {
                replace_ident_in_statement(s, name, with);
            }
        }
        Statement::StructDecl(struct_decl) => {
            for method in &mut struct_decl.methods {
                if method.params.iter().any(|p| p.name == name) {
                    continue;
                }
                for s in &mut method.body.statements {
                    replace_ident_in_statement(s, name, with);
                }
            }
        }
        Statement::EnumDecl(enum_decl) => {
            for method in &mut enum_decl.methods {
                if method.params.iter().any(|p| p.name == name) {
                    continue;
                }
                for s in &mut method.body.statements {
                    replace_ident_in_statement(s, name, with);
                }
            }
        }
        Statement::Return(None)
        | Statement::Continue
        | Statement::Break
        | Statement::RawLua { .. }
        | Statement::SourceOrigin { .. } => {}
    }
}

pub(super) fn replace_ident_in_expr(expr: &mut Expression, name: &str, with: &Expression) {
    match expr {
        Expression::Identifier(id) if id == name => *expr = with.clone(),
        Expression::FieldAccess { base, .. }
        | Expression::Not(base)
        | Expression::Len(base)
        | Expression::FatPointer { data: base, .. } => replace_ident_in_expr(base, name, with),
        Expression::Call { func, args } => {
            replace_ident_in_expr(func, name, with);
            for arg in args {
                replace_ident_in_expr(arg, name, with);
            }
        }
        Expression::MethodCall { receiver, args, .. }
        | Expression::DynMethodCall { receiver, args, .. } => {
            replace_ident_in_expr(receiver, name, with);
            for arg in args {
                replace_ident_in_expr(arg, name, with);
            }
        }
        Expression::BinaryOp { lhs, rhs, .. } => {
            replace_ident_in_expr(lhs, name, with);
            replace_ident_in_expr(rhs, name, with);
        }
        Expression::Index { base, key } => {
            replace_ident_in_expr(base, name, with);
            replace_ident_in_expr(key, name, with);
        }
        Expression::FormatConcat { parts } | Expression::Array { elements: parts } => {
            for part in parts {
                replace_ident_in_expr(part, name, with);
            }
        }
        Expression::StructLiteral { fields, .. } | Expression::EnumLiteral { fields, .. } => {
            for (_, value) in fields {
                replace_ident_in_expr(value, name, with);
            }
        }
        Expression::If {
            condition,
            then_expr,
            else_expr,
        } => {
            replace_ident_in_expr(condition, name, with);
            replace_ident_in_expr(then_expr, name, with);
            replace_ident_in_expr(else_expr, name, with);
        }
        Expression::Closure { params, body } => {
            if params.iter().any(|p| p == name) {
                return;
            }
            for statement in &mut body.statements {
                replace_ident_in_statement(statement, name, with);
            }
        }
        Expression::Literal(_) | Expression::Identifier(_) | Expression::QualifiedPath { .. } => {}
    }
}