b2c2-stat 0.1.5

デバッグ用にところどころで使ってるぽい
Documentation
// b2c2-stat crate
// author: Leonardone @ NEETSDKASU

use b2c2_casl2::*;
use std::collections::{BTreeMap, HashMap};

pub fn analyze(statements: &[Statement]) -> String {
    let mut comment_lines: usize = 0;
    let mut with_comment_lines: usize = 0;
    let mut labels = HashMap::<String, usize>::new();
    let mut commands = HashMap::<String, usize>::new();
    let mut total_ds_size: usize = 0;
    let mut total_dc_size: usize = 0;
    let mut total_dc_item_count: usize = 0;
    let mut registers = vec![0_usize; 8];
    let mut index_registers = vec![0_usize; 8];
    let mut literals = HashMap::<String, usize>::new();
    let mut r_codes = HashMap::<String, usize>::new();
    let mut a_codes = HashMap::<String, usize>::new();
    let mut p_codes = HashMap::<String, usize>::new();
    let mut name: String = String::new();

    for stmt in statements.iter() {
        match stmt {
            Statement::Comment { .. } => {
                comment_lines += 1;
            }
            Statement::Code {
                label,
                command,
                comment,
            } => {
                if comment.is_some() {
                    with_comment_lines += 1;
                }
                if let Some(label) = label {
                    let key = label.as_str().to_string();
                    labels.entry(key).or_insert(0);
                }
                match command {
                    Command::Start { entry_point } => {
                        if let Some(label) = label {
                            name.push_str(label.as_str());
                        }
                        if let Some(label) = entry_point {
                            let key = label.as_str().to_string();
                            *labels.entry(key).or_insert(0) += 1;
                        }
                        *commands.entry("START".to_string()).or_insert(0) += 1;
                    }
                    Command::End => *commands.entry("END".to_string()).or_insert(0) += 1,
                    Command::Ds { size } => {
                        total_ds_size += *size as usize;
                        *commands.entry("DS".to_string()).or_insert(0) += 1;
                    }
                    Command::Dc { constants } => {
                        total_dc_item_count += constants.len();
                        total_dc_size += constants.len();
                        for cnst in constants.iter() {
                            match cnst {
                                Constant::Label(label) => {
                                    let key = label.as_str().to_string();
                                    *labels.entry(key).or_insert(0) += 1;
                                }
                                Constant::Str(s) => {
                                    total_dc_size += s.chars().count();
                                    total_dc_size -= 1;
                                }
                                _ => {}
                            }
                        }
                        *commands.entry("DC".to_string()).or_insert(0) += 1;
                    }
                    Command::In { pos, len } => {
                        *labels.entry(pos.as_str().to_string()).or_insert(0) += 1;
                        *labels.entry(len.as_str().to_string()).or_insert(0) += 1;
                        *commands.entry("IN".to_string()).or_insert(0) += 1;
                    }
                    Command::Out { pos, len } => {
                        *labels.entry(pos.as_str().to_string()).or_insert(0) += 1;
                        *labels.entry(len.as_str().to_string()).or_insert(0) += 1;
                        *commands.entry("OUT".to_string()).or_insert(0) += 1;
                    }
                    Command::Rpush => *commands.entry("RPUSH".to_string()).or_insert(0) += 1,
                    Command::Rpop => *commands.entry("RPOP".to_string()).or_insert(0) += 1,
                    Command::R { code, r1, r2 } => {
                        registers[*r1 as usize] += 1;
                        registers[*r2 as usize] += 1;
                        use R::*;
                        let s = match code {
                            Ld => "LD",
                            Adda => "ADDA",
                            Addl => "ADDL",
                            Suba => "SUBA",
                            Subl => "SUBL",
                            And => "AND",
                            Or => "OR",
                            Xor => "XOR",
                            Cpa => "CPA",
                            Cpl => "CPL",
                        };
                        *r_codes.entry(s.to_string()).or_insert(0) += 1;
                    }
                    Command::A { code, r, adr, x } => {
                        registers[*r as usize] += 1;
                        if let Some(reg) = x {
                            index_registers[*reg as usize] += 1;
                        }
                        if let Adr::Label(label) = adr {
                            let key = label.as_str().to_string();
                            *labels.entry(key).or_insert(0) += 1;
                        } else if matches!(
                            adr,
                            Adr::LiteralDec(_) | Adr::LiteralHex(_) | Adr::LiteralStr(_)
                        ) {
                            *literals.entry(adr.to_string()).or_insert(0) += 1;
                        }
                        use A::*;
                        let s = match code {
                            Ld => "LD",
                            St => "ST",
                            Lad => "LAD",
                            Adda => "ADDA",
                            Addl => "ADDL",
                            Suba => "SUBA",
                            Subl => "SUBL",
                            And => "AND",
                            Or => "OR",
                            Xor => "XOR",
                            Cpa => "CPA",
                            Cpl => "CPL",
                            Sla => "SLA",
                            Sra => "SRA",
                            Sll => "SLL",
                            Srl => "SRL",
                        };
                        *a_codes.entry(s.to_string()).or_insert(0) += 1;
                    }
                    Command::P { code, adr, x } => {
                        if let Some(reg) = x {
                            index_registers[*reg as usize] += 1;
                        }
                        if let Adr::Label(label) = adr {
                            let key = label.as_str().to_string();
                            *labels.entry(key).or_insert(0) += 1;
                        } else if matches!(
                            adr,
                            Adr::LiteralDec(_) | Adr::LiteralHex(_) | Adr::LiteralStr(_)
                        ) {
                            *literals.entry(adr.to_string()).or_insert(0) += 1;
                        }
                        use P::*;
                        let s = match code {
                            Jpl => "JPL",
                            Jmi => "JMI",
                            Jnz => "JNZ",
                            Jze => "JZE",
                            Jov => "JOV",
                            Jump => "JUMP",
                            Push => "PUSH",
                            Call => "CALL",
                            Svc => "SVC",
                        };
                        *p_codes.entry(s.to_string()).or_insert(0) += 1;
                    }
                    Command::Pop { r } => {
                        registers[*r as usize] += 1;
                        *commands.entry("POP".to_string()).or_insert(0) += 1;
                    }
                    Command::Ret => *commands.entry("RET".to_string()).or_insert(0) += 1,
                    Command::Nop => *commands.entry("NOP".to_string()).or_insert(0) += 1,
                    Command::DebugBasicStep { .. } => {}
                }
            }
        }
    }
    format!(
        r#"
STATISTICS

name: {name}

lines: {lines}
    comment: {comments}
    code: {codes}
        with_comment: {with_comment}

total_ds_size: {total_ds_size}

total_dc_item_count: {total_dc_item_count}
total_dc_size: {total_dc_size}

labels:
    total: {total_label}
    unused: {unused_label}
    {labels}

registers:
    [GR0,GR1,GR2,GR3,GR4,GR5,GR6,GR7]
    {registers}

index registers:
    [---,GR1,GR2,GR3,GR4,GR5,GR6,GR7]
    {index_registers}

literals:
    {literals}

commands:
    {commands}
    {p_codes}

commands(r1,r2):
    {r_codes}

commands(r,adr,x):
    {a_codes}

"#,
        name = name,
        lines = statements.len(),
        comments = comment_lines,
        codes = statements.len() - comment_lines,
        with_comment = with_comment_lines,
        labels = format_args!("{:?}", labels.iter().collect::<BTreeMap<_, _>>()),
        total_label = labels.len(),
        unused_label = labels.iter().filter(|(_, c)| **c == 0).count(),
        commands = format_args!("{:?}", commands.iter().collect::<BTreeMap<_, _>>()),
        p_codes = format_args!("{:?}", p_codes.iter().collect::<BTreeMap<_, _>>()),
        total_ds_size = total_ds_size,
        total_dc_item_count = total_dc_item_count,
        total_dc_size = total_dc_size,
        registers = format_args!("{:?}", registers),
        index_registers = format_args!("{:?}", index_registers),
        literals = format_args!("{:?}", literals.iter().collect::<BTreeMap<_, _>>()),
        r_codes = format_args!("{:?}", r_codes.iter().collect::<BTreeMap<_, _>>()),
        a_codes = format_args!("{:?}", a_codes.iter().collect::<BTreeMap<_, _>>())
    )
}