formalang 0.0.5-beta

FormaLang compiler frontend: lexer, parser, semantic analyzer, and IR lowering.
Documentation
use crate::ir::{IrExpr, IrModule};

use super::IdRemap;

pub(super) fn build_impl_index_remap(module: &IrModule, remap: &IdRemap) -> Vec<Option<usize>> {
    use crate::ir::ImplTarget;
    let mut out = Vec::with_capacity(module.impls.len());
    let mut next: usize = 0;
    for imp in &module.impls {
        let keep = match imp.target {
            ImplTarget::Struct(id) => remap.struct_of(id).is_some(),
            ImplTarget::Enum(id) => remap.enum_of(id).is_some(),
            ImplTarget::Primitive(_) => true,
        };
        if keep {
            out.push(Some(next));
            next = next.saturating_add(1);
        } else {
            out.push(None);
        }
    }
    out
}

pub(super) fn apply_impl_index_remap(module: &mut IrModule, remap: &[Option<usize>]) {
    let identity = remap
        .iter()
        .enumerate()
        .all(|(i, slot)| matches!(slot, Some(j) if *j == i));
    if identity {
        return;
    }
    for f in &mut module.functions {
        if let Some(body) = &mut f.body {
            rewrite_static_impl_ids(body, remap);
        }
    }
    for imp in &mut module.impls {
        for f in &mut imp.functions {
            if let Some(body) = &mut f.body {
                rewrite_static_impl_ids(body, remap);
            }
        }
    }
    for s in &mut module.structs {
        for field in &mut s.fields {
            if let Some(default) = &mut field.default {
                rewrite_static_impl_ids(default, remap);
            }
        }
    }
    for l in &mut module.lets {
        rewrite_static_impl_ids(&mut l.value, remap);
    }
}

fn rewrite_static_impl_ids(expr: &mut IrExpr, remap: &[Option<usize>]) {
    use crate::ir::{DispatchKind, ImplId};
    walk_expr_static_impl(expr, remap);
    if let IrExpr::MethodCall {
        dispatch: DispatchKind::Static { impl_id },
        ..
    } = expr
    {
        if let Some(Some(new)) = remap.get(impl_id.0 as usize).copied() {
            *impl_id = ImplId(u32::try_from(new).unwrap_or(u32::MAX));
        }
    }
}

fn walk_expr_static_impl(expr: &mut IrExpr, remap: &[Option<usize>]) {
    use crate::ir::IrBlockStatement;
    match expr {
        IrExpr::StructInst { fields, .. } | IrExpr::EnumInst { fields, .. } => {
            for (_, _, e) in fields {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::Array { elements, .. } => {
            for e in elements {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::Tuple { fields, .. } => {
            for (_, e) in fields {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::BinaryOp { left, right, .. } => {
            rewrite_static_impl_ids(left, remap);
            rewrite_static_impl_ids(right, remap);
        }
        IrExpr::UnaryOp { operand, .. } => rewrite_static_impl_ids(operand, remap),
        IrExpr::FieldAccess { object, .. } => rewrite_static_impl_ids(object, remap),
        IrExpr::If {
            condition,
            then_branch,
            else_branch,
            ..
        } => {
            rewrite_static_impl_ids(condition, remap);
            rewrite_static_impl_ids(then_branch, remap);
            if let Some(e) = else_branch {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::For {
            collection, body, ..
        } => {
            rewrite_static_impl_ids(collection, remap);
            rewrite_static_impl_ids(body, remap);
        }
        IrExpr::Match {
            scrutinee, arms, ..
        } => {
            rewrite_static_impl_ids(scrutinee, remap);
            for arm in arms {
                rewrite_static_impl_ids(&mut arm.body, remap);
            }
        }
        IrExpr::FunctionCall { args, .. } => {
            for (_, e) in args {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::CallClosure { closure, args, .. } => {
            rewrite_static_impl_ids(closure, remap);
            for (_, e) in args {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::MethodCall { receiver, args, .. } => {
            rewrite_static_impl_ids(receiver, remap);
            for (_, e) in args {
                rewrite_static_impl_ids(e, remap);
            }
        }
        IrExpr::Closure { body, .. } => rewrite_static_impl_ids(body, remap),
        IrExpr::ClosureRef { env_struct, .. } => rewrite_static_impl_ids(env_struct, remap),
        IrExpr::DictLiteral { entries, .. } => {
            for (k, v) in entries {
                rewrite_static_impl_ids(k, remap);
                rewrite_static_impl_ids(v, remap);
            }
        }
        IrExpr::DictAccess { dict, key, .. } => {
            rewrite_static_impl_ids(dict, remap);
            rewrite_static_impl_ids(key, remap);
        }
        IrExpr::Block {
            statements, result, ..
        } => {
            for stmt in statements.iter_mut() {
                match stmt {
                    IrBlockStatement::Let { value, .. } => rewrite_static_impl_ids(value, remap),
                    IrBlockStatement::Assign { target, value, .. } => {
                        rewrite_static_impl_ids(target, remap);
                        rewrite_static_impl_ids(value, remap);
                    }
                    IrBlockStatement::Expr(e) => rewrite_static_impl_ids(e, remap),
                }
            }
            rewrite_static_impl_ids(result, remap);
        }
        IrExpr::Literal { .. }
        | IrExpr::Reference { .. }
        | IrExpr::SelfFieldRef { .. }
        | IrExpr::LetRef { .. } => {}
    }
}