mod arch;
mod flow;
mod ir;

use crate::{
    arch::{
        Arch, LiftArch,
        arm::{Arm, ArmLiftCtx, ArmMode, DummyEnv},
    },
    ir::*,
};
use clap::{
    Parser,
    builder::{
        Styles,
        styling::{AnsiColor, Effects},
    },
};

const STYLES: Styles = Styles::styled()
    .header(AnsiColor::Green.on_default().effects(Effects::BOLD))
    .usage(AnsiColor::Green.on_default().effects(Effects::BOLD))
    .literal(AnsiColor::Cyan.on_default().effects(Effects::BOLD))
    .placeholder(AnsiColor::Cyan.on_default());

#[derive(Parser)]
#[command(name = "slonik", author)]
#[command(about = "an experimental decompiler")]
#[command(disable_version_flag = true, arg_required_else_help = true)]
#[command(styles=STYLES)]
struct Args {}

fn main() {
    let arm = Arm::default();

    let bytes: &[u8] = &[
        0x01, 0x00, 0xA0, 0xE3, // mov r0, #1
        0x02, 0x10, 0xA0, 0xE3, // mov r1, #2
        0x01, 0x00, 0x80, 0xE0, // add r0, r0, r1
        0x1E, 0xFF, 0x2F, 0xE1, // bx lr
    ];

    let mut body = crate::ir::Body::new();
    let mut fb_ctx = crate::ir::FrontendBuilderContext::new();
    let env = DummyEnv;

    {
        let mut fb = crate::ir::FrontendBuilder::new(&mut body, &mut fb_ctx);
        let entry = fb.create_block();
        fb.switch_to_block(entry);
        fb.seal_block(entry);

        let mut pc = 0x1000u64;
        let mut rest = bytes;

        let mut cx = ArmLiftCtx::new(&arm, &env, &mut fb, pc, ArmMode::Arm);

        while !rest.is_empty() {
            let (len, inst) = arm.decode(rest, ArmMode::Arm).unwrap();
            println!("{:#x}: {}", pc, arm.disasm(&inst, pc, ArmMode::Arm));
            println!("  flow: {:?}", arm.flow_info(&inst, pc, ArmMode::Arm));

            cx.pc = pc;
            arm.lift(&mut cx, &inst).unwrap();

            pc += len as u64;
            rest = &rest[len..];
        }
    }

    crate::ir::verify(&body).unwrap();
    println!("{body}");
}
