use crate::cdsl::operands::OperandKind;
use std::fmt;
use std::rc::Rc;
#[derive(Debug)]
pub(crate) struct FormatField {
pub kind: OperandKind,
pub member: &'static str,
}
#[derive(Debug)]
pub(crate) struct InstructionFormat {
pub name: &'static str,
pub num_value_operands: usize,
pub has_value_list: bool,
pub imm_fields: Vec<FormatField>,
pub typevar_operand: Option<usize>,
}
#[derive(Hash, PartialEq, Eq)]
pub(crate) struct FormatStructure {
pub num_value_operands: usize,
pub has_value_list: bool,
pub imm_field_names: Vec<(&'static str, &'static str)>,
}
impl fmt::Display for InstructionFormat {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let imm_args = self
.imm_fields
.iter()
.map(|field| format!("{}: {}", field.member, field.kind.rust_type))
.collect::<Vec<_>>()
.join(", ");
fmt.write_fmt(format_args!(
"{}(imms=({}), vals={})",
self.name, imm_args, self.num_value_operands
))?;
Ok(())
}
}
impl InstructionFormat {
pub fn imm_by_name(&self, name: &'static str) -> &FormatField {
self.imm_fields
.iter()
.find(|&field| field.member == name)
.unwrap_or_else(|| {
panic!(
"unexpected immediate field named {} in instruction format {}",
name, self.name
)
})
}
pub fn structure(&self) -> FormatStructure {
FormatStructure {
num_value_operands: self.num_value_operands,
has_value_list: self.has_value_list,
imm_field_names: self
.imm_fields
.iter()
.map(|field| (field.kind.rust_field_name, field.kind.rust_type))
.collect::<Vec<_>>(),
}
}
}
pub(crate) struct InstructionFormatBuilder {
name: &'static str,
num_value_operands: usize,
has_value_list: bool,
imm_fields: Vec<FormatField>,
typevar_operand: Option<usize>,
}
impl InstructionFormatBuilder {
pub fn new(name: &'static str) -> Self {
Self {
name,
num_value_operands: 0,
has_value_list: false,
imm_fields: Vec::new(),
typevar_operand: None,
}
}
pub fn value(mut self) -> Self {
self.num_value_operands += 1;
self
}
pub fn varargs(mut self) -> Self {
self.has_value_list = true;
self
}
pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
let field = FormatField {
kind: operand_kind.clone(),
member: operand_kind.rust_field_name,
};
self.imm_fields.push(field);
self
}
pub fn imm_with_name(mut self, member: &'static str, operand_kind: &OperandKind) -> Self {
let field = FormatField {
kind: operand_kind.clone(),
member,
};
self.imm_fields.push(field);
self
}
pub fn typevar_operand(mut self, operand_index: usize) -> Self {
assert!(self.typevar_operand.is_none());
assert!(self.has_value_list || operand_index < self.num_value_operands);
self.typevar_operand = Some(operand_index);
self
}
pub fn build(self) -> Rc<InstructionFormat> {
let typevar_operand = if self.typevar_operand.is_some() {
self.typevar_operand
} else if self.has_value_list || self.num_value_operands > 0 {
Some(0)
} else {
None
};
Rc::new(InstructionFormat {
name: self.name,
num_value_operands: self.num_value_operands,
has_value_list: self.has_value_list,
imm_fields: self.imm_fields,
typevar_operand,
})
}
}