yulang-runtime-refine 0.1.0

Runtime type refinement, validation, invariant checks, and hygiene printing for Yulang.
Documentation
use super::*;

pub(super) fn pattern_bindings(pattern: &Pattern) -> Vec<(typed_ir::Path, RuntimeType)> {
    let mut bindings = Vec::new();
    collect_pattern_bindings(pattern, &mut bindings);
    bindings
}

pub(super) fn push_bindings(
    locals: &mut HashMap<typed_ir::Path, RuntimeType>,
    bindings: &[(typed_ir::Path, RuntimeType)],
) -> Vec<(typed_ir::Path, Option<RuntimeType>)> {
    bindings
        .iter()
        .map(|(path, ty)| (path.clone(), locals.insert(path.clone(), ty.clone())))
        .collect()
}

pub(super) fn push_binding(
    locals: &mut HashMap<typed_ir::Path, RuntimeType>,
    path: typed_ir::Path,
    ty: RuntimeType,
) -> Vec<(typed_ir::Path, Option<RuntimeType>)> {
    vec![(path.clone(), locals.insert(path, ty))]
}

pub(super) fn pop_bindings(
    locals: &mut HashMap<typed_ir::Path, RuntimeType>,
    previous: Vec<(typed_ir::Path, Option<RuntimeType>)>,
) {
    for (path, ty) in previous.into_iter().rev() {
        match ty {
            Some(ty) => {
                locals.insert(path, ty);
            }
            None => {
                locals.remove(&path);
            }
        }
    }
}

pub(super) fn push_stmt_bindings(locals: &mut HashMap<typed_ir::Path, RuntimeType>, stmt: &Stmt) {
    match stmt {
        Stmt::Let { pattern, .. } => {
            for (path, ty) in pattern_bindings(pattern) {
                locals.insert(path, ty);
            }
        }
        Stmt::Module { def, body } => {
            locals.insert(def.clone(), body.ty.clone());
        }
        Stmt::Expr(_) => {}
    }
}

fn collect_pattern_bindings(pattern: &Pattern, bindings: &mut Vec<(typed_ir::Path, RuntimeType)>) {
    match pattern {
        Pattern::Bind { name, ty } => {
            bindings.push((typed_ir::Path::from_name(name.clone()), ty.clone()));
        }
        Pattern::As { pattern, name, ty } => {
            collect_pattern_bindings(pattern, bindings);
            bindings.push((typed_ir::Path::from_name(name.clone()), ty.clone()));
        }
        Pattern::Tuple { items, .. } | Pattern::List { prefix: items, .. } => {
            for item in items {
                collect_pattern_bindings(item, bindings);
            }
            if let Pattern::List { spread, suffix, .. } = pattern {
                if let Some(spread) = spread {
                    collect_pattern_bindings(spread, bindings);
                }
                for item in suffix {
                    collect_pattern_bindings(item, bindings);
                }
            }
        }
        Pattern::Record { fields, spread, .. } => {
            for field in fields {
                collect_pattern_bindings(&field.pattern, bindings);
            }
            if let Some(spread) = spread {
                match spread {
                    RecordSpreadPattern::Head(pattern) | RecordSpreadPattern::Tail(pattern) => {
                        collect_pattern_bindings(pattern, bindings);
                    }
                }
            }
        }
        Pattern::Variant { value, .. } => {
            if let Some(value) = value {
                collect_pattern_bindings(value, bindings);
            }
        }
        Pattern::Or { left, right, .. } => {
            collect_pattern_bindings(left, bindings);
            collect_pattern_bindings(right, bindings);
        }
        Pattern::Wildcard { .. } | Pattern::Lit { .. } => {}
    }
}