gaia-assembler 0.1.1

Universal assembler framework for Gaia project
Documentation
//! Type mapping utilities for Gaia IR
//! 
//! This module provides utilities for mapping types to various backend formats,
//! with special handling for JVM types, type erasure, and generic bounds.

use super::GaiaType;
use std::collections::HashMap;

/// Type mapping context for type conversion
#[derive(Debug, Default)]
pub struct TypeMappingContext {
    /// Cache for resolved types to avoid redundant calculations
    type_cache: HashMap<String, GaiaType>,
    /// Generic type parameters and their bounds
    generic_bounds: HashMap<String, Vec<GaiaType>>,
    /// Type erasure information
    type_erasure_map: HashMap<String, String>,
}

impl TypeMappingContext {
    /// Create a new type mapping context
    pub fn new() -> Self {
        Self::default()
    }

    /// Add a generic type bound
    pub fn add_generic_bound(&mut self, type_param: &str, bound: GaiaType) {
        self.generic_bounds.entry(type_param.to_string())
            .or_default()
            .push(bound);
    }

    /// Add type erasure information
    pub fn add_type_erasure(&mut self, generic_type: &str, erased_type: &str) {
        self.type_erasure_map.insert(generic_type.to_string(), erased_type.to_string());
    }

    /// Get the erased type for a generic type
    pub fn get_erased_type(&self, generic_type: &str) -> Option<&String> {
        self.type_erasure_map.get(generic_type)
    }
}

/// Parse a type name string to GaiaType
/// 
/// Supports primitive types, reference types, array types, and generic types.
pub fn parse_type_name(type_name: &str, ctx: &mut TypeMappingContext) -> GaiaType {
    if let Some(gaia_type) = ctx.type_cache.get(type_name) {
        return gaia_type.clone();
    }

    let gaia_type = match type_name {
        "bool" => GaiaType::Bool,
        "byte" | "i8" => GaiaType::I8,
        "short" | "i16" => GaiaType::I16,
        "int" | "i32" => GaiaType::I32,
        "long" | "i64" => GaiaType::I64,
        "float" | "f32" => GaiaType::F32,
        "double" | "f64" => GaiaType::F64,
        "char" => GaiaType::U16,
        "void" => GaiaType::Void,
        
        "String" => GaiaType::String,
        "Object" => GaiaType::Object,
        
        s if s.starts_with('[') => {
            let element_type = &s[1..];
            let gaia_element_type = parse_type_name(element_type, ctx);
            GaiaType::Array(Box::new(gaia_element_type), 0)
        }
        
        s if s.contains('<') && s.contains('>') => {
            let (base_type, _type_params) = parse_generic_type(s);
            
            if let Some(erased_type) = ctx.get_erased_type(base_type) {
                GaiaType::Class(erased_type.clone())
            } else {
                GaiaType::Class(base_type.to_string())
            }
        }
        
        s => GaiaType::Class(s.to_string()),
    };

    ctx.type_cache.insert(type_name.to_string(), gaia_type.clone());
    gaia_type
}

/// Legacy alias for backward compatibility
pub fn map_uir_type_to_gaia_type(uir_type: &str, ctx: &mut TypeMappingContext) -> GaiaType {
    parse_type_name(uir_type, ctx)
}

/// Parse generic type string into base type and type parameters
fn parse_generic_type(generic_type: &str) -> (&str, Vec<&str>) {
    if let Some(idx) = generic_type.find('<') {
        let base_type = &generic_type[..idx];
        let params_str = &generic_type[idx+1..generic_type.len()-1];
        let type_params = params_str.split(',').map(|p| p.trim()).collect();
        (base_type, type_params)
    } else {
        (generic_type, Vec::new())
    }
}

/// Map GaiaType to JVM type descriptor
pub fn map_gaia_type_to_jvm_descriptor(ty: &GaiaType) -> String {
    match ty {
        GaiaType::Void => "V".to_string(),
        GaiaType::Bool => "Z".to_string(),
        GaiaType::I8 => "B".to_string(),
        GaiaType::U8 => "B".to_string(),
        GaiaType::I16 => "S".to_string(),
        GaiaType::U16 => "S".to_string(),
        GaiaType::I32 => "I".to_string(),
        GaiaType::U32 => "I".to_string(),
        GaiaType::I64 => "J".to_string(),
        GaiaType::U64 => "J".to_string(),
        GaiaType::F32 => "F".to_string(),
        GaiaType::F64 => "D".to_string(),
        GaiaType::String => "Ljava/lang/String;".to_string(),
        GaiaType::Class(name) => format!("L{};", name.replace('.', "/")),
        GaiaType::Array(inner, _) => format!("[{}", map_gaia_type_to_jvm_descriptor(inner)),
        GaiaType::Object => "Ljava/lang/Object;".to_string(),
        GaiaType::Interface(name) => format!("L{};", name.replace('.', "/")),
        _ => "Ljava/lang/Object;".to_string(),
    }
}

