yulang-runtime 0.1.1

Runtime IR, validation, monomorphization, and VM support for Yulang
Documentation
use super::*;

pub(super) fn is_role_method_path(path: &typed_ir::Path) -> bool {
    let Some(role) = path.segments.iter().rev().nth(1) else {
        return false;
    };
    role.0.chars().next().is_some_and(char::is_uppercase)
}

pub(super) fn is_specialized_path(path: &typed_ir::Path) -> bool {
    path.segments
        .last()
        .is_some_and(|segment| segment.0.contains("__mono"))
}

pub(super) fn specialization_suffix(path: &typed_ir::Path) -> Option<usize> {
    path.segments
        .last()?
        .0
        .rsplit_once("__mono")?
        .1
        .parse()
        .ok()
}

pub(super) fn unspecialized_path(path: &typed_ir::Path) -> Option<typed_ir::Path> {
    let mut path = path.clone();
    let name = &mut path.segments.last_mut()?.0;
    let index = name.find("__mono")?;
    name.truncate(index);
    Some(path)
}

pub(super) fn canonical_path(path: &typed_ir::Path) -> String {
    path.segments
        .iter()
        .map(|segment| segment.0.as_str())
        .collect::<Vec<_>>()
        .join("::")
}

pub(super) fn canonical_type(ty: &typed_ir::Type, out: &mut String) {
    match ty {
        typed_ir::Type::Unknown => out.push('?'),
        typed_ir::Type::Any => out.push('_'),
        typed_ir::Type::Never => out.push('!'),
        typed_ir::Type::Var(var) => out.push_str(&var.0),
        typed_ir::Type::Named { path, args } => {
            out.push_str(&canonical_path(path));
            if !args.is_empty() {
                out.push('<');
                for (index, arg) in args.iter().enumerate() {
                    if index > 0 {
                        out.push(',');
                    }
                    canonical_type_arg(arg, out);
                }
                out.push('>');
            }
        }
        typed_ir::Type::Fun {
            param,
            param_effect,
            ret_effect,
            ret,
        } => {
            out.push('(');
            canonical_type(param, out);
            out.push('-');
            canonical_type(param_effect, out);
            out.push('/');
            canonical_type(ret_effect, out);
            out.push_str("->");
            canonical_type(ret, out);
            out.push(')');
        }
        typed_ir::Type::Tuple(items) => canonical_type_list("(", ")", items, out),
        typed_ir::Type::Record(record) => {
            out.push('{');
            for field in &record.fields {
                out.push_str(&field.name.0);
                out.push(':');
                canonical_type(&field.value, out);
                out.push(',');
            }
            out.push('}');
        }
        typed_ir::Type::Variant(variant) => {
            out.push('[');
            for case in &variant.cases {
                out.push_str(&case.name.0);
                canonical_type_list("(", ")", &case.payloads, out);
                out.push(',');
            }
            out.push(']');
        }
        typed_ir::Type::Row { items, tail } => {
            canonical_type_list("[", "]", items, out);
            out.push('|');
            canonical_type(tail, out);
        }
        typed_ir::Type::Union(items) => canonical_type_list("union(", ")", items, out),
        typed_ir::Type::Inter(items) => canonical_type_list("inter(", ")", items, out),
        typed_ir::Type::Recursive { var, body } => {
            out.push_str("rec ");
            out.push_str(&var.0);
            out.push('.');
            canonical_type(body, out);
        }
    }
}

fn canonical_type_arg(arg: &typed_ir::TypeArg, out: &mut String) {
    match arg {
        typed_ir::TypeArg::Type(ty) => canonical_type(ty, out),
        typed_ir::TypeArg::Bounds(bounds) => {
            out.push_str("bounds(");
            if let Some(lower) = bounds.lower.as_deref() {
                canonical_type(lower, out);
            }
            out.push_str("..");
            if let Some(upper) = bounds.upper.as_deref() {
                canonical_type(upper, out);
            }
            out.push(')');
        }
    }
}

fn canonical_type_list(open: &str, close: &str, items: &[typed_ir::Type], out: &mut String) {
    out.push_str(open);
    for (index, item) in items.iter().enumerate() {
        if index > 0 {
            out.push(',');
        }
        canonical_type(item, out);
    }
    out.push_str(close);
}