use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, ToTokens};
use super::{Disassembler, ToLiteral, WorkType, DISPLAY_WORK_TYPE};
use crate::{NonZeroTypeU, NumberSuperSigned};
#[derive(Debug, Clone)]
pub struct VarMeaning {
id: sleigh_rs::AttachVarnodeId,
pub display_func: Ident,
pub value_func: Ident,
pub index_type: WorkType,
pub varnode_bytes: NonZeroTypeU,
}
impl VarMeaning {
pub fn new(
sleigh: &sleigh_rs::Sleigh,
id: sleigh_rs::AttachVarnodeId,
attach: &sleigh_rs::meaning::AttachVarnode,
fun_count: usize,
) -> Self {
let index_max = attach
.0
.iter()
.map(|(index, _varnode)| *index)
.max()
.unwrap();
let index_bits = (usize::BITS - index_max.leading_zeros()) + 1;
let index_type = WorkType::new_int_bits(index_bits, false);
let varnode_bytes = attach
.0
.first()
.map(|(_index, varnode)| sleigh.varnode(*varnode).len_bytes)
.unwrap();
Self {
display_func: format_ident!("meaning_{}_display", fun_count),
value_func: format_ident!("meaning_{}_value", fun_count),
index_type,
varnode_bytes,
id,
}
}
pub fn to_tokens(
&self,
tokens: &mut TokenStream,
disassembler: &Disassembler,
) {
let Self {
id,
display_func,
value_func,
index_type,
varnode_bytes: _,
} = self;
let sleigh = disassembler.sleigh.attach_varnode(*id);
let display_element = &disassembler.display.name;
let ele_index = sleigh.0.iter().map(|(i, _v)| i.unsuffixed());
let ele_value = sleigh.0.iter().map(|(_i, v)| {
let regs = disassembler.registers.name();
let variant = disassembler.registers.register(*v);
quote! { #regs::#variant }
});
let registers_enum = disassembler.registers.name();
tokens.extend(quote! {
fn #value_func<T>(num: T) -> #registers_enum
where
#index_type: TryFrom<T>,
<#index_type as TryFrom<T>>::Error: core::fmt::Debug,
{
match #index_type::try_from(num).unwrap() {
#(#ele_index => #ele_value,)*
_ => unreachable!("Invalid Attach Value"),
}
}
fn #display_func<T>(num: T) -> #display_element
where
#index_type: TryFrom<T>,
<#index_type as TryFrom<T>>::Error: core::fmt::Debug,
{
let value = #value_func(num.try_into().unwrap());
<#display_element>::Register(value)
}
});
}
}
#[derive(Debug, Clone)]
pub struct NameMeaning {
id: sleigh_rs::AttachLiteralId,
pub display_func: Ident,
pub index_type: WorkType,
}
impl NameMeaning {
pub fn new(
id: sleigh_rs::AttachLiteralId,
attach: &sleigh_rs::meaning::AttachLiteral,
fun_count: usize,
) -> Self {
let index_max = attach
.0
.iter()
.map(|(index, _varnode)| *index)
.max()
.unwrap();
let index_bits = (usize::BITS - index_max.leading_zeros()) + 1;
let index_type = WorkType::new_int_bits(index_bits, false);
Self {
id,
display_func: format_ident!("meaning_{}_display", fun_count),
index_type,
}
}
pub fn to_tokens(
&self,
tokens: &mut TokenStream,
disassembler: &Disassembler,
) {
let param_type = &self.index_type;
let display_element = &disassembler.display.name;
let attach = disassembler.sleigh.attach_literal(self.id);
let ele_index = attach.0.iter().map(|(i, _v)| i.unsuffixed());
let ele_value = attach.0.iter().map(|(_i, v)| v);
let display_func = &self.display_func;
let index_type = &self.index_type;
tokens.extend(quote! {
fn #display_func<T>(num: T) -> #display_element
where
#param_type: TryFrom<T>,
<#param_type as TryFrom<T>>::Error: core::fmt::Debug,
{
match #index_type::try_from(num).unwrap() {
#(#ele_index => <#display_element>::Literal(#ele_value),)*
_ => unreachable!("Invalid Attach Value"),
}
}
});
}
}
#[derive(Debug, Clone)]
pub struct ValueMeaning {
id: sleigh_rs::AttachNumberId,
pub display_func: Ident,
pub value_func: Ident,
pub index_type: WorkType,
pub value_type: WorkType,
}
impl ValueMeaning {
pub fn new(
id: sleigh_rs::AttachNumberId,
attach: &sleigh_rs::meaning::AttachNumber,
fun_count: usize,
) -> Self {
let index_max = attach
.0
.iter()
.map(|(index, _varnode)| *index)
.max()
.unwrap();
let index_bits = (usize::BITS - index_max.leading_zeros()) + 1;
let index_type = WorkType::new_int_bits(index_bits, false);
let (min, max) = attach.0.iter().map(|(_i, value)| *value).fold(
(0, 0),
|(min, max), value| {
let min = min.min(value.signed_super());
let max = max.max(value.signed_super());
(min, max)
},
);
let mut value_bits =
NumberSuperSigned::BITS - min.abs().max(max.abs()).leading_zeros();
let signed = min.is_negative();
if min.is_negative() {
value_bits += 1;
}
let value_type = WorkType::new_int_bits(value_bits, signed);
Self {
id,
display_func: format_ident!("meaning_{}_display", fun_count),
value_func: format_ident!("meaning_{}_value", fun_count),
index_type,
value_type,
}
}
pub fn to_tokens(
&self,
tokens: &mut TokenStream,
disassembler: &Disassembler,
) {
let param_type = &self.index_type;
let display_element = &disassembler.display.name;
let sleigh = disassembler.sleigh.attach_number(self.id);
let ele_index = sleigh.0.iter().map(|(i, _v)| i.unsuffixed());
let ele_value =
sleigh.0.iter().map(|(_i, v)| v.signed_super().unsuffixed());
let display_func = &self.display_func;
let value_func = &self.value_func;
let value_type = &self.value_type;
let index_type = &self.index_type;
let number_ele = &disassembler.display.number_var;
let into_display = if value_type.is_signed() {
quote! {
<#display_element>::#number_ele(hex, value.is_negative(), value.abs() as #DISPLAY_WORK_TYPE)
}
} else {
quote! {
<#display_element>::#number_ele(hex, false, value as #DISPLAY_WORK_TYPE)
}
};
tokens.extend(quote! {
fn #value_func<T>(num: T) -> #value_type
where
#param_type: TryFrom<T>,
<#param_type as TryFrom<T>>::Error: core::fmt::Debug,
{
match #index_type::try_from(num).unwrap() {
#(#ele_index => #ele_value,)*
_ => unreachable!("Invalid Attach Value"),
}
}
fn #display_func<T>(hex: bool, num: T) -> #display_element
where
#param_type: TryFrom<T>,
<#param_type as TryFrom<T>>::Error: core::fmt::Debug,
{
let value = #value_func(num);
#into_display
}
});
}
}
#[derive(Debug, Clone)]
pub struct Meanings {
pub vars: Vec<VarMeaning>,
pub names: Vec<NameMeaning>,
pub values: Vec<ValueMeaning>,
}
impl Meanings {
pub fn new(sleigh: &sleigh_rs::Sleigh) -> Self {
let mut counter = 0usize;
let mut counter_value = || {
let value = counter;
counter += 1;
value
};
let vars = sleigh
.attach_varnodes()
.iter()
.enumerate()
.map(|(i, var)| {
VarMeaning::new(
sleigh,
sleigh_rs::AttachVarnodeId(i),
var,
counter_value(),
)
})
.collect();
let names = sleigh
.attach_literals()
.iter()
.enumerate()
.map(|(i, var)| {
NameMeaning::new(
sleigh_rs::AttachLiteralId(i),
var,
counter_value(),
)
})
.collect();
let values = sleigh
.attach_numbers()
.iter()
.enumerate()
.map(|(i, var)| {
ValueMeaning::new(
sleigh_rs::AttachNumberId(i),
var,
counter_value(),
)
})
.collect();
Self {
vars,
names,
values,
}
}
pub fn display_function_call(
&self,
len_bits: u32,
value: impl ToTokens,
meaning: sleigh_rs::meaning::Meaning,
) -> TokenStream {
use sleigh_rs::meaning::Meaning;
match meaning {
Meaning::NoAttach(print_fmt) => {
let hex = print_fmt.base.is_hex();
if !print_fmt.signed {
quote! { DisplayElement::Number(#hex, false, #value as #DISPLAY_WORK_TYPE) }
} else {
let final_type = WorkType::new_int_bits(len_bits, true);
let value = crate::builder::helper::sign_from_value(
len_bits, final_type, value,
);
quote! { DisplayElement::Number(#hex, #value.is_negative(), #value.abs() as #DISPLAY_WORK_TYPE) }
}
}
Meaning::Varnode(vars) => {
let function = &self.vars[vars.0].display_func;
quote! { #function(#value) }
}
Meaning::Literal(vars) => {
let function = &self.names[vars.0].display_func;
quote! { #function(#value) }
}
Meaning::Number(base, vars) => {
let function = &self.values[vars.0].display_func;
let hex = base.is_hex();
quote! {
#function(#hex, #value)
}
}
}
}
pub fn disassembly_function_call(
&self,
len_bits: u32,
value: impl ToTokens,
meaning: sleigh_rs::meaning::Meaning,
) -> TokenStream {
use sleigh_rs::meaning::Meaning;
match meaning {
Meaning::NoAttach(print_fmt) if print_fmt.signed => {
let final_type = WorkType::new_int_bits(len_bits, true);
crate::builder::helper::sign_from_value(
len_bits, final_type, value,
)
}
Meaning::Number(_base, vars) => {
let function = &self.values[vars.0].value_func;
quote! { #function(#value) }
}
_ => value.into_token_stream(),
}
}
pub fn to_tokens(
&self,
tokens: &mut TokenStream,
disassembler: &Disassembler,
) {
for variable in self.vars.iter() {
variable.to_tokens(tokens, disassembler);
}
for name in self.names.iter() {
name.to_tokens(tokens, disassembler);
}
for value in self.values.iter() {
value.to_tokens(tokens, disassembler);
}
}
}