[meta] Delegate finding the default value to OperandKind instead of its builder.

This applies both to the default_member value (which is now determined at
runtime, instead of pre-computed) and the rust_type value (which is
determined in the Operand's ctor, instead of the builder).
This commit is contained in:
Benjamin Bouvier
2019-10-29 15:18:45 +01:00
parent 4632d35196
commit ae3ea47dbd
3 changed files with 67 additions and 61 deletions

View File

@@ -95,7 +95,7 @@ impl EncodingBuilder {
&inst.inst.format, &inst.inst.format,
immediate_operand immediate_operand
.kind .kind
.default_member .default_member()
.expect("Immediates must always have a default member name set."), .expect("Immediates must always have a default member name set."),
immediate_value.to_string(), immediate_value.to_string(),
); );

View File

@@ -127,7 +127,7 @@ impl InstructionFormatBuilder {
pub fn imm(mut self, operand_kind: &OperandKind) -> Self { pub fn imm(mut self, operand_kind: &OperandKind) -> Self {
let field = FormatField { let field = FormatField {
kind: operand_kind.clone(), kind: operand_kind.clone(),
member: operand_kind.default_member.unwrap(), member: operand_kind.default_member().unwrap(),
}; };
self.imm_fields.push(field); self.imm_fields.push(field);
self self

View File

@@ -111,18 +111,55 @@ pub(crate) enum OperandKindFields {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct OperandKind { pub(crate) struct OperandKind {
pub name: &'static str, pub name: &'static str,
doc: Option<&'static str>,
doc: Option<String>, default_member: Option<&'static str>,
pub default_member: Option<&'static str>,
/// The camel-cased name of an operand kind is also the Rust type used to represent it. /// The camel-cased name of an operand kind is also the Rust type used to represent it.
pub rust_type: String, pub rust_type: String,
pub fields: OperandKindFields, pub fields: OperandKindFields,
} }
impl OperandKind { impl OperandKind {
fn new(
name: &'static str,
doc: Option<&'static str>,
default_member: Option<&'static str>,
rust_type: Option<&'static str>,
fields: OperandKindFields,
) -> Self {
// Compute the default rust_type value, if it wasn't provided.
let rust_type = match rust_type {
Some(rust_type) => rust_type.to_string(),
None => match &fields {
OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => {
format!("ir::immediates::{}", camel_case(name))
}
OperandKindFields::VariableArgs => "&[Value]".to_string(),
OperandKindFields::TypeVar(_) | OperandKindFields::EntityRef => {
format!("ir::{}", camel_case(name))
}
},
};
Self {
name,
doc,
default_member,
rust_type,
fields,
}
}
/// Name of this OperandKind in the format's member field.
pub fn default_member(&self) -> Option<&'static str> {
if let Some(member) = &self.default_member {
return Some(member);
}
match &self.fields {
OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => Some("imm"),
OperandKindFields::TypeVar(_) | OperandKindFields::EntityRef => Some(self.name),
OperandKindFields::VariableArgs => None,
}
}
fn doc(&self) -> Option<&str> { fn doc(&self) -> Option<&str> {
if let Some(doc) = &self.doc { if let Some(doc) = &self.doc {
return Some(doc); return Some(doc);
@@ -146,16 +183,22 @@ impl OperandKind {
} }
} }
impl Into<OperandKind> for &TypeVar {
fn into(self) -> OperandKind {
OperandKindBuilder::new("value", OperandKindFields::TypeVar(self.into())).build()
}
}
impl Into<OperandKind> for &OperandKind {
fn into(self) -> OperandKind {
self.clone()
}
}
pub(crate) struct OperandKindBuilder { pub(crate) struct OperandKindBuilder {
name: &'static str, name: &'static str,
doc: Option<&'static str>,
doc: Option<String>,
default_member: Option<&'static str>, default_member: Option<&'static str>,
rust_type: Option<&'static str>,
/// The camel-cased name of an operand kind is also the Rust type used to represent it.
rust_type: Option<String>,
fields: OperandKindFields, fields: OperandKindFields,
} }
@@ -169,7 +212,6 @@ impl OperandKindBuilder {
fields, fields,
} }
} }
pub fn new_imm(name: &'static str) -> Self { pub fn new_imm(name: &'static str) -> Self {
Self { Self {
name, name,
@@ -179,7 +221,6 @@ impl OperandKindBuilder {
fields: OperandKindFields::ImmValue, fields: OperandKindFields::ImmValue,
} }
} }
pub fn new_enum(name: &'static str, values: EnumValues) -> Self { pub fn new_enum(name: &'static str, values: EnumValues) -> Self {
Self { Self {
name, name,
@@ -189,10 +230,9 @@ impl OperandKindBuilder {
fields: OperandKindFields::ImmEnum(values), fields: OperandKindFields::ImmEnum(values),
} }
} }
pub fn doc(mut self, doc: &'static str) -> Self { pub fn doc(mut self, doc: &'static str) -> Self {
assert!(self.doc.is_none()); assert!(self.doc.is_none());
self.doc = Some(doc.to_string()); self.doc = Some(doc);
self self
} }
pub fn default_member(mut self, default_member: &'static str) -> Self { pub fn default_member(mut self, default_member: &'static str) -> Self {
@@ -202,50 +242,16 @@ impl OperandKindBuilder {
} }
pub fn rust_type(mut self, rust_type: &'static str) -> Self { pub fn rust_type(mut self, rust_type: &'static str) -> Self {
assert!(self.rust_type.is_none()); assert!(self.rust_type.is_none());
self.rust_type = Some(rust_type.to_string()); self.rust_type = Some(rust_type);
self self
} }
pub fn build(self) -> OperandKind { pub fn build(self) -> OperandKind {
let default_member = match self.default_member { OperandKind::new(
Some(default_member) => Some(default_member), self.name,
None => match &self.fields { self.doc,
OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => Some("imm"), self.default_member,
OperandKindFields::TypeVar(_) | OperandKindFields::EntityRef => Some(self.name), self.rust_type,
OperandKindFields::VariableArgs => None, self.fields,
}, )
};
let rust_type = match self.rust_type {
Some(rust_type) => rust_type.to_string(),
None => match &self.fields {
OperandKindFields::ImmEnum(_) | OperandKindFields::ImmValue => {
format!("ir::immediates::{}", camel_case(self.name))
}
OperandKindFields::VariableArgs => "&[Value]".to_string(),
OperandKindFields::TypeVar(_) | OperandKindFields::EntityRef => {
format!("ir::{}", camel_case(self.name))
}
},
};
OperandKind {
name: self.name,
doc: self.doc,
default_member,
rust_type,
fields: self.fields,
}
}
}
impl Into<OperandKind> for &TypeVar {
fn into(self) -> OperandKind {
OperandKindBuilder::new("value", OperandKindFields::TypeVar(self.into())).build()
}
}
impl Into<OperandKind> for &OperandKind {
fn into(self) -> OperandKind {
self.clone()
} }
} }