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: crate::AttachVarnodeId,
pub display_func: Ident,
pub value_func: Ident,
pub index_type: WorkType,
pub varnode_bytes: NonZeroTypeU,
}
impl VarMeaning {
pub fn new(
sleigh: &crate::Sleigh,
id: crate::AttachVarnodeId,
attach: &crate::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();
let first_value = {
let (_i, v) = &sleigh.0[0];
let regs = disassembler.registers.name();
let variant = disassembler.registers.register(*v);
quote! { #regs::#variant }
};
tokens.extend(quote! {
pub 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,)*
_ => #first_value,
}
}
pub 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: crate::AttachLiteralId,
pub display_func: Ident,
pub index_type: WorkType,
}
impl NameMeaning {
pub fn new(
id: crate::AttachLiteralId,
attach: &crate::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;
let first_literal = attach.0[0].1.clone();
tokens.extend(quote! {
pub 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),)*
_ => <#display_element>::Literal(#first_literal),
}
}
});
}
}
#[derive(Debug, Clone)]
pub struct ValueMeaning {
id: crate::AttachNumberId,
pub display_func: Ident,
pub value_func: Ident,
pub index_type: WorkType,
pub value_type: WorkType,
}
impl ValueMeaning {
pub fn new(
id: crate::AttachNumberId,
attach: &crate::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 as i128).unsigned_abs() as #DISPLAY_WORK_TYPE)
}
} else {
quote! {
<#display_element>::#number_ele(hex, false, value as #DISPLAY_WORK_TYPE)
}
};
let first_num_value = sleigh.0[0].1.signed_super().unsuffixed();
tokens.extend(quote! {
pub 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,)*
_ => #first_num_value,
}
}
pub 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: &crate::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, crate::AttachVarnodeId(i), var, counter_value())
})
.collect();
let names = sleigh
.attach_literals()
.iter()
.enumerate()
.map(|(i, var)| NameMeaning::new(crate::AttachLiteralId(i), var, counter_value()))
.collect();
let values = sleigh
.attach_numbers()
.iter()
.enumerate()
.map(|(i, var)| ValueMeaning::new(crate::AttachNumberId(i), var, counter_value()))
.collect();
Self {
vars,
names,
values,
}
}
pub fn display_function_call(
&self,
len_bits: u32,
value: impl ToTokens,
meaning: crate::meaning::Meaning,
) -> TokenStream {
use crate::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::codegen::builder::helper::sign_from_value(
len_bits, final_type, value,
);
quote! { DisplayElement::Number(#hex, #value.is_negative(), (#value as i128).unsigned_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: crate::meaning::Meaning,
) -> TokenStream {
use crate::meaning::Meaning;
match meaning {
Meaning::NoAttach(print_fmt) if print_fmt.signed => {
let final_type = WorkType::new_int_bits(len_bits, true);
crate::codegen::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);
}
}
}