use super::config::*;
use super::instruction::*;
use super::operand::*;
use crate::error::*;
pub trait Formatter: Sized {
fn format(
&mut self,
output: &mut impl FormatterOutput,
config: &Config,
instr: &Instruction,
) -> Result<()> {
instr.format(self, output, config)
}
#[allow(unused)]
fn format_mnemonic(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
) -> Result<()>;
#[allow(unused)]
fn format_condition(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
) -> Result<()>;
#[allow(unused)]
fn format_qualifier(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
qualifier: FormatterQualifier,
multiwidth: bool,
fixed: bool,
) -> Result<()>;
#[allow(unused)]
fn format_suffix(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
suffix: FormatterSuffix,
) -> Result<()>;
#[allow(unused)]
fn format_punctuation(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
punctuation: FormatterTextKind,
) -> Result<()>;
#[allow(unused)]
fn format_operand(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
index: usize,
) -> Result<()>;
#[allow(unused)]
fn format_enclosed_operand(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
index: usize,
) -> Result<()>;
#[allow(unused)]
fn format_u32(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: u32,
) -> Result<()>;
#[allow(unused)]
fn format_i32(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: i32,
) -> Result<()>;
#[allow(unused)]
fn format_u64(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: u64,
) -> Result<()>;
#[allow(unused)]
fn format_i64(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
value: i64,
) -> Result<()>;
#[allow(unused)]
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,
Hat,
Comma,
NumSign,
Dot,
ExclamationMark,
BracketLeft,
BracketRight,
CurlyBracketLeft,
CurlyBracketRight,
}
pub enum FormatterQualifier {
None,
Narrow,
Wide,
}
pub enum FormatterSuffix {
Ia,
}
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_condition(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
) -> Result<()> {
Ok(())
}
#[allow(unused)]
fn format_qualifier(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
qualifier: FormatterQualifier,
multiwidth: bool,
fixed: bool,
) -> Result<()> {
let qualifier_config = instr_config.qualifier().unwrap_or(global_config.qualifier);
Ok(match qualifier_config {
FormatQualifier::Always => output.write(".w")?,
FormatQualifier::WideOnly => match qualifier {
FormatterQualifier::None => {}
FormatterQualifier::Narrow => {}
FormatterQualifier::Wide => output.write(".w")?,
},
FormatQualifier::Recommended => {
if fixed || multiwidth {
match qualifier {
FormatterQualifier::None => {}
FormatterQualifier::Narrow => {}
FormatterQualifier::Wide => output.write(".w")?,
}
}
}
FormatQualifier::Never => {}
})
}
#[allow(unused)]
fn format_suffix(
&mut self,
output: &mut impl FormatterOutput,
global_config: &ConfigGlobal,
instr_config: &impl HasConfigInstruction,
instr: &Instruction,
suffix: FormatterSuffix,
) -> Result<()> {
match suffix {
FormatterSuffix::Ia => output.write("ia"),
}
}
#[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::Hat => output.write(" ^")?,
FormatterTextKind::Comma => output.write(", ")?,
FormatterTextKind::Dot => output.write(".")?,
FormatterTextKind::NumSign => output.write("#")?,
FormatterTextKind::ExclamationMark => output.write("!")?,
FormatterTextKind::BracketLeft => output.write("[")?,
FormatterTextKind::BracketRight => output.write("]")?,
FormatterTextKind::CurlyBracketLeft => output.write("{")?,
FormatterTextKind::CurlyBracketRight => 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::MnemonicCondition(cond) => match cond {
MnemonicCondition::Al => output.write("")?,
_ => output.write(cond.as_str())?,
},
Operand::Register(register) => output.write(register.as_str())?,
Operand::RegisterList(list) => {
let mut s = String::new();
for i in 0..16 {
if (list.0 >> i) & 1 == 1 {
if !s.is_empty() {
s.push_str(", ");
}
s.push_str(Register::decode(i).unwrap().as_str());
}
}
output.write(format!("{{{}}}", s))?
}
Operand::UnsignedImmediate(imm) => {
self.format_u32(output, global_config, instr_config, instr, imm)?
}
Operand::SignedImmediate(imm) => {
self.format_i32(output, global_config, instr_config, instr, imm)?
}
Operand::ModifiedImmediate(imm) => {
if imm.0 == 0 {
self.format_u32(output, global_config, instr_config, instr, imm.1)?;
} else if imm.1 == 0 {
self.format_u32(output, global_config, instr_config, instr, imm.1)?;
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::Comma,
)?;
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(output, global_config, instr_config, instr, imm.0 * 2)?;
} else {
self.format_i32(
output,
global_config,
instr_config,
instr,
imm.1.rotate_right(imm.0 * 2) as i32,
)?;
}
}
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::Shift(shift) => {
output.write(shift.as_str())?;
if let Shift::RRX = shift {
return Ok(());
}
if shift.value() != 0 {
output.write(" ")?;
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(output, global_config, instr_config, instr, shift.value())?;
}
}
Operand::ShiftType(shift) => {
output.write(shift.as_str())?;
}
Operand::Iflags(iflags) => {
let mut count = 0;
if iflags.a {
output.write("a")?;
count += 1;
}
if iflags.i {
output.write("i")?;
count += 1;
}
if iflags.f {
output.write("f")?;
count += 1;
}
if count == 0 {
output.write("none")?;
}
}
Operand::BarrierOperation(BarrierOperation::Reserved(barrier_op)) => {
self.format_punctuation(
output,
global_config,
instr_config,
instr,
FormatterTextKind::NumSign,
)?;
self.format_u32(
output,
global_config,
instr_config,
instr,
barrier_op as u32,
)?;
}
Operand::BarrierOperation(barrier_op) => output.write(barrier_op.as_str())?,
Operand::PlusMinus(pm) => match pm {
PlusMinus::Minus => output.write("-")?,
_ => {}
},
Operand::WriteBack(wb) => match wb {
WriteBack::True => output.write("!")?,
_ => {}
},
Operand::AddressMode(am) => match am {
AddressMode::IncrementAfter => output.write("")?,
_ => output.write(am.as_str())?,
},
Operand::SysRegEncodingSpace(es) => output.write(es.as_str())?,
Operand::SysRegRegister(register) => output.write(register.as_str())?,
Operand::ApsrNzcv => output.write("apsr_nzcv")?,
Operand::SpecialRegister(spreg) => match instr_config
.syntax()
.get_special_register_format(&global_config.syntax)
{
FormatSpecialRegister::Lowercase => output.write(spreg.as_str().to_lowercase())?,
FormatSpecialRegister::Recommended => output.write(spreg.as_str())?,
FormatSpecialRegister::Uppercase => output.write(spreg.as_str().to_uppercase())?,
},
Operand::BankedRegister(breg) => output.write(breg.as_str())?,
Operand::Endianness(en) => output.write(en.as_str())?,
_ => todo!("{:#?}", op),
}
Ok(())
}
#[allow(unused)]
fn format_enclosed_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::UnsignedImmediate(imm) => {
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(())
}
}