// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright 2018 Jacob Lifshay
+use proc_macro2::TokenStream;
+use quote::ToTokens;
use serde::de::{self, Deserialize, Deserializer};
+use std::borrow::Cow;
use std::fmt;
+use std::mem;
+use std::num::ParseIntError;
use util::NameFormat::*;
use util::WordIterator;
#[derive(Copy, Clone)]
-pub enum QuotedInteger {
- U16Hex(u16),
- U32Hex(u32),
+pub struct QuotedInteger<T>(pub T);
+
+pub trait QuotedIntegerProperties: Sized {
+ const DIGIT_COUNT: usize;
+ fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError>;
}
-impl fmt::Display for QuotedInteger {
+impl QuotedIntegerProperties for QuotedInteger<u16> {
+ const DIGIT_COUNT: usize = 4;
+ fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ Ok(QuotedInteger(u16::from_str_radix(src, radix)?))
+ }
+}
+
+impl QuotedIntegerProperties for QuotedInteger<u32> {
+ const DIGIT_COUNT: usize = 8;
+ fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ Ok(QuotedInteger(u32::from_str_radix(src, radix)?))
+ }
+}
+
+impl<T: ToTokens> ToTokens for QuotedInteger<T> {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.0.to_tokens(tokens)
+ }
+}
+
+impl fmt::Display for QuotedInteger<u16> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- QuotedInteger::U16Hex(v) => write!(f, "{:#06X}", v),
- QuotedInteger::U32Hex(v) => write!(f, "{:#010X}", v),
- }
+ write!(f, "{:#06X}", self.0)
+ }
+}
+
+impl fmt::Display for QuotedInteger<u32> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:#010X}", self.0)
}
}
-impl fmt::Debug for QuotedInteger {
+impl<T> fmt::Debug for QuotedInteger<T>
+where
+ Self: fmt::Display + Copy,
+{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- struct DisplayQuotedInteger(self::QuotedInteger);
- impl fmt::Debug for DisplayQuotedInteger {
+ struct DisplayQuotedInteger<T>(QuotedInteger<T>);
+ impl<T> fmt::Debug for DisplayQuotedInteger<T>
+ where
+ QuotedInteger<T>: fmt::Display,
+ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
- #[derive(Debug)]
- struct QuotedInteger(DisplayQuotedInteger);
- QuotedInteger(DisplayQuotedInteger(*self)).fmt(f)
+ f.debug_tuple("QuotedInteger")
+ .field(&DisplayQuotedInteger(*self))
+ .finish()
}
}
-impl<'de> Deserialize<'de> for QuotedInteger {
+impl<'de, T> Deserialize<'de> for QuotedInteger<T>
+where
+ Self: QuotedIntegerProperties,
+{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
let prefix = "0x";
"invalid quoted integer -- not a hexadecimal digit",
));
}
- let retval = match digits.len() {
- 4 => QuotedInteger::U16Hex(u16::from_str_radix(digits, radix).unwrap()),
- 8 => QuotedInteger::U32Hex(u32::from_str_radix(digits, radix).unwrap()),
- _ => {
- return Err(de::Error::custom(
- "invalid quoted integer -- wrong number of hex digits",
- ));
- }
- };
- Ok(retval)
+ if digits.len() != Self::DIGIT_COUNT {
+ return Err(de::Error::custom(
+ "invalid quoted integer -- wrong number of hex digits",
+ ));
+ }
+ Ok(Self::from_str_radix(digits, radix).unwrap())
}
}
Variadic,
}
-#[derive(Deserialize, Debug)]
+#[derive(Clone, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct InstructionOperand {
- kind: String,
- name: Option<String>,
- quantifier: Option<Quantifier>,
+ pub kind: Kind,
+ pub name: Option<String>,
+ pub quantifier: Option<Quantifier>,
}
impl InstructionOperand {
- pub fn guess_name(&mut self) -> Result<(), ::Error> {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
if self.name.is_none() {
self.name = Some(
SnakeCase
- .name_from_words(WordIterator::new(&self.kind))
+ .name_from_words(WordIterator::new(self.kind.as_ref()))
.ok_or(::Error::DeducingNameForInstructionOperandFailed)?,
);
}
+ self.kind.set_bit_width(BitWidth::Bits32);
Ok(())
}
}
-#[derive(Deserialize, Debug)]
+#[derive(Clone, Eq, PartialEq, Hash, Debug)]
+pub enum InstructionName {
+ OpSwitch,
+ OpSwitch32,
+ OpSwitch64,
+ OpConstant,
+ OpConstant32,
+ OpConstant64,
+ OpSpecConstant,
+ OpSpecConstant32,
+ OpSpecConstant64,
+ OpSpecConstantOp,
+ OpAccessChain,
+ OpBitcast,
+ OpBitwiseAnd,
+ OpBitwiseOr,
+ OpBitwiseXor,
+ OpCompositeExtract,
+ OpCompositeInsert,
+ OpConvertFToS,
+ OpConvertFToU,
+ OpConvertPtrToU,
+ OpConvertSToF,
+ OpConvertUToF,
+ OpConvertUToPtr,
+ OpFAdd,
+ OpFConvert,
+ OpFDiv,
+ OpFMod,
+ OpFMul,
+ OpFNegate,
+ OpFRem,
+ OpFSub,
+ OpGenericCastToPtr,
+ OpIAdd,
+ OpIEqual,
+ OpIMul,
+ OpINotEqual,
+ OpISub,
+ OpInBoundsAccessChain,
+ OpInBoundsPtrAccessChain,
+ OpLogicalAnd,
+ OpLogicalEqual,
+ OpLogicalNot,
+ OpLogicalNotEqual,
+ OpLogicalOr,
+ OpNot,
+ OpPtrAccessChain,
+ OpPtrCastToGeneric,
+ OpQuantizeToF16,
+ OpSConvert,
+ OpSDiv,
+ OpSGreaterThan,
+ OpSGreaterThanEqual,
+ OpSLessThan,
+ OpSLessThanEqual,
+ OpSMod,
+ OpSNegate,
+ OpSRem,
+ OpSelect,
+ OpShiftLeftLogical,
+ OpShiftRightArithmetic,
+ OpShiftRightLogical,
+ OpUConvert,
+ OpUDiv,
+ OpUGreaterThan,
+ OpUGreaterThanEqual,
+ OpULessThan,
+ OpULessThanEqual,
+ OpUMod,
+ OpVectorShuffle,
+ Other(String),
+}
+
+pub const OP_SPEC_CONSTANT_OP_SUPPORTED_INSTRUCTIONS: &[InstructionName] = &[
+ InstructionName::OpAccessChain,
+ InstructionName::OpBitcast,
+ InstructionName::OpBitwiseAnd,
+ InstructionName::OpBitwiseOr,
+ InstructionName::OpBitwiseXor,
+ InstructionName::OpCompositeExtract,
+ InstructionName::OpCompositeInsert,
+ InstructionName::OpConvertFToS,
+ InstructionName::OpConvertFToU,
+ InstructionName::OpConvertPtrToU,
+ InstructionName::OpConvertSToF,
+ InstructionName::OpConvertUToF,
+ InstructionName::OpConvertUToPtr,
+ InstructionName::OpFAdd,
+ InstructionName::OpFConvert,
+ InstructionName::OpFDiv,
+ InstructionName::OpFMod,
+ InstructionName::OpFMul,
+ InstructionName::OpFNegate,
+ InstructionName::OpFRem,
+ InstructionName::OpFSub,
+ InstructionName::OpGenericCastToPtr,
+ InstructionName::OpIAdd,
+ InstructionName::OpIEqual,
+ InstructionName::OpIMul,
+ InstructionName::OpINotEqual,
+ InstructionName::OpISub,
+ InstructionName::OpInBoundsAccessChain,
+ InstructionName::OpInBoundsPtrAccessChain,
+ InstructionName::OpLogicalAnd,
+ InstructionName::OpLogicalEqual,
+ InstructionName::OpLogicalNot,
+ InstructionName::OpLogicalNotEqual,
+ InstructionName::OpLogicalOr,
+ InstructionName::OpNot,
+ InstructionName::OpPtrAccessChain,
+ InstructionName::OpPtrCastToGeneric,
+ InstructionName::OpQuantizeToF16,
+ InstructionName::OpSConvert,
+ InstructionName::OpSDiv,
+ InstructionName::OpSGreaterThan,
+ InstructionName::OpSGreaterThanEqual,
+ InstructionName::OpSLessThan,
+ InstructionName::OpSLessThanEqual,
+ InstructionName::OpSMod,
+ InstructionName::OpSNegate,
+ InstructionName::OpSRem,
+ InstructionName::OpSelect,
+ InstructionName::OpShiftLeftLogical,
+ InstructionName::OpShiftRightArithmetic,
+ InstructionName::OpShiftRightLogical,
+ InstructionName::OpUConvert,
+ InstructionName::OpUDiv,
+ InstructionName::OpUGreaterThan,
+ InstructionName::OpUGreaterThanEqual,
+ InstructionName::OpULessThan,
+ InstructionName::OpULessThanEqual,
+ InstructionName::OpUMod,
+ InstructionName::OpVectorShuffle,
+];
+
+impl Default for InstructionName {
+ fn default() -> Self {
+ InstructionName::Other(String::new())
+ }
+}
+
+impl From<String> for InstructionName {
+ fn from(v: String) -> Self {
+ match &*v {
+ "OpSwitch" => return InstructionName::OpSwitch,
+ "OpConstant" => return InstructionName::OpConstant,
+ "OpSpecConstant" => return InstructionName::OpSpecConstant,
+ "OpSpecConstantOp" => return InstructionName::OpSpecConstantOp,
+ "OpAccessChain" => return InstructionName::OpAccessChain,
+ "OpBitcast" => return InstructionName::OpBitcast,
+ "OpBitwiseAnd" => return InstructionName::OpBitwiseAnd,
+ "OpBitwiseOr" => return InstructionName::OpBitwiseOr,
+ "OpBitwiseXor" => return InstructionName::OpBitwiseXor,
+ "OpCompositeExtract" => return InstructionName::OpCompositeExtract,
+ "OpCompositeInsert" => return InstructionName::OpCompositeInsert,
+ "OpConvertFToS" => return InstructionName::OpConvertFToS,
+ "OpConvertFToU" => return InstructionName::OpConvertFToU,
+ "OpConvertPtrToU" => return InstructionName::OpConvertPtrToU,
+ "OpConvertSToF" => return InstructionName::OpConvertSToF,
+ "OpConvertUToF" => return InstructionName::OpConvertUToF,
+ "OpConvertUToPtr" => return InstructionName::OpConvertUToPtr,
+ "OpFAdd" => return InstructionName::OpFAdd,
+ "OpFConvert" => return InstructionName::OpFConvert,
+ "OpFDiv" => return InstructionName::OpFDiv,
+ "OpFMod" => return InstructionName::OpFMod,
+ "OpFMul" => return InstructionName::OpFMul,
+ "OpFNegate" => return InstructionName::OpFNegate,
+ "OpFRem" => return InstructionName::OpFRem,
+ "OpFSub" => return InstructionName::OpFSub,
+ "OpGenericCastToPtr" => return InstructionName::OpGenericCastToPtr,
+ "OpIAdd" => return InstructionName::OpIAdd,
+ "OpIEqual" => return InstructionName::OpIEqual,
+ "OpIMul" => return InstructionName::OpIMul,
+ "OpINotEqual" => return InstructionName::OpINotEqual,
+ "OpISub" => return InstructionName::OpISub,
+ "OpInBoundsAccessChain" => return InstructionName::OpInBoundsAccessChain,
+ "OpInBoundsPtrAccessChain" => return InstructionName::OpInBoundsPtrAccessChain,
+ "OpLogicalAnd" => return InstructionName::OpLogicalAnd,
+ "OpLogicalEqual" => return InstructionName::OpLogicalEqual,
+ "OpLogicalNot" => return InstructionName::OpLogicalNot,
+ "OpLogicalNotEqual" => return InstructionName::OpLogicalNotEqual,
+ "OpLogicalOr" => return InstructionName::OpLogicalOr,
+ "OpNot" => return InstructionName::OpNot,
+ "OpPtrAccessChain" => return InstructionName::OpPtrAccessChain,
+ "OpPtrCastToGeneric" => return InstructionName::OpPtrCastToGeneric,
+ "OpQuantizeToF16" => return InstructionName::OpQuantizeToF16,
+ "OpSConvert" => return InstructionName::OpSConvert,
+ "OpSDiv" => return InstructionName::OpSDiv,
+ "OpSGreaterThan" => return InstructionName::OpSGreaterThan,
+ "OpSGreaterThanEqual" => return InstructionName::OpSGreaterThanEqual,
+ "OpSLessThan" => return InstructionName::OpSLessThan,
+ "OpSLessThanEqual" => return InstructionName::OpSLessThanEqual,
+ "OpSMod" => return InstructionName::OpSMod,
+ "OpSNegate" => return InstructionName::OpSNegate,
+ "OpSRem" => return InstructionName::OpSRem,
+ "OpSelect" => return InstructionName::OpSelect,
+ "OpShiftLeftLogical" => return InstructionName::OpShiftLeftLogical,
+ "OpShiftRightArithmetic" => return InstructionName::OpShiftRightArithmetic,
+ "OpShiftRightLogical" => return InstructionName::OpShiftRightLogical,
+ "OpUConvert" => return InstructionName::OpUConvert,
+ "OpUDiv" => return InstructionName::OpUDiv,
+ "OpUGreaterThan" => return InstructionName::OpUGreaterThan,
+ "OpUGreaterThanEqual" => return InstructionName::OpUGreaterThanEqual,
+ "OpULessThan" => return InstructionName::OpULessThan,
+ "OpULessThanEqual" => return InstructionName::OpULessThanEqual,
+ "OpUMod" => return InstructionName::OpUMod,
+ "OpVectorShuffle" => return InstructionName::OpVectorShuffle,
+ _ => {}
+ }
+ InstructionName::Other(v)
+ }
+}
+
+impl AsRef<str> for InstructionName {
+ fn as_ref(&self) -> &str {
+ match self {
+ InstructionName::OpSwitch => "OpSwitch",
+ InstructionName::OpSwitch32 => "OpSwitch32",
+ InstructionName::OpSwitch64 => "OpSwitch64",
+ InstructionName::OpConstant => "OpConstant",
+ InstructionName::OpConstant32 => "OpConstant32",
+ InstructionName::OpConstant64 => "OpConstant64",
+ InstructionName::OpSpecConstant => "OpSpecConstant",
+ InstructionName::OpSpecConstant32 => "OpSpecConstant32",
+ InstructionName::OpSpecConstant64 => "OpSpecConstant64",
+ InstructionName::OpSpecConstantOp => "OpSpecConstantOp",
+ InstructionName::OpAccessChain => "OpAccessChain",
+ InstructionName::OpBitcast => "OpBitcast",
+ InstructionName::OpBitwiseAnd => "OpBitwiseAnd",
+ InstructionName::OpBitwiseOr => "OpBitwiseOr",
+ InstructionName::OpBitwiseXor => "OpBitwiseXor",
+ InstructionName::OpCompositeExtract => "OpCompositeExtract",
+ InstructionName::OpCompositeInsert => "OpCompositeInsert",
+ InstructionName::OpConvertFToS => "OpConvertFToS",
+ InstructionName::OpConvertFToU => "OpConvertFToU",
+ InstructionName::OpConvertPtrToU => "OpConvertPtrToU",
+ InstructionName::OpConvertSToF => "OpConvertSToF",
+ InstructionName::OpConvertUToF => "OpConvertUToF",
+ InstructionName::OpConvertUToPtr => "OpConvertUToPtr",
+ InstructionName::OpFAdd => "OpFAdd",
+ InstructionName::OpFConvert => "OpFConvert",
+ InstructionName::OpFDiv => "OpFDiv",
+ InstructionName::OpFMod => "OpFMod",
+ InstructionName::OpFMul => "OpFMul",
+ InstructionName::OpFNegate => "OpFNegate",
+ InstructionName::OpFRem => "OpFRem",
+ InstructionName::OpFSub => "OpFSub",
+ InstructionName::OpGenericCastToPtr => "OpGenericCastToPtr",
+ InstructionName::OpIAdd => "OpIAdd",
+ InstructionName::OpIEqual => "OpIEqual",
+ InstructionName::OpIMul => "OpIMul",
+ InstructionName::OpINotEqual => "OpINotEqual",
+ InstructionName::OpISub => "OpISub",
+ InstructionName::OpInBoundsAccessChain => "OpInBoundsAccessChain",
+ InstructionName::OpInBoundsPtrAccessChain => "OpInBoundsPtrAccessChain",
+ InstructionName::OpLogicalAnd => "OpLogicalAnd",
+ InstructionName::OpLogicalEqual => "OpLogicalEqual",
+ InstructionName::OpLogicalNot => "OpLogicalNot",
+ InstructionName::OpLogicalNotEqual => "OpLogicalNotEqual",
+ InstructionName::OpLogicalOr => "OpLogicalOr",
+ InstructionName::OpNot => "OpNot",
+ InstructionName::OpPtrAccessChain => "OpPtrAccessChain",
+ InstructionName::OpPtrCastToGeneric => "OpPtrCastToGeneric",
+ InstructionName::OpQuantizeToF16 => "OpQuantizeToF16",
+ InstructionName::OpSConvert => "OpSConvert",
+ InstructionName::OpSDiv => "OpSDiv",
+ InstructionName::OpSGreaterThan => "OpSGreaterThan",
+ InstructionName::OpSGreaterThanEqual => "OpSGreaterThanEqual",
+ InstructionName::OpSLessThan => "OpSLessThan",
+ InstructionName::OpSLessThanEqual => "OpSLessThanEqual",
+ InstructionName::OpSMod => "OpSMod",
+ InstructionName::OpSNegate => "OpSNegate",
+ InstructionName::OpSRem => "OpSRem",
+ InstructionName::OpSelect => "OpSelect",
+ InstructionName::OpShiftLeftLogical => "OpShiftLeftLogical",
+ InstructionName::OpShiftRightArithmetic => "OpShiftRightArithmetic",
+ InstructionName::OpShiftRightLogical => "OpShiftRightLogical",
+ InstructionName::OpUConvert => "OpUConvert",
+ InstructionName::OpUDiv => "OpUDiv",
+ InstructionName::OpUGreaterThan => "OpUGreaterThan",
+ InstructionName::OpUGreaterThanEqual => "OpUGreaterThanEqual",
+ InstructionName::OpULessThan => "OpULessThan",
+ InstructionName::OpULessThanEqual => "OpULessThanEqual",
+ InstructionName::OpUMod => "OpUMod",
+ InstructionName::OpVectorShuffle => "OpVectorShuffle",
+ InstructionName::Other(v) => v,
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for InstructionName {
+ fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+ Ok(Self::from(String::deserialize(deserializer)?))
+ }
+}
+
+#[derive(Clone, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Instruction {
- opname: String,
- opcode: u16,
+ pub opname: InstructionName,
+ pub opcode: u16,
#[serde(default)]
- operands: Vec<InstructionOperand>,
+ pub operands: Vec<InstructionOperand>,
#[serde(default)]
- capabilities: Vec<String>,
+ pub capabilities: Vec<String>,
#[serde(default)]
- extensions: Vec<String>,
+ pub extensions: Vec<String>,
#[serde(default)]
- version: SPIRVVersion,
+ pub version: SPIRVVersion,
}
impl Instruction {
- pub fn guess_names(&mut self) -> Result<(), ::Error> {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
for operand in self.operands.iter_mut() {
- operand.guess_name()?;
+ operand.fixup()?;
}
Ok(())
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct ExtensionInstruction {
- opname: String,
- opcode: u16,
+ pub opname: String,
+ pub opcode: u16,
#[serde(default)]
- operands: Vec<InstructionOperand>,
+ pub operands: Vec<InstructionOperand>,
#[serde(default)]
- capabilities: Vec<String>,
+ pub capabilities: Vec<String>,
}
impl ExtensionInstruction {
- pub fn guess_names(&mut self) -> Result<(), ::Error> {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
for operand in self.operands.iter_mut() {
- operand.guess_name()?;
+ operand.fixup()?;
}
Ok(())
}
}
-#[derive(Deserialize, Debug)]
+#[derive(Deserialize, Debug, Default)]
+#[serde(deny_unknown_fields)]
+pub struct BitwiseEnumerantParameter {
+ pub kind: Kind,
+}
+
+impl BitwiseEnumerantParameter {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
+ self.kind.set_bit_width(BitWidth::Bits32);
+ Ok(())
+ }
+}
+
+#[derive(Deserialize, Debug, Default)]
#[serde(deny_unknown_fields)]
-pub struct EnumerantParameter {
- kind: String,
- name: Option<String>,
+pub struct ValueEnumerantParameter {
+ pub kind: Kind,
+ pub name: Option<String>,
}
-impl EnumerantParameter {
- pub fn guess_name(&mut self) -> Result<(), ::Error> {
+impl ValueEnumerantParameter {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
if self.name.is_none() {
self.name = Some(
SnakeCase
- .name_from_words(WordIterator::new(&self.kind))
+ .name_from_words(WordIterator::new(self.kind.as_ref()))
.ok_or(::Error::DeducingNameForEnumerantParameterFailed)?,
);
}
+ self.kind.set_bit_width(BitWidth::Bits32);
Ok(())
}
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
-pub struct Enumerant<Value> {
- enumerant: String,
- value: Value,
+pub struct Enumerant<Value, EnumerantParameter> {
+ pub enumerant: String,
+ pub value: Value,
#[serde(default)]
- capabilities: Vec<String>,
+ pub capabilities: Vec<String>,
#[serde(default)]
- parameters: Vec<EnumerantParameter>,
+ pub parameters: Vec<EnumerantParameter>,
#[serde(default)]
- extensions: Vec<String>,
+ pub extensions: Vec<String>,
#[serde(default)]
- version: SPIRVVersion,
+ pub version: SPIRVVersion,
+}
+
+impl Enumerant<u32, ValueEnumerantParameter> {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
+ for parameter in self.parameters.iter_mut() {
+ parameter.fixup()?;
+ }
+ Ok(())
+ }
}
-impl<Value> Enumerant<Value> {
- pub fn guess_names(&mut self) -> Result<(), ::Error> {
+impl Enumerant<QuotedInteger<u16>, BitwiseEnumerantParameter> {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
for parameter in self.parameters.iter_mut() {
- parameter.guess_name()?;
+ parameter.fixup()?;
}
Ok(())
}
}
+#[derive(Clone, Eq, PartialEq, Hash, Debug)]
+pub enum Kind {
+ Literal(LiteralKind),
+ IdRef,
+ PairLiteralIntegerIdRef,
+ PairLiteralInteger32IdRef,
+ PairLiteralInteger64IdRef,
+ Other(String),
+}
+
+impl Kind {
+ pub fn set_bit_width(&mut self, bit_width: BitWidth) {
+ match (self, bit_width) {
+ (Kind::Literal(literal), bit_width) => literal.set_bit_width(bit_width),
+ (this @ Kind::PairLiteralIntegerIdRef, BitWidth::Bits32) => {
+ *this = Kind::PairLiteralInteger32IdRef
+ }
+ (this @ Kind::PairLiteralIntegerIdRef, BitWidth::Bits64) => {
+ *this = Kind::PairLiteralInteger64IdRef
+ }
+ (Kind::IdRef, _)
+ | (Kind::PairLiteralInteger32IdRef, _)
+ | (Kind::PairLiteralInteger64IdRef, _)
+ | (Kind::Other(_), _) => {}
+ }
+ }
+}
+
+impl Default for Kind {
+ fn default() -> Self {
+ Kind::Other(String::new())
+ }
+}
+
+impl<'a> From<Cow<'a, str>> for Kind {
+ fn from(v: Cow<'a, str>) -> Self {
+ if let Some(v) = LiteralKind::from_str(&v) {
+ Kind::Literal(v)
+ } else if v == "IdRef" {
+ Kind::IdRef
+ } else if v == "PairLiteralIntegerIdRef" {
+ Kind::PairLiteralIntegerIdRef
+ } else {
+ Kind::Other(v.into_owned())
+ }
+ }
+}
+
+impl<'a> From<&'a str> for Kind {
+ fn from(v: &'a str) -> Self {
+ Kind::from(Cow::Borrowed(v))
+ }
+}
+
+impl From<String> for Kind {
+ fn from(v: String) -> Self {
+ Kind::from(Cow::Owned(v))
+ }
+}
+
+impl AsRef<str> for Kind {
+ fn as_ref(&self) -> &str {
+ match self {
+ Kind::Literal(v) => v.as_ref(),
+ Kind::IdRef => "IdRef",
+ Kind::PairLiteralIntegerIdRef => "PairLiteralIntegerIdRef",
+ Kind::PairLiteralInteger32IdRef => "PairLiteralInteger32IdRef",
+ Kind::PairLiteralInteger64IdRef => "PairLiteralInteger64IdRef",
+ Kind::Other(v) => v,
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for Kind {
+ fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
+ Ok(Self::from(String::deserialize(deserializer)?))
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Deserialize)]
+pub enum LiteralKind {
+ LiteralInteger,
+ #[serde(skip_deserializing)]
+ LiteralInteger32,
+ #[serde(skip_deserializing)]
+ LiteralInteger64,
+ LiteralString,
+ LiteralContextDependentNumber,
+ #[serde(skip_deserializing)]
+ LiteralContextDependentNumber32,
+ #[serde(skip_deserializing)]
+ LiteralContextDependentNumber64,
+ LiteralExtInstInteger,
+ LiteralSpecConstantOpInteger,
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub enum BitWidth {
+ Bits32,
+ Bits64,
+}
+
+impl LiteralKind {
+ pub fn from_str<T: AsRef<str>>(v: T) -> Option<Self> {
+ match v.as_ref() {
+ "LiteralInteger" => Some(LiteralKind::LiteralInteger),
+ "LiteralString" => Some(LiteralKind::LiteralString),
+ "LiteralContextDependentNumber" => Some(LiteralKind::LiteralContextDependentNumber),
+ "LiteralExtInstInteger" => Some(LiteralKind::LiteralExtInstInteger),
+ "LiteralSpecConstantOpInteger" => Some(LiteralKind::LiteralSpecConstantOpInteger),
+ _ => None,
+ }
+ }
+ pub fn set_bit_width(&mut self, bit_width: BitWidth) {
+ *self = match (*self, bit_width) {
+ (LiteralKind::LiteralInteger, BitWidth::Bits32) => LiteralKind::LiteralInteger32,
+ (LiteralKind::LiteralInteger, BitWidth::Bits64) => LiteralKind::LiteralInteger64,
+ (LiteralKind::LiteralContextDependentNumber, BitWidth::Bits32) => {
+ LiteralKind::LiteralContextDependentNumber32
+ }
+ (LiteralKind::LiteralContextDependentNumber, BitWidth::Bits64) => {
+ LiteralKind::LiteralContextDependentNumber64
+ }
+ (LiteralKind::LiteralInteger32, _)
+ | (LiteralKind::LiteralInteger64, _)
+ | (LiteralKind::LiteralString, _)
+ | (LiteralKind::LiteralContextDependentNumber32, _)
+ | (LiteralKind::LiteralContextDependentNumber64, _)
+ | (LiteralKind::LiteralExtInstInteger, _)
+ | (LiteralKind::LiteralSpecConstantOpInteger, _) => return,
+ }
+ }
+}
+
+impl AsRef<str> for LiteralKind {
+ fn as_ref(&self) -> &str {
+ match self {
+ LiteralKind::LiteralInteger => "LiteralInteger",
+ LiteralKind::LiteralInteger32 => "LiteralInteger32",
+ LiteralKind::LiteralInteger64 => "LiteralInteger64",
+ LiteralKind::LiteralString => "LiteralString",
+ LiteralKind::LiteralContextDependentNumber => "LiteralContextDependentNumber",
+ LiteralKind::LiteralContextDependentNumber32 => "LiteralContextDependentNumber32",
+ LiteralKind::LiteralContextDependentNumber64 => "LiteralContextDependentNumber64",
+ LiteralKind::LiteralExtInstInteger => "LiteralExtInstInteger",
+ LiteralKind::LiteralSpecConstantOpInteger => "LiteralSpecConstantOpInteger",
+ }
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
#[serde(tag = "category")]
pub enum OperandKind {
BitEnum {
- kind: String,
- enumerants: Vec<Enumerant<QuotedInteger>>,
+ kind: Kind,
+ enumerants: Vec<Enumerant<QuotedInteger<u16>, BitwiseEnumerantParameter>>,
},
ValueEnum {
- kind: String,
- enumerants: Vec<Enumerant<u32>>,
+ kind: Kind,
+ enumerants: Vec<Enumerant<u32, ValueEnumerantParameter>>,
},
Id {
- kind: String,
+ kind: Kind,
doc: Option<String>,
},
Literal {
- kind: String,
+ kind: LiteralKind,
doc: Option<String>,
},
Composite {
- kind: String,
- bases: Vec<String>,
+ kind: Kind,
+ bases: Vec<Kind>,
},
}
-impl OperandKind {
- pub fn guess_names(&mut self) -> Result<(), ::Error> {
- match self {
- OperandKind::BitEnum { enumerants, .. } => {
- for enumerant in enumerants.iter_mut() {
- enumerant.guess_names()?;
- }
- }
- OperandKind::ValueEnum { enumerants, .. } => {
- for enumerant in enumerants.iter_mut() {
- enumerant.guess_names()?;
- }
- }
- OperandKind::Id { .. }
- | OperandKind::Literal { .. }
- | OperandKind::Composite { .. } => {}
- }
- Ok(())
- }
-}
-
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct CoreGrammar {
- copyright: Vec<String>,
- magic_number: QuotedInteger,
- major_version: u16,
- minor_version: u16,
- revision: u32,
- instructions: Vec<Instruction>,
- operand_kinds: Vec<OperandKind>,
+ pub copyright: Vec<String>,
+ pub magic_number: QuotedInteger<u32>,
+ pub major_version: u32,
+ pub minor_version: u32,
+ pub revision: u32,
+ pub instructions: Vec<Instruction>,
+ pub operand_kinds: Vec<OperandKind>,
}
impl CoreGrammar {
- pub fn guess_names(&mut self) -> Result<(), ::Error> {
- for instruction in self.instructions.iter_mut() {
- instruction.guess_names()?;
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
+ let instructions = mem::replace(&mut self.instructions, Vec::new());
+ for mut instruction in instructions {
+ if instruction.version == SPIRVVersion::None {
+ continue;
+ }
+ let (opname_32, opname_64) = match instruction.opname {
+ InstructionName::OpSwitch => {
+ (InstructionName::OpSwitch32, InstructionName::OpSwitch64)
+ }
+ InstructionName::OpConstant => {
+ (InstructionName::OpConstant32, InstructionName::OpConstant64)
+ }
+ InstructionName::OpSpecConstant => (
+ InstructionName::OpSpecConstant32,
+ InstructionName::OpSpecConstant64,
+ ),
+ opname => {
+ instruction.opname = opname;
+ instruction.fixup()?;
+ self.instructions.push(instruction);
+ continue;
+ }
+ };
+ instruction.opname = InstructionName::default();
+ let mut op_32 = Instruction {
+ opname: opname_32,
+ ..instruction.clone()
+ };
+ for operand in op_32.operands.iter_mut() {
+ operand.kind.set_bit_width(BitWidth::Bits32);
+ }
+ op_32.fixup()?;
+ self.instructions.push(op_32);
+ let mut op_64 = Instruction {
+ opname: opname_64,
+ ..instruction
+ };
+ for operand in op_64.operands.iter_mut() {
+ operand.kind.set_bit_width(BitWidth::Bits64);
+ }
+ op_64.fixup()?;
+ self.instructions.push(op_64);
}
- for operand_kind in self.operand_kinds.iter_mut() {
- operand_kind.guess_names()?;
+ let operand_kinds = mem::replace(&mut self.operand_kinds, Vec::new());
+ for operand_kind in operand_kinds {
+ match operand_kind {
+ OperandKind::BitEnum {
+ kind,
+ mut enumerants,
+ } => {
+ enumerants.retain(|enumerant| enumerant.version != SPIRVVersion::None);
+ for enumerant in enumerants.iter_mut() {
+ enumerant.fixup()?;
+ }
+ self.operand_kinds
+ .push(OperandKind::BitEnum { kind, enumerants });
+ }
+ OperandKind::ValueEnum {
+ kind,
+ mut enumerants,
+ } => {
+ enumerants.retain(|enumerant| enumerant.version != SPIRVVersion::None);
+ for enumerant in enumerants.iter_mut() {
+ enumerant.fixup()?;
+ }
+ self.operand_kinds
+ .push(OperandKind::ValueEnum { kind, enumerants });
+ }
+ OperandKind::Composite { kind, mut bases } => match kind {
+ Kind::PairLiteralIntegerIdRef => {
+ let mut bases_32 = bases.clone();
+ let mut bases_64 = bases;
+ for base in bases_32.iter_mut() {
+ base.set_bit_width(BitWidth::Bits32);
+ }
+ for base in bases_64.iter_mut() {
+ base.set_bit_width(BitWidth::Bits64);
+ }
+ self.operand_kinds.push(OperandKind::Composite {
+ kind: Kind::PairLiteralInteger32IdRef,
+ bases: bases_32,
+ });
+ self.operand_kinds.push(OperandKind::Composite {
+ kind: Kind::PairLiteralInteger64IdRef,
+ bases: bases_64,
+ });
+ }
+ kind => {
+ for base in bases.iter_mut() {
+ base.set_bit_width(BitWidth::Bits32);
+ }
+ self.operand_kinds
+ .push(OperandKind::Composite { kind, bases });
+ }
+ },
+ OperandKind::Literal { kind, doc } => match kind {
+ LiteralKind::LiteralInteger => {
+ self.operand_kinds.push(OperandKind::Literal {
+ kind: LiteralKind::LiteralInteger32,
+ doc: doc.clone(),
+ });
+ self.operand_kinds.push(OperandKind::Literal {
+ kind: LiteralKind::LiteralInteger64,
+ doc,
+ });
+ }
+ LiteralKind::LiteralContextDependentNumber => {
+ self.operand_kinds.push(OperandKind::Literal {
+ kind: LiteralKind::LiteralContextDependentNumber32,
+ doc: doc.clone(),
+ });
+ self.operand_kinds.push(OperandKind::Literal {
+ kind: LiteralKind::LiteralContextDependentNumber64,
+ doc,
+ });
+ }
+ kind => self.operand_kinds.push(OperandKind::Literal { kind, doc }),
+ },
+ OperandKind::Id { kind, doc } => {
+ self.operand_kinds.push(OperandKind::Id { kind, doc })
+ }
+ }
}
Ok(())
}
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct ExtensionInstructionSet {
- copyright: Vec<String>,
- version: u32,
- revision: u32,
- instructions: Vec<ExtensionInstruction>,
+ pub copyright: Vec<String>,
+ pub version: u32,
+ pub revision: u32,
+ pub instructions: Vec<ExtensionInstruction>,
}
impl ExtensionInstructionSet {
- pub fn guess_names(&mut self) -> Result<(), ::Error> {
+ pub fn fixup(&mut self) -> Result<(), ::Error> {
for instruction in self.instructions.iter_mut() {
- instruction.guess_names()?;
+ instruction.fixup()?;
}
Ok(())
}
--- /dev/null
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// Copyright 2018 Jacob Lifshay
+
+use ast;
+use proc_macro2;
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::fmt;
+use std::io::{self, Read, Write};
+use std::process::{Child, Command, ExitStatus, Stdio};
+use std::thread;
+use util::{self, NameFormat::*};
+use which;
+use Error;
+use Options;
+
+#[derive(Debug)]
+enum FormatError {
+ IOError(io::Error),
+ WhichError(which::Error),
+ RustFmtFailed(ExitStatus),
+}
+
+impl fmt::Display for FormatError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ FormatError::IOError(v) => fmt::Display::fmt(v, f),
+ FormatError::WhichError(v) => fmt::Display::fmt(v, f),
+ FormatError::RustFmtFailed(v) => write!(f, "rustfmt failed: {:?}", v),
+ }
+ }
+}
+
+impl From<which::Error> for FormatError {
+ fn from(v: which::Error) -> Self {
+ FormatError::WhichError(v)
+ }
+}
+
+impl From<io::Error> for FormatError {
+ fn from(v: io::Error) -> Self {
+ FormatError::IOError(v)
+ }
+}
+
+fn format_source<'a>(options: &Options, source: &'a str) -> Result<Cow<'a, str>, FormatError> {
+ if !options.run_rustfmt {
+ return Ok(Cow::Borrowed(source));
+ }
+ let rustfmt_path = match options.rustfmt_path.clone() {
+ Some(v) => v,
+ None => which::which("rustfmt")?,
+ };
+ let mut command = Command::new(rustfmt_path)
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()?;
+ let stdin = command.stdin.take().unwrap();
+ let reader_thread = thread::spawn(move || -> io::Result<(String, Child)> {
+ let mut output = String::new();
+ command.stdout.take().unwrap().read_to_string(&mut output)?;
+ Ok((output, command))
+ });
+ { stdin }.write_all(source.as_bytes())?;
+ let (output, mut command) = reader_thread.join().unwrap()?;
+ let exit_status = command.wait()?;
+ if exit_status.success() {
+ Ok(Cow::Owned(output))
+ } else {
+ Err(FormatError::RustFmtFailed(exit_status))
+ }
+}
+
+fn remove_initial_op(name: &str) -> &str {
+ const INITIAL_OP: &str = "Op";
+ assert!(name.starts_with(INITIAL_OP));
+ &name[INITIAL_OP.len()..]
+}
+
+fn new_id<T: AsRef<str>>(name: T, name_format: util::NameFormat) -> proc_macro2::Ident {
+ proc_macro2::Ident::new(
+ &name_format
+ .name_from_words(util::WordIterator::new(name.as_ref()))
+ .unwrap(),
+ proc_macro2::Span::call_site(),
+ )
+}
+
+fn new_enumerant_id<T1: AsRef<str>, T2: AsRef<str>>(
+ enum_name: T1,
+ enumerant_name: T2,
+) -> proc_macro2::Ident {
+ let enumerant_name_words = util::WordIterator::new(enumerant_name.as_ref());
+ let enumerant_name_first_word = enumerant_name_words.clone().next();
+ let name = if enumerant_name_first_word
+ .map(str::chars)
+ .as_mut()
+ .and_then(Iterator::next)
+ .filter(char::is_ascii_digit)
+ .is_some()
+ {
+ CamelCase
+ .name_from_words(
+ util::WordIterator::new(enum_name.as_ref()).chain(enumerant_name_words),
+ )
+ .unwrap()
+ } else {
+ CamelCase.name_from_words(enumerant_name_words).unwrap()
+ };
+ proc_macro2::Ident::new(&name, proc_macro2::Span::call_site())
+}
+
+fn new_combined_id<I: IntoIterator>(names: I, name_format: util::NameFormat) -> proc_macro2::Ident
+where
+ I::Item: AsRef<str>,
+{
+ let names: Vec<I::Item> = names.into_iter().collect();
+ proc_macro2::Ident::new(
+ &name_format
+ .name_from_words(
+ names
+ .iter()
+ .map(AsRef::as_ref)
+ .flat_map(util::WordIterator::new),
+ )
+ .unwrap(),
+ proc_macro2::Span::call_site(),
+ )
+}
+
+#[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
+pub(crate) fn generate(
+ core_grammar: ast::CoreGrammar,
+ parsed_extension_instruction_sets: HashMap<
+ super::ExtensionInstructionSet,
+ ast::ExtensionInstructionSet,
+ >,
+ options: &Options,
+) -> Result<String, Error> {
+ let mut out = Vec::new();
+ let ast::CoreGrammar {
+ copyright: core_grammar_copyright,
+ magic_number,
+ major_version,
+ minor_version,
+ revision: core_revision,
+ instructions: core_instructions,
+ operand_kinds,
+ } = core_grammar;
+ writeln!(&mut out, "// automatically generated file")?;
+ writeln!(&mut out, "//")?;
+ for i in &core_grammar_copyright {
+ assert_eq!(i.find('\r'), None);
+ assert_eq!(i.find('\n'), None);
+ if i == "" {
+ writeln!(&mut out, "//");
+ } else {
+ writeln!(&mut out, "// {}", i);
+ }
+ }
+ writeln!(
+ &mut out,
+ "{}",
+ quote!{
+ pub const MAGIC_NUMBER: u32 = #magic_number;
+ pub const MAJOR_VERSION: u32 = #major_version;
+ pub const MINOR_VERSION: u32 = #minor_version;
+ pub const REVISION: u32 = #core_revision;
+ }
+ )?;
+ for operand_kind in &operand_kinds {
+ match operand_kind {
+ ast::OperandKind::BitEnum { kind, enumerants } => {
+ let mut enumerant_members = Vec::new();
+ let mut enumerant_member_names = Vec::new();
+ let mut enumerant_items = Vec::new();
+ for enumerant in enumerants {
+ if enumerant.value.0 == 0 {
+ continue;
+ }
+ let member_name = new_id(&enumerant.enumerant, SnakeCase);
+ enumerant_member_names.push(member_name.clone());
+ let type_name =
+ new_combined_id(&[kind.as_ref(), &enumerant.enumerant], CamelCase);
+ if enumerant.parameters.is_empty() {
+ enumerant_items.push(quote!{
+ #[derive(Clone, Debug, Default)]
+ pub struct #type_name;
+ });
+ } else {
+ let parameters = enumerant.parameters.iter().map(|parameter| {
+ let kind = new_id(¶meter.kind, CamelCase);
+ quote!{
+ pub #kind,
+ }
+ });
+ enumerant_items.push(quote!{
+ #[derive(Clone, Debug, Default)]
+ pub struct #type_name(#(#parameters)*);
+ });
+ }
+ enumerant_members.push(quote!{
+ pub #member_name: Option<#type_name>
+ });
+ }
+ let kind_id = new_id(kind, CamelCase);
+ writeln!(
+ &mut out,
+ "{}",
+ quote!{
+ #[derive(Clone, Debug, Default)]
+ pub struct #kind_id {
+ #(#enumerant_members),*
+ }
+ impl #kind_id {
+ pub fn new() -> Self {
+ Self {
+ #(#enumerant_member_names: None,)*
+ }
+ }
+ }
+ #(#enumerant_items)*
+ }
+ )?;
+ }
+ ast::OperandKind::ValueEnum { kind, enumerants } => {
+ let kind_id = new_id(&kind, CamelCase);
+ let mut generated_enumerants = Vec::new();
+ for enumerant in enumerants {
+ let name = new_enumerant_id(&kind, &enumerant.enumerant);
+ if enumerant.parameters.is_empty() {
+ generated_enumerants.push(quote!{#name});
+ continue;
+ }
+ }
+ writeln!(
+ &mut out,
+ "{}",
+ quote!{
+ #[derive(Clone, Debug)]
+ pub enum #kind_id {
+ #(#generated_enumerants,)*
+ }
+ }
+ )?;
+ }
+ ast::OperandKind::Id { kind, doc: _ } => {
+ let base = if *kind == ast::Kind::IdRef {
+ quote!{u32}
+ } else {
+ quote!{IdRef}
+ };
+ let kind_id = new_id(kind, CamelCase);
+ writeln!(
+ &mut out,
+ "{}",
+ quote!{
+ #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
+ #[repr(transparent)]
+ pub struct #kind_id(pub #base);
+ }
+ )?;
+ }
+ ast::OperandKind::Literal { kind, doc: _ } => {
+ let kind_id = new_id(kind, CamelCase);
+ writeln!(
+ &mut out,
+ "{}",
+ match kind {
+ ast::LiteralKind::LiteralInteger
+ | ast::LiteralKind::LiteralContextDependentNumber => unreachable!(),
+ ast::LiteralKind::LiteralInteger32
+ | ast::LiteralKind::LiteralContextDependentNumber32 => {
+ quote!{pub type #kind_id = u32;}
+ }
+ ast::LiteralKind::LiteralInteger64
+ | ast::LiteralKind::LiteralContextDependentNumber64 => {
+ quote!{pub type #kind_id = u64;}
+ }
+ ast::LiteralKind::LiteralString => quote!{pub type #kind_id = String;},
+ ast::LiteralKind::LiteralExtInstInteger => {
+ quote!{pub type #kind_id = u32;}
+ }
+ ast::LiteralKind::LiteralSpecConstantOpInteger => continue,
+ }
+ )?;
+ }
+ ast::OperandKind::Composite { kind, bases } => {
+ let kind = new_id(kind, CamelCase);
+ let bases = bases.into_iter().map(|base| new_id(base, CamelCase));
+ writeln!(&mut out, "{}", quote!{pub type #kind = (#(#bases),*);})?;
+ }
+ }
+ }
+ {
+ let mut instruction_enumerants = Vec::new();
+ let mut spec_constant_op_instruction_enumerants = Vec::new();
+ for instruction in core_instructions.iter() {
+ let opname = new_id(remove_initial_op(instruction.opname.as_ref()), CamelCase);
+ let instruction_enumerant =
+ if instruction.opname == ast::InstructionName::OpSpecConstantOp {
+ quote!{
+ #opname {
+ operation: OpSpecConstantOp,
+ }
+ }
+ } else if instruction.operands.is_empty() {
+ quote!{#opname}
+ } else {
+ let mut fields = Vec::new();
+ for operand in instruction.operands.iter() {
+ let kind = new_id(&operand.kind, CamelCase);
+ let name = new_id(operand.name.as_ref().unwrap(), SnakeCase);
+ let kind = match &operand.quantifier {
+ None => quote!{#kind},
+ Some(ast::Quantifier::Optional) => quote!{Option<#kind>},
+ Some(ast::Quantifier::Variadic) => quote!{Vec<#kind>},
+ };
+ fields.push(quote!{#name: #kind});
+ }
+ quote!{
+ #opname {
+ #(#fields,)*
+ }
+ }
+ };
+ if ast::OP_SPEC_CONSTANT_OP_SUPPORTED_INSTRUCTIONS.contains(&instruction.opname) {
+ spec_constant_op_instruction_enumerants.push(instruction_enumerant.clone());
+ }
+ instruction_enumerants.push(instruction_enumerant);
+ }
+ writeln!(
+ &mut out,
+ "{}",
+ quote!{
+ #[derive(Clone, Debug)]
+ pub enum OpSpecConstantOp {
+ #(#spec_constant_op_instruction_enumerants,)*
+ }
+ #[derive(Clone, Debug)]
+ pub enum Instruction {
+ #(#instruction_enumerants,)*
+ }
+ }
+ )?;
+ }
+ let source = String::from_utf8(out).unwrap();
+ let source = match format_source(&options, &source) {
+ Ok(source) => source.into_owned(),
+ Err(error) => {
+ eprintln!("formatting source failed: {}", error);
+ source.clone()
+ }
+ };
+ Ok(source)
+}