diff --git a/bit-wrap/src/ast.rs b/bit-wrap/src/ast.rs index 3ac5dfe..94bc441 100644 --- a/bit-wrap/src/ast.rs +++ b/bit-wrap/src/ast.rs @@ -2,33 +2,17 @@ use crate::grammar; use unsynn::*; pub struct Struct { - pub attr: Attribute, + pub bit_width: u128, + pub error_type: Ident, pub name: Ident, pub body: Ident, } -impl Struct { - pub fn bit_width(&self) -> u128 { - self.attr.bit_width - } -} - -pub struct Attribute { - pub bit_width: u128, -} - -impl From for Attribute { - fn from(value: grammar::Attribute) -> Self { - Self { - bit_width: value.bit_width.content.bit_width.content.value(), - } - } -} - impl From for Struct { fn from(value: grammar::StructDef) -> Self { Self { - attr: value.attr.into(), + bit_width: value.bit_width.bit_width.content.width.content.value(), + error_type: value.error_type.error.content.error.content, name: value.name, body: value.body.content, } diff --git a/bit-wrap/src/bit_wrapper.rs b/bit-wrap/src/bit_wrapper.rs index 880e0e0..4eac0ee 100644 --- a/bit-wrap/src/bit_wrapper.rs +++ b/bit-wrap/src/bit_wrapper.rs @@ -2,6 +2,9 @@ use crate::{codegen::generate_impl, grammar::StructDef}; use unsynn::*; pub fn impl_bit_wrapper(input: &TokenStream) -> TokenStream { - let parsed = input.to_token_iter().parse::().unwrap(); + let parsed = input + .to_token_iter() + .parse::() + .expect("StructDef parsing"); generate_impl(&parsed.into()) } diff --git a/bit-wrap/src/codegen.rs b/bit-wrap/src/codegen.rs index 8f4bba9..f63c3d5 100644 --- a/bit-wrap/src/codegen.rs +++ b/bit-wrap/src/codegen.rs @@ -70,8 +70,9 @@ fn generate_bitwise_fmt(info: &Struct) -> TokenStream { fn generate_bitwise_ops(info: &Struct) -> TokenStream { let name = &info.name; let inner = &info.body; + let error_type = &info.error_type; - let bit_width = u8::try_from(info.bit_width()).expect("8-bit value"); + let bit_width = u8::try_from(info.bit_width).expect("8-bit value"); let hex_width = usize::from(bit_width.div_ceil(4)); let bin_width = usize::from(bit_width); @@ -91,7 +92,7 @@ fn generate_bitwise_ops(info: &Struct) -> TokenStream { /// Create a new [`Self`] from a key value #[inline] #[macro_use] - pub fn new(key: #inner) -> Result { + pub fn new(key: #inner) -> Result { key.try_into() } @@ -263,17 +264,17 @@ fn generate_bitwise_ops(info: &Struct) -> TokenStream { } /// Create from a hex string with bit width validation - pub fn from_hex(hex: &str) -> Result { - let value = #inner::from_str_radix(hex, 16).map_err(|e| format!("Invalid hex string: {e}"))?; + pub fn from_hex(hex: &str) -> Result { + let value = #inner::from_str_radix(hex, 16)?; let masked = value & Self::MAX; if value != masked { - return Err( - format!( - "Hex value 0x{value:X} exceeds {}-bit limit (masked to 0x{masked:0width$X})", - Self::BIT_WIDTH, width = #hex_width - ) - ) + return Err(#error_type::ExceedsBitLimit { + value, + bit_width: Self::BIT_WIDTH, + masked, + width: #hex_width + }) } Ok(Self(value)) diff --git a/bit-wrap/src/grammar.rs b/bit-wrap/src/grammar.rs index 9aa153a..c154790 100644 --- a/bit-wrap/src/grammar.rs +++ b/bit-wrap/src/grammar.rs @@ -4,12 +4,13 @@ keyword! { pub KwStruct = "struct"; pub KwPub = "pub"; pub KwBitWidth = "bit_width"; + pub KwError = "bit_conversion_error"; } unsynn! { - pub struct BitWidth{ + pub struct BitWidth { pub kw_bit_width: KwBitWidth, - pub bit_width: ParenthesisGroupContaining, + pub width: ParenthesisGroupContaining, } pub struct Attribute { @@ -17,8 +18,19 @@ unsynn! { pub bit_width: BracketGroupContaining, } + pub struct ErrorType { + pub kw_bit_width: KwError, + pub error: ParenthesisGroupContaining, + } + + pub struct AttributeError { + pub pound: Pound, + pub error: BracketGroupContaining, + } + pub struct StructDef { - pub attr: Attribute, + pub bit_width: Attribute, + pub error_type: AttributeError, pub vis: Option, pub kw_struct: KwStruct, pub name: Ident, @@ -33,6 +45,7 @@ mod tests { const SAMPLE: &str = r#" #[bit_width(48)] + #[bit_conversion_error()] pub struct Subkey(u64); "#; diff --git a/bit-wrap/src/lib.rs b/bit-wrap/src/lib.rs index ff30cb0..0921da9 100644 --- a/bit-wrap/src/lib.rs +++ b/bit-wrap/src/lib.rs @@ -6,7 +6,7 @@ mod grammar; use crate::bit_wrapper::impl_bit_wrapper; use proc_macro::TokenStream; -#[proc_macro_derive(BitWrapper, attributes(bit_width))] +#[proc_macro_derive(BitWrapper, attributes(bit_width, bit_conversion_error))] pub fn derive_bit_wrapper(input: TokenStream) -> TokenStream { impl_bit_wrapper(&input.into()).into() }