feat: add error type

This commit is contained in:
Kristofers Solo 2025-10-04 17:02:25 +03:00
parent d362a7df3a
commit b8b963455d
Signed by: kristoferssolo
GPG Key ID: 8687F2D3EEE6F0ED
5 changed files with 36 additions and 35 deletions

View File

@ -2,33 +2,17 @@ use crate::grammar;
use unsynn::*; use unsynn::*;
pub struct Struct { pub struct Struct {
pub attr: Attribute, pub bit_width: u128,
pub error_type: Ident,
pub name: Ident, pub name: Ident,
pub body: 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<grammar::Attribute> for Attribute {
fn from(value: grammar::Attribute) -> Self {
Self {
bit_width: value.bit_width.content.bit_width.content.value(),
}
}
}
impl From<grammar::StructDef> for Struct { impl From<grammar::StructDef> for Struct {
fn from(value: grammar::StructDef) -> Self { fn from(value: grammar::StructDef) -> Self {
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, name: value.name,
body: value.body.content, body: value.body.content,
} }

View File

@ -2,6 +2,9 @@ use crate::{codegen::generate_impl, grammar::StructDef};
use unsynn::*; use unsynn::*;
pub fn impl_bit_wrapper(input: &TokenStream) -> TokenStream { pub fn impl_bit_wrapper(input: &TokenStream) -> TokenStream {
let parsed = input.to_token_iter().parse::<StructDef>().unwrap(); let parsed = input
.to_token_iter()
.parse::<StructDef>()
.expect("StructDef parsing");
generate_impl(&parsed.into()) generate_impl(&parsed.into())
} }

View File

@ -70,8 +70,9 @@ fn generate_bitwise_fmt(info: &Struct) -> TokenStream {
fn generate_bitwise_ops(info: &Struct) -> TokenStream { fn generate_bitwise_ops(info: &Struct) -> TokenStream {
let name = &info.name; let name = &info.name;
let inner = &info.body; 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 hex_width = usize::from(bit_width.div_ceil(4));
let bin_width = usize::from(bit_width); 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 /// Create a new [`Self`] from a key value
#[inline] #[inline]
#[macro_use] #[macro_use]
pub fn new(key: #inner) -> Result<Self, String> { pub fn new(key: #inner) -> Result<Self, #error_type> {
key.try_into() key.try_into()
} }
@ -263,17 +264,17 @@ fn generate_bitwise_ops(info: &Struct) -> TokenStream {
} }
/// Create from a hex string with bit width validation /// Create from a hex string with bit width validation
pub fn from_hex(hex: &str) -> Result<Self, String> { pub fn from_hex(hex: &str) -> Result<Self, #error_type> {
let value = #inner::from_str_radix(hex, 16).map_err(|e| format!("Invalid hex string: {e}"))?; let value = #inner::from_str_radix(hex, 16)?;
let masked = value & Self::MAX; let masked = value & Self::MAX;
if value != masked { if value != masked {
return Err( return Err(#error_type::ExceedsBitLimit {
format!( value,
"Hex value 0x{value:X} exceeds {}-bit limit (masked to 0x{masked:0width$X})", bit_width: Self::BIT_WIDTH,
Self::BIT_WIDTH, width = #hex_width masked,
) width: #hex_width
) })
} }
Ok(Self(value)) Ok(Self(value))

View File

@ -4,12 +4,13 @@ keyword! {
pub KwStruct = "struct"; pub KwStruct = "struct";
pub KwPub = "pub"; pub KwPub = "pub";
pub KwBitWidth = "bit_width"; pub KwBitWidth = "bit_width";
pub KwError = "bit_conversion_error";
} }
unsynn! { unsynn! {
pub struct BitWidth{ pub struct BitWidth {
pub kw_bit_width: KwBitWidth, pub kw_bit_width: KwBitWidth,
pub bit_width: ParenthesisGroupContaining<LiteralInteger>, pub width: ParenthesisGroupContaining<LiteralInteger>,
} }
pub struct Attribute { pub struct Attribute {
@ -17,8 +18,19 @@ unsynn! {
pub bit_width: BracketGroupContaining<BitWidth>, pub bit_width: BracketGroupContaining<BitWidth>,
} }
pub struct ErrorType {
pub kw_bit_width: KwError,
pub error: ParenthesisGroupContaining<Ident>,
}
pub struct AttributeError {
pub pound: Pound,
pub error: BracketGroupContaining<ErrorType>,
}
pub struct StructDef { pub struct StructDef {
pub attr: Attribute, pub bit_width: Attribute,
pub error_type: AttributeError,
pub vis: Option<KwPub>, pub vis: Option<KwPub>,
pub kw_struct: KwStruct, pub kw_struct: KwStruct,
pub name: Ident, pub name: Ident,
@ -33,6 +45,7 @@ mod tests {
const SAMPLE: &str = r#" const SAMPLE: &str = r#"
#[bit_width(48)] #[bit_width(48)]
#[bit_conversion_error()]
pub struct Subkey(u64); pub struct Subkey(u64);
"#; "#;

View File

@ -6,7 +6,7 @@ mod grammar;
use crate::bit_wrapper::impl_bit_wrapper; use crate::bit_wrapper::impl_bit_wrapper;
use proc_macro::TokenStream; 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 { pub fn derive_bit_wrapper(input: TokenStream) -> TokenStream {
impl_bit_wrapper(&input.into()).into() impl_bit_wrapper(&input.into()).into()
} }