rusty-javac 0.2.3

A Java compiler written in Rust.
Documentation
use crate::ty::Ty;
use crate::ty::method_sig::MethodSig;
use ustr::Ustr;

pub fn field_descriptor(ty: &Ty) -> String {
    ty.erasure().descriptor()
}

pub fn method_descriptor(sig: &MethodSig) -> String {
    sig.descriptor()
}

pub fn class_descriptor(class_name: &str) -> String {
    format!("L{};", class_name.replace('.', "/"))
}

pub fn descriptor_to_ty(desc: &str) -> Option<Ty> {
    let chars = desc.chars().collect::<Vec<_>>();
    if chars.is_empty() {
        return None;
    }
    let (ty, _) = parse_type(&chars, 0)?;
    Some(ty)
}

pub fn method_descriptor_to_sig(name: &str, desc: &str) -> Option<MethodSig> {
    let chars = desc.chars().collect::<Vec<_>>();
    if chars.first().copied()? != '(' {
        return None;
    }

    let mut params = Vec::new();
    let mut pos = 1;
    while chars.get(pos).copied()? != ')' {
        let (param, next) = parse_type(&chars, pos)?;
        params.push(param);
        pos = next;
    }

    let (return_type, end) = parse_type(&chars, pos + 1)?;
    (end == chars.len()).then(|| MethodSig::new(Ustr::from(name), params, return_type))
}

fn parse_type(chars: &[char], pos: usize) -> Option<(Ty, usize)> {
    if pos >= chars.len() {
        return None;
    }
    match chars[pos] {
        'V' => Some((Ty::Void, pos + 1)),
        'Z' => Some((Ty::Boolean, pos + 1)),
        'B' => Some((Ty::Byte, pos + 1)),
        'C' => Some((Ty::Char, pos + 1)),
        'S' => Some((Ty::Short, pos + 1)),
        'I' => Some((Ty::Int, pos + 1)),
        'J' => Some((Ty::Long, pos + 1)),
        'F' => Some((Ty::Float, pos + 1)),
        'D' => Some((Ty::Double, pos + 1)),
        'L' => {
            let end = chars.iter().skip(pos + 1).position(|&c| c == ';')?;
            let name: String = chars[pos + 1..pos + 1 + end].iter().collect();
            Some((Ty::Class(ustr::Ustr::from(&name)), pos + 1 + end + 1))
        }
        '[' => {
            let (elem, next) = parse_type(chars, pos + 1)?;
            Some((Ty::Array(Box::new(elem)), next))
        }
        _ => None,
    }
}