jaust 0.1.2

Java ecosystem tools in rust a learning project
Documentation
use super::attributes::AttStart;
use super::attributes::Attributes;

use crate::class_file::{bytecode::ByteCode, constant_pool::ConstantPool, file_reader::FileReader};
use anyhow::Result;

#[derive(Debug)]
pub struct CodeAttribute {
    attribute_name_index: u16,
    attribute_length: u32,
    max_stack: u16,
    max_locals: u16,
    code_length: u32,
    code: Vec<ByteCode>,
    exception_table: Vec<ExceptionTable>,
    attributes: Attributes,
}

#[derive(Debug)]
pub struct ExceptionTable {
    start_pc: u16,
    end_pc: u16,
    handler_pc: u16,
    catch_type: u16,
}

impl CodeAttribute {
    pub fn parse(
        file: &mut FileReader,
        att_start: &AttStart,
        cp: &ConstantPool,
    ) -> Result<CodeAttribute> {
        let max_stack = file.read_u2_to_u16()?;
        let max_locals = file.read_u2_to_u16()?;
        let code_length = file.read_u4_to_u32()?;

        let mut code = Vec::new();
        let mut curr_code = 0;
        while curr_code < code_length {
            let (byte_code, len) = ByteCode::parse(file)?;
            curr_code += len;
            code.push(byte_code);
        }

        let exception_table_length = file.read_u2_to_u16()?;
        let mut exception_table = Vec::new();
        for _i in 0..exception_table_length {
            let start_pc = file.read_u2_to_u16()?;
            let end_pc = file.read_u2_to_u16()?;
            let handler_pc = file.read_u2_to_u16()?;
            let catch_type = file.read_u2_to_u16()?;
            exception_table.push(ExceptionTable {
                start_pc,
                end_pc,
                handler_pc,
                catch_type,
            });
        }

        let attributes = Attributes::from(file, cp)?;

        Ok(CodeAttribute {
            attribute_name_index: att_start.attribute_name_index,
            attribute_length: att_start.attribute_length,
            max_stack,
            max_locals,
            code_length,
            code,
            exception_table,
            attributes,
        })
    }

    pub fn to_string(&self, cp: &ConstantPool) -> String {
        let mut s = String::new();
        s.push_str(&format!(
            "name {}\n",
            cp.get_to_string(self.attribute_name_index)
        ));
        s.push_str(&format!("length {}\n", self.attribute_length));

        s.push_str(&format!(
            "Code: max_stack: {}, max_locals: {}, code_length: {}\n",
            self.max_stack, self.max_locals, self.code_length
        ));

        s.push_str(&format!("Code: {}\n", self.code.len()));
        for c in &self.code {
            s.push_str(&format!("\t- {}\n", c.to_string()));
        }

        s.push_str(&format!(
            "  Exception table: {}\n",
            self.exception_table.len()
        ));
        for et in &self.exception_table {
            s.push_str(&format!(
                "\t- start_pc: {}, end_pc: {}, handler_pc: {}, catch_type: {}\n",
                et.start_pc, et.end_pc, et.handler_pc, et.catch_type
            ));
        }

        s.push_str(&self.attributes.to_string(cp));

        s
    }

    pub fn code(&self) -> &Vec<ByteCode> {
        &self.code
    }
}