machine_check_bitmask_switch/
lib.rs1#![doc = include_str!("../README.md")]
2
3extern crate proc_macro;
4
5mod arm;
6mod types;
7mod util;
8
9use arm::process_arms;
10pub use types::{BitmaskArm, BitmaskArmChoice, BitmaskSwitch};
11
12use num::BigUint;
13use proc_macro2::{Span, TokenStream};
14use quote::quote;
15use syn::spanned::Spanned;
16use syn::token::Brace;
17use syn::{parse2, Block, Ident, Local, LocalInit, Pat, PatIdent, Stmt, Token};
18use util::{convert_type, create_number_expr};
19
20pub fn process(stream: TokenStream) -> Result<TokenStream, Error> {
21 let switch: BitmaskSwitch = parse2(stream).map_err(Error::Parse)?;
22 generate(switch)
23}
24
25#[derive(Debug)]
26pub enum Error {
27 Parse(syn::parse::Error),
28 Process(String, Span),
29}
30
31impl Error {
32 pub fn msg(&self) -> String {
33 match self {
34 Error::Parse(error) => error.to_string(),
35 Error::Process(msg, _span) => msg.clone(),
36 }
37 }
38}
39
40pub fn generate(switch: BitmaskSwitch) -> Result<TokenStream, Error> {
41 let scrutinee_span = switch.expr.span();
42 let scrutinee_ident = Ident::new("__scrutinee", Span::mixed_site());
44 let something_taken_ident = Ident::new("__something_taken", Span::mixed_site());
45
46 let (arm_stmts, num_bits) = process_arms(
50 scrutinee_ident.clone(),
51 something_taken_ident.clone(),
52 switch.arms,
53 switch.brace_token.span.span(),
54 )?;
55
56 let scrutinee_local = Stmt::Local(Local {
58 attrs: vec![],
59 let_token: Token,
60 pat: Pat::Ident(PatIdent {
61 attrs: vec![],
62 by_ref: None,
63 mutability: None,
64 ident: scrutinee_ident,
65 subpat: None,
66 }),
67 init: Some(LocalInit {
68 eq_token: Token,
69 expr: Box::new(convert_type(*switch.expr, num_bits, scrutinee_span, true)),
70 diverge: None,
71 }),
72 semi_token: Token,
73 });
74 let something_taken_local = Stmt::Local(Local {
75 attrs: vec![],
76 let_token: Token,
77 pat: Pat::Ident(PatIdent {
78 attrs: vec![],
79 by_ref: None,
80 mutability: Some(Token),
81 ident: something_taken_ident,
82 subpat: None,
83 }),
84 init: Some(LocalInit {
85 eq_token: Token,
86 expr: Box::new(create_number_expr(&BigUint::from(0u8), 1, scrutinee_span)),
87 diverge: None,
88 }),
89 semi_token: Token,
90 });
91
92 let mut outer_block = Block {
94 brace_token: Brace {
95 span: switch.brace_token.span,
96 },
97 stmts: vec![scrutinee_local, something_taken_local],
98 };
99
100 outer_block.stmts.extend(arm_stmts);
101
102 let expanded = quote! {
103 #outer_block
104 };
105
106 Ok(expanded)
107}