use super::config::*;
use super::instruction::*;
use super::operand::*;
use crate::error::*;
use crate::utils::*;
pub trait Formatter: Sized {
fn format(
&mut self,
output: &mut impl FormatterOutput,
config: &Config,
instr: &Instruction,
) -> Result<()> {
instr.format(self, output, config)
}
fn format_mnemonic(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
) -> Result<()>;
fn format_punctuation(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
punctuation: FormatterTextKind,
) -> Result<()>;
fn format_operand(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
index: usize,
) -> Result<()>;
fn format_u32(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: u32,
) -> Result<()>;
fn format_i32(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: i32,
) -> Result<()>;
fn format_u64(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: u64,
) -> Result<()>;
fn format_i64(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: i64,
) -> Result<()>;
fn format_text(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
text: &str,
) -> Result<()>;
}
pub trait FormatterOutput {
fn write(&mut self, src: impl AsRef<str>) -> Result<()>;
}
pub enum FormatterTextKind {
Space,
Comma,
Dot,
NumSign,
Minus,
BracketLeft,
BracketRight,
ExclamationMark,
}
pub struct Fmt {}
impl Formatter for Fmt {
#[allow(unused)]
fn format_mnemonic(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
) -> Result<()> {
output.write(instr.mnemonic.as_str())?;
Ok(())
}
#[allow(unused)]
fn format_punctuation(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
punctuation: FormatterTextKind,
) -> Result<()> {
match punctuation {
FormatterTextKind::Space => output.write(" ")?,
FormatterTextKind::Comma => output.write(", ")?,
FormatterTextKind::Dot => output.write(".")?,
FormatterTextKind::NumSign => output.write("#")?,
FormatterTextKind::Minus => output.write("-")?,
FormatterTextKind::BracketLeft => output.write("[")?,
FormatterTextKind::BracketRight => output.write("]")?,
FormatterTextKind::ExclamationMark => output.write("!")?,
}
Ok(())
}
#[allow(unused)]
fn format_operand(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
index: usize,
) -> Result<()> {
let op = instr.operands[index];
match op {
Operand::Register(register) => output.write(register.as_str())?,
Operand::UnsignedImmediate(imm) => {
self.format_u32(output, global_config, instr_config, instr, imm)?
}
Operand::UnsignedImmediate64(imm) => {
self.format_u64(output, global_config, instr_config, instr, imm)?
}
Operand::SignedImmediate(imm) => {
self.format_i32(output, global_config, instr_config, instr, imm)?
}
Operand::SignedImmediate64(imm) => {
self.format_i64(output, global_config, instr_config, instr, imm)?
}
Operand::ExtensionWrapper(ExtensionWrapper::CantOmit(extension)) => {
output.write(extension.as_str())?;
output.write(" ")?;
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(
output,
global_config,
instr_config,
instr,
extension.value(),
)?;
}
Operand::ExtensionWrapper(ExtensionWrapper::CanOmit(extension))
| Operand::Extension(extension) => match extension {
Extension::Uxtb(value)
| Extension::Uxth(value)
| Extension::Uxtw(value)
| Extension::Uxtx(value)
| Extension::Sxtb(value)
| Extension::Sxth(value)
| Extension::Sxtw(value)
| Extension::Sxtx(value) => {
output.write(extension.as_str())?;
if value != 0 {
output.write(" ")?;
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(
output,
global_config,
instr_config,
instr,
extension.value(),
)?;
}
}
_ => {
output.write(extension.as_str())?;
output.write(" ")?;
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(
output,
global_config,
instr_config,
instr,
extension.value(),
)?;
}
},
Operand::Label(label) => {
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_i64(output, global_config, instr_config, instr, label.value())?
}
Operand::Bitmask(n, imms, immr, aarch32) => {
if aarch32 {
self.format_i32(
output,
global_config,
instr_config,
instr,
bitmask_decode::<32>(n, imms, immr).0 as i32,
)?
} else {
self.format_i64(
output,
global_config,
instr_config,
instr,
bitmask_decode::<64>(n, imms, immr).0 as i64,
)?
}
}
Operand::Condition(cond) => {
output.write(cond.as_str())?;
}
Operand::PrefetchOp(op) => match op {
PrefetchOp::PLDKEEP => output.write("pldkeep")?,
PrefetchOp::PSTKEEP => output.write("pstkeep")?,
PrefetchOp::PLDSTRM => output.write("pldstrm")?,
PrefetchOp::PSTSTRM => output.write("pststrm")?,
PrefetchOp::PLDL1KEEP => output.write("pldl1keep")?,
PrefetchOp::PLDL1STRM => output.write("pldl1strm")?,
PrefetchOp::PLDL2KEEP => output.write("pldl2keep")?,
PrefetchOp::PLDL2STRM => output.write("pldl2strm")?,
PrefetchOp::PLDL3KEEP => output.write("pldl3keep")?,
PrefetchOp::PLDL3STRM => output.write("pldl3strm")?,
PrefetchOp::PLDSLCKEEP => output.write("pldslckeep")?,
PrefetchOp::PLDSLCSTRM => output.write("pldslcstrm")?,
PrefetchOp::PLIL1KEEP => output.write("plil1keep")?,
PrefetchOp::PLIL1STRM => output.write("plil1strm")?,
PrefetchOp::PLIL2KEEP => output.write("plil2keep")?,
PrefetchOp::PLIL2STRM => output.write("plil2strm")?,
PrefetchOp::PLIL3KEEP => output.write("plil3keep")?,
PrefetchOp::PLIL3STRM => output.write("plil3strm")?,
PrefetchOp::PLISLCKEEP => output.write("plislckeep")?,
PrefetchOp::PLISLCSTRM => output.write("plislcstrm")?,
PrefetchOp::PSTL1KEEP => output.write("pstl1keep")?,
PrefetchOp::PSTL1STRM => output.write("pstl1strm")?,
PrefetchOp::PSTL2KEEP => output.write("pstl2keep")?,
PrefetchOp::PSTL2STRM => output.write("pstl2strm")?,
PrefetchOp::PSTL3KEEP => output.write("pstl3keep")?,
PrefetchOp::PSTL3STRM => output.write("pstl3strm")?,
PrefetchOp::PSTSLCKEEP => output.write("pstslckeep")?,
PrefetchOp::PSTSLCSTRM => output.write("pstslcstrm")?,
PrefetchOp::IR => output.write("ir")?,
PrefetchOp::Other(imm) => {
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(output, global_config, instr_config, instr, imm)?;
}
},
_ => todo!("{:#?}", op),
}
Ok(())
}
#[allow(unused)]
fn format_u32(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: u32,
) -> Result<()> {
match instr_config
.syntax()
.get_positive_integer_format(&global_config.syntax)
{
FormatInteger::HexadecimalUnsigned | FormatInteger::HexadecimalSigned => {
output.write(format!("{:#x}", value))?
}
FormatInteger::DecimalUnsigned | FormatInteger::DecimalSigned => {
output.write(format!("{}", value))?
}
}
Ok(())
}
#[allow(unused)]
fn format_i32(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: i32,
) -> Result<()> {
if value >= 0 {
self.format_u32(output, global_config, instr_config, instr, value as u32)?;
} else {
match instr_config
.syntax()
.get_negative_integer_format(&global_config.syntax)
{
FormatInteger::HexadecimalUnsigned => {
output.write(format!("{:#x}", value as u32))?
}
FormatInteger::HexadecimalSigned => output.write(format!("{:#x}", value))?,
FormatInteger::DecimalUnsigned => output.write(format!("{}", value as u32))?,
FormatInteger::DecimalSigned => output.write(format!("{}", value))?,
}
}
Ok(())
}
#[allow(unused)]
fn format_u64(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: u64,
) -> Result<()> {
match instr_config
.syntax()
.get_positive_integer_format(&global_config.syntax)
{
FormatInteger::HexadecimalUnsigned | FormatInteger::HexadecimalSigned => {
output.write(format!("{:#x}", value))?
}
FormatInteger::DecimalUnsigned | FormatInteger::DecimalSigned => {
output.write(format!("{}", value))?
}
}
Ok(())
}
#[allow(unused)]
fn format_i64(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: i64,
) -> Result<()> {
if value >= 0 {
self.format_u64(output, global_config, instr_config, instr, value as u64)?;
} else {
match instr_config
.syntax()
.get_negative_integer_format(&global_config.syntax)
{
FormatInteger::HexadecimalUnsigned => {
output.write(format!("{:#x}", value as u64))?
}
FormatInteger::HexadecimalSigned => output.write(format!("{:#x}", value))?,
FormatInteger::DecimalUnsigned => output.write(format!("{}", value as u64))?,
FormatInteger::DecimalSigned => output.write(format!("{}", value))?,
}
}
Ok(())
}
#[allow(unused)]
fn format_text(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
text: &str,
) -> Result<()> {
output.write(text)?;
Ok(())
}
}
impl FormatterOutput for String {
fn write(&mut self, src: impl AsRef<str>) -> Result<()> {
self.push_str(src.as_ref());
Ok(())
}
}