/// Check if two Gaia types are compatible
pub fn are_types_compatible(from: &GaiaType, to: &GaiaType) -> bool {
    match (from, to) {
        (f, t) if f == t => true,
        
        (GaiaType::I8, GaiaType::I16) => true,
        (GaiaType::I8, GaiaType::I32) => true,
        (GaiaType::I8, GaiaType::I64) => true,
        (GaiaType::I8, GaiaType::F32) => true,
        (GaiaType::I8, GaiaType::F64) => true,
        (GaiaType::U8, GaiaType::I16) => true,
        (GaiaType::U8, GaiaType::I32) => true,
        (GaiaType::U8, GaiaType::I64) => true,
        (GaiaType::U8, GaiaType::F32) => true,
        (GaiaType::U8, GaiaType::F64) => true,
        (GaiaType::I16, GaiaType::I32) => true,
        (GaiaType::I16, GaiaType::I64) => true,
        (GaiaType::I16, GaiaType::F32) => true,
        (GaiaType::I16, GaiaType::F64) => true,
        (GaiaType::U16, GaiaType::I32) => true,
        (GaiaType::U16, GaiaType::I64) => true,
        (GaiaType::U16, GaiaType::F32) => true,
        (GaiaType::U16, GaiaType::F64) => true,
        (GaiaType::I32, GaiaType::I64) => true,
        (GaiaType::I32, GaiaType::F32) => true,
        (GaiaType::I32, GaiaType::F64) => true,
        (GaiaType::U32, GaiaType::I64) => true,
        (GaiaType::U32, GaiaType::F32) => true,
        (GaiaType::U32, GaiaType::F64) => true,
        (GaiaType::I64, GaiaType::F64) => true,
        (GaiaType::U64, GaiaType::F64) => true,
        (GaiaType::F32, GaiaType::F64) => true,
        
        (GaiaType::String, GaiaType::Object) => true,
        (GaiaType::Class(_), GaiaType::Object) => true,
        (GaiaType::Interface(_), GaiaType::Object) => true,
        (GaiaType::Array(_, _), GaiaType::Object) => true,
        
        (GaiaType::Bool, GaiaType::Object) => true,
        (GaiaType::I8, GaiaType::Object) => true,
        (GaiaType::U8, GaiaType::Object) => true,
        (GaiaType::I16, GaiaType::Object) => true,
        (GaiaType::U16, GaiaType::Object) => true,
        (GaiaType::I32, GaiaType::Object) => true,
        (GaiaType::U32, GaiaType::Object) => true,
        (GaiaType::I64, GaiaType::Object) => true,
        (GaiaType::U64, GaiaType::Object) => true,
        (GaiaType::F32, GaiaType::Object) => true,
        (GaiaType::F64, GaiaType::Object) => true,
        
        (GaiaType::Array(f_inner, _), GaiaType::Array(t_inner, _)) => {
            are_types_compatible(f_inner, t_inner)
        },
        
        (GaiaType::Any, GaiaType::Object) => true,
        
        _ => false,
    }
}

/// Get the common super type of two Gaia types
pub fn get_common_super_type(a: &GaiaType, b: &GaiaType) -> Option<GaiaType> {
    if are_types_compatible(a, b) {
        return Some(b.clone());
    }
    if are_types_compatible(b, a) {
        return Some(a.clone());
    }
    
    match (a, b) {
        (GaiaType::String, _) | (_, GaiaType::String) => Some(GaiaType::Object),
        (GaiaType::Class(_), _) | (_, GaiaType::Class(_)) => Some(GaiaType::Object),
        (GaiaType::Interface(_), _) | (_, GaiaType::Interface(_)) => Some(GaiaType::Object),
        (GaiaType::Array(_, _), _) | (_, GaiaType::Array(_, _)) => Some(GaiaType::Object),
        _ => None,
    }
}