msp430_rt_macros/
lib.rs

1extern crate proc_macro;
2extern crate proc_macro2;
3extern crate quote;
4extern crate rand;
5extern crate rand_xoshiro;
6extern crate syn;
7
8use proc_macro::TokenStream;
9use std::{
10    collections::HashSet,
11    sync::atomic::{AtomicUsize, Ordering},
12    time::{SystemTime, UNIX_EPOCH},
13};
14
15use proc_macro2::Span;
16use quote::{quote, quote_spanned};
17use rand::Rng;
18use rand_xoshiro::rand_core::SeedableRng;
19use syn::{
20    parenthesized,
21    parse::{self, Parse},
22    parse_macro_input,
23    punctuated::Punctuated,
24    spanned::Spanned,
25    FnArg, Ident, Item, ItemFn, ItemStatic, Pat, PatIdent, PathArguments, PathSegment, ReturnType,
26    Stmt, Token, Type, TypePath, Visibility,
27};
28
29/// Attribute to declare the entry point of the program
30///
31/// The specified function will be called by the reset handler *after* RAM has been initialized.
32///
33/// The type of the specified function must be `[unsafe] fn([<name>: CriticalSection]) -> !` (never
34/// ending function), where the `CriticalSection` argument is optional.
35///
36/// # Properties
37///
38/// The entry point will be called by the reset handler. The program can't reference to the entry
39/// point, much less invoke it.
40///
41/// `static mut` variables declared within the entry point are safe to access. The compiler can't
42/// prove this is safe so the attribute will help by making a transformation to the source code: for
43/// this reason a variable like `static mut FOO: u32` will become `let FOO: &'static mut u32;`. Note
44/// that `&'static mut` references have move semantics.
45///
46/// ## Examples
47///
48/// - Simple entry point
49///
50/// ``` no_run
51/// # #![no_main]
52/// # use msp430_rt_macros::entry;
53/// #[entry]
54/// fn main() -> ! {
55///     loop {
56///         /* .. */
57///     }
58/// }
59/// ```
60///
61/// - `static mut` variables local to the entry point are safe to modify.
62///
63/// ``` no_run
64/// # #![no_main]
65/// # use msp430_rt_macros::entry;
66/// #[entry]
67/// fn main(_cs: CriticalSection) -> ! {
68///     static mut FOO: u32 = 0;
69///
70///     let foo: &'static mut u32 = FOO;
71///     assert_eq!(*foo, 0);
72///     *foo = 1;
73///     assert_eq!(*foo, 1);
74///
75///     loop {
76///         /* .. */
77///     }
78/// }
79/// ```
80///
81/// # Pre-entry Interrupt Enable
82///
83/// If the argument `interrupt_enable` is passed into the macro, interrupts will be enabled
84/// globally before the entry function runs. If this is enabled then the entry function will no
85/// longer accept `CriticalSection` as a parameter, since that it will be unsound.
86///
87/// The macro can also take arguments of the form `interrupt_enable(pre_interrupt = <init>)`, where
88/// `init` is the name of a function with the signature `fn(cs: CriticalSection) -> <Type>`.  The
89/// entry function can then optionally take a parameter of `Type`. This makes `init` run before
90/// interrupts are enabled and possibly pass its return value into the entry function, allowing
91/// pre-interrupt initialization to be done.
92///
93/// Note that a function marked with the entry attribute is allowed to take no input parameters
94/// even if `init` returns a value, due to implementation details. To reduce code size, it is
95/// strongly recommended to put `#[inline(always)]` on `init` if it's used nowhere else.
96///
97/// ## Examples
98///
99/// - Enable interrupts before entry
100///
101/// ``` no_run
102/// # #![no_main]
103/// # use msp430_rt_macros::entry;
104/// #[entry(interrupt_enable)]
105/// fn main() -> ! {
106///     /* interrupts now enabled */
107///     loop {}
108/// }
109/// ```
110///
111/// - Pre-interrupt initialization
112///
113/// ``` no_run
114/// # #![no_main]
115/// # use msp430_rt_macros::entry;
116/// use msp430::interrupt::CriticalSection;
117///
118/// # struct Hal;
119/// #[inline(always)]
120/// fn init(cs: CriticalSection) -> Hal {
121///     /* initialize hardware */
122///     # Hal
123/// }
124///
125/// #[entry(interrupt_enable(pre_interrupt = init))]
126/// fn main(hal: Hal) -> ! {
127///     loop {
128///         /* do something with hal */
129///     }
130/// }
131/// ```
132///
133/// - Pre-interrupt initialization with no return
134///
135/// ``` no_run
136/// # #![no_main]
137/// # use msp430_rt_macros::entry;
138/// use msp430::interrupt::CriticalSection;
139///
140/// #[inline(always)]
141/// fn arg(cs: CriticalSection) {
142///     /* initialize */
143/// }
144///
145/// #[entry(interrupt_enable(pre_interrupt = arg))]
146/// fn main() -> ! {
147///     loop {}
148/// }
149/// ```
150///
151/// ## Note
152///
153/// The `CriticalSection`s passed into the entry and the pre-interrupt functions have their
154/// lifetimes restrained to their respective functions. Attempting to pass the `CriticalSection`
155/// outside its scope fails with a `borrowed value does not live long enough` error.
156#[proc_macro_attribute]
157pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
158    let interrupt_enable = if args.is_empty() {
159        None
160    } else {
161        Some(parse_macro_input!(args as EntryInterruptEnable))
162    };
163
164    let f = parse_macro_input!(input as ItemFn);
165
166    // check the function signature
167    let valid_signature = f.sig.constness.is_none()
168        && f.vis == Visibility::Inherited
169        && f.sig.abi.is_none()
170        && f.sig.generics.params.is_empty()
171        && f.sig.generics.where_clause.is_none()
172        && f.sig.variadic.is_none()
173        && match f.sig.output {
174            ReturnType::Default => false,
175            ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)),
176        };
177
178    let pair = match &interrupt_enable {
179        Some(interrupt_enable) => interrupt_enable.extract_init_arg(&f.sig.inputs),
180        None => extract_critical_section_arg(&f.sig.inputs),
181    };
182
183    if let (true, Ok(ParamArgPair { fn_param, fn_arg })) = (valid_signature, pair) {
184        // XXX should we blacklist other attributes?
185        let attrs = f.attrs;
186        let unsafety = f.sig.unsafety;
187        let hash = random_ident();
188        let (statics, stmts) = match extract_static_muts(f.block.stmts) {
189            Err(e) => return e.to_compile_error().into(),
190            Ok(x) => x,
191        };
192
193        let vars = statics
194            .into_iter()
195            .map(|var| {
196                let attrs = var.attrs;
197                let ident = var.ident;
198                let ty = var.ty;
199                let expr = var.expr;
200
201                quote!(
202                    #[allow(non_snake_case)]
203                    let #ident: &'static mut #ty = unsafe {
204                        #(#attrs)*
205                        static mut #ident: #ty = #expr;
206
207                        &mut #ident
208                    };
209                )
210            })
211            .collect::<Vec<_>>();
212
213        // Only generate the argument if fn_param exists, to handle the case where the argument
214        // expression does exist but the entry function doesn't accept any args
215        let arg_ident = fn_param
216            .as_ref()
217            .map(|_| Ident::new("arg", Span::mixed_site()));
218        let arg_def = fn_arg
219            .as_ref()
220            .map(|arg| quote_spanned!(Span::mixed_site()=> let arg = #arg; ));
221
222        quote!(
223            #[export_name = "main"]
224            #(#attrs)*
225            pub #unsafety fn #hash() -> ! {
226                #[inline(always)]
227                #unsafety fn #hash<'a>(#fn_param) -> ! {
228                    #(#vars)*
229                    #(#stmts)*
230                }
231                #arg_def
232                { #hash(#arg_ident) }
233            }
234        )
235        .into()
236    } else {
237        let err = match interrupt_enable {
238            None => parse::Error::new(
239                f.sig.span(),
240                "`#[entry]` function must have signature `[unsafe] fn([<ident> : CriticalSection]) -> !`",
241            ),
242            Some(EntryInterruptEnable { pre_interrupt: None }) => parse::Error::new(
243                f.sig.span(),
244                "`#[entry(interrupt_enable)]` function must have signature `[unsafe] fn() -> !`",
245            ),
246            Some(EntryInterruptEnable { pre_interrupt: Some(ident) }) => parse::Error::new(
247                f.sig.span(),
248                format!("`#[entry(interrupt_enable(pre_interrupt = {fname}))]` function must have signature `[unsafe] fn([<ident> : <Type>]) -> !`, where <Type> is the return value of {fname}", fname = ident)
249            ),
250        };
251        err.to_compile_error().into()
252    }
253}
254
255#[derive(Default)]
256struct ParamArgPair {
257    fn_param: Option<proc_macro2::TokenStream>,
258    fn_arg: Option<proc_macro2::TokenStream>,
259}
260
261struct EntryInterruptEnable {
262    pre_interrupt: Option<Ident>,
263}
264
265impl Parse for EntryInterruptEnable {
266    fn parse(input: parse::ParseStream) -> syn::Result<Self> {
267        let interrupt_enable = input.parse::<Ident>()?;
268        if interrupt_enable != "interrupt_enable" {
269            return Err(parse::Error::new(
270                interrupt_enable.span(),
271                "expected `interrupt_enable` or no arguments at all",
272            ));
273        }
274        let pre_interrupt = if input.peek(syn::token::Paren) {
275            let inner;
276            parenthesized!(inner in input);
277            let pre_interrupt = inner.parse::<Ident>()?;
278            if pre_interrupt != "pre_interrupt" {
279                return Err(parse::Error::new(
280                    pre_interrupt.span(),
281                    "expected `pre_interrupt`",
282                ));
283            }
284            inner.parse::<syn::token::Eq>()?;
285            Some(inner.parse::<Ident>()?)
286        } else {
287            None
288        };
289
290        Ok(EntryInterruptEnable { pre_interrupt })
291    }
292}
293
294impl EntryInterruptEnable {
295    fn extract_init_arg(&self, list: &Punctuated<FnArg, Token![,]>) -> Result<ParamArgPair, ()> {
296        if let Some(fn_name) = &self.pre_interrupt {
297            let hash = random_ident();
298            let fn_arg = Some(quote_spanned!(Span::mixed_site()=> {
299                let cs = unsafe { msp430::interrupt::CriticalSection::new() };
300
301                // This struct forces the lifetime of the CriticalSection to match the lifetime of
302                // the reference. Since the reference lifetime is restricted to this scope, the
303                // compiler has to constrain the lifetime of the CriticalSection as well,
304                // preventing the CriticalSection from being leaked as a return value.
305                #[allow(non_camel_case_types)]
306                struct #hash<'a>(&'a msp430::interrupt::CriticalSection<'a>);
307                let arg = #fn_name(*#hash(&cs).0);
308
309                unsafe { msp430::interrupt::enable() };
310                arg
311            }));
312
313            if let Some(first) = list.first() {
314                if let FnArg::Typed(pat_type) = first {
315                    // Case where pre-init exists and entry takes a param
316                    return Ok(ParamArgPair {
317                        fn_param: Some(quote! { #pat_type }),
318                        fn_arg,
319                    });
320                }
321            } else {
322                // Case where pre-init exists but entry takes no params
323                return Ok(ParamArgPair {
324                    fn_param: None,
325                    fn_arg,
326                });
327            }
328        } else if list.is_empty() {
329            // Case where pre-init doesn't exist and entry takes no params
330            return Ok(ParamArgPair {
331                fn_param: None,
332                fn_arg: Some(quote!({
333                    unsafe { msp430::interrupt::enable() };
334                })),
335            });
336        }
337        Err(())
338    }
339}
340
341/// Attribute to declare an interrupt handler
342///
343/// When the `device` feature is disabled this attribute can only be used to override the
344/// DefaultHandler.
345///
346/// When the `device` feature is enabled this attribute can be used to override other interrupt
347/// handlers but only when imported from a PAC (Peripheral Access Crate) crate which re-exports it.
348/// Importing this attribute from the `msp430-rt` crate and using it on a function will result in a
349/// compiler error.
350///
351/// # Syntax
352///
353/// ``` ignore
354/// extern crate device;
355///
356/// // the attribute comes from the device crate not from msp430-rt
357/// use device::interrupt;
358///
359/// #[interrupt]
360/// // Pass in optional CriticalSection
361/// fn USART1(cs: CriticalSection) {
362///     // ..
363/// }
364/// ```
365///
366/// where the name of the function must be `DefaultHandler` or one of the device interrupts.
367///
368/// # Usage
369///
370/// `#[interrupt] fn Name(..` overrides the default handler for the interrupt with the given `Name`.
371/// These handlers must have signature `[unsafe] fn([<name>: CriticalSection]) [-> !]`. It's
372/// possible to add state to these handlers by declaring `static mut` variables at the beginning of
373/// the body of the function. These variables will be safe to access from the function body.
374///
375/// If the interrupt handler has not been overridden it will be dispatched by the default interrupt
376/// handler (`DefaultHandler`).
377///
378/// `#[interrupt] fn DefaultHandler(..` can be used to override the default interrupt handler. When
379/// not overridden `DefaultHandler` defaults to an infinite loop.
380///
381/// `#[interrupt(wake_cpu)]` additionally returns the CPU to active mode after the interrupt
382/// returns. This cannot be done by naively writing to the status register, as the status register
383/// contents are pushed to the stack before an interrupt begins and this value is loaded back into
384/// the status register after an interrupt completes, effectively making any changes to the status
385/// register within an interrupt temporary.
386/// Using the `wake_cpu` variant incurs a delay of two instructions (6 cycles) before the interrupt
387/// handler begins.
388/// The following status register bits are cleared: SCG1, SCG0, OSC_OFF and CPU_OFF.
389///
390/// # Properties
391///
392/// Interrupts handlers can only be called by the hardware. Other parts of the program can't refer
393/// to the interrupt handlers, much less invoke them as if they were functions.
394///
395/// `static mut` variables declared within an interrupt handler are safe to access and can be used
396/// to preserve state across invocations of the handler. The compiler can't prove this is safe so
397/// the attribute will help by making a transformation to the source code: for this reason a
398/// variable like `static mut FOO: u32` will become `let FOO: &mut u32;`.
399///
400/// ## Examples
401///
402/// - Using state within an interrupt handler
403///
404/// ``` ignore
405/// extern crate device;
406///
407/// use device::interrupt;
408///
409/// #[interrupt]
410/// fn TIM2() {
411///     static mut COUNT: i32 = 0;
412///
413///     // `COUNT` is safe to access and has type `&mut i32`
414///     *COUNT += 1;
415///
416///     println!("{}", COUNT);
417/// }
418/// ```
419///
420/// ## Note
421///
422/// The `CriticalSection` passed into the interrupt function has its lifetime restrained to the
423/// function scope. Attempting to pass the `CriticalSection` outside its scope fails with a
424/// `borrowed value does not live long enough` error.
425#[proc_macro_attribute]
426pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
427    let f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
428
429    let maybe_arg = parse_macro_input::parse::<Option<Ident>>(args.clone());
430
431    let wake_cpu = match maybe_arg {
432        Ok(None) => false,
433        Ok(Some(ident)) if ident == "wake_cpu" => true,
434        Ok(Some(_)) => {
435            return parse::Error::new(
436                Span::call_site(),
437                "this attribute accepts only 'wake_cpu' as an argument",
438            )
439            .to_compile_error()
440            .into()
441        }
442        Err(e) => return e.into_compile_error().into(),
443    };
444
445    let fspan = f.sig.span();
446    let ident = f.sig.ident;
447
448    let check = if ident == "DefaultHandler" {
449        None
450    } else if cfg!(feature = "device") {
451        Some(quote!(interrupt::#ident;))
452    } else {
453        return parse::Error::new(
454            ident.span(),
455            "only the DefaultHandler can be overridden when the `device` feature is disabled",
456        )
457        .to_compile_error()
458        .into();
459    };
460
461    // XXX should we blacklist other attributes?
462    let attrs = f.attrs;
463    let block = f.block;
464    let stmts = block.stmts;
465    let unsafety = f.sig.unsafety;
466
467    let valid_signature = f.sig.constness.is_none()
468        && f.vis == Visibility::Inherited
469        && f.sig.abi.is_none()
470        && f.sig.generics.params.is_empty()
471        && f.sig.generics.where_clause.is_none()
472        && f.sig.variadic.is_none()
473        && match f.sig.output {
474            ReturnType::Default => true,
475            ReturnType::Type(_, ref ty) => match **ty {
476                Type::Tuple(ref tuple) => tuple.elems.is_empty(),
477                Type::Never(..) => true,
478                _ => false,
479            },
480        };
481
482    let pair = extract_critical_section_arg(&f.sig.inputs);
483
484    if let (true, Ok(ParamArgPair { fn_arg, fn_param })) = (valid_signature, pair) {
485        let (statics, stmts) = match extract_static_muts(stmts) {
486            Err(e) => return e.to_compile_error().into(),
487            Ok(x) => x,
488        };
489
490        let vars = statics
491            .into_iter()
492            .map(|var| {
493                let attrs = var.attrs;
494                let ident = var.ident;
495                let ty = var.ty;
496                let expr = var.expr;
497
498                quote!(
499                    #[allow(non_snake_case)]
500                    let #ident: &mut #ty = unsafe {
501                        #(#attrs)*
502                        static mut #ident: #ty = #expr;
503
504                        &mut #ident
505                    };
506                )
507            })
508            .collect::<Vec<_>>();
509
510        let output = f.sig.output;
511        let hash = random_ident();
512        let ident = ident.to_string();
513        if wake_cpu {
514            quote!(
515                #[export_name = #ident]
516                #(#attrs)*
517                #[unsafe(naked)]
518                unsafe extern "msp430-interrupt" fn #hash() {
519                    #[inline(always)]
520                    #unsafety extern "msp430-interrupt" fn #hash<'a>(#fn_param) #output {
521                        #check
522                        #(#vars)*
523                        #(#stmts)*
524                    }
525                    {
526                        // Clear SCG1, SCG0, OSC_OFF, CPU_OFF in saved copy of SR register on stack
527                        const MASK: u8 = (1<<7) + (1<<6) + (1<<5) + (1<<4);
528                        core::arch::naked_asm!(
529                            "bic.b #{mask}, 0(r1)",
530                            "jmp {inner}",
531                            inner = sym #hash,
532                            mask = const MASK
533                        );
534                    }
535                }
536            )
537        } else {
538            quote!(
539                #[export_name = #ident]
540                #(#attrs)*
541                #unsafety extern "msp430-interrupt" fn #hash() {
542                    #check
543
544                    #[inline(always)]
545                    #unsafety fn #hash<'a>(#fn_param) #output {
546                        #(#vars)*
547                        #(#stmts)*
548                    }
549                    { #hash(#fn_arg) }
550                }
551            )
552        }.into()
553    } else {
554        parse::Error::new(
555            fspan,
556            "`#[interrupt]` handlers must have signature `[unsafe] fn([<name>: CriticalSection]) [-> !]`",
557        )
558        .to_compile_error()
559        .into()
560    }
561}
562
563/// Attribute to mark which function will be called at the beginning of the reset handler.
564///
565/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph.
566///
567/// The function must have the signature of `unsafe fn()`.
568///
569/// The function passed will be called before static variables are initialized. Any access of static
570/// variables will result in undefined behavior.
571///
572/// ## Examples
573///
574/// ```
575/// # use msp430_rt_macros::pre_init;
576/// #[pre_init]
577/// unsafe fn before_main() {
578///     // do something here
579/// }
580///
581/// # fn main() {}
582/// ```
583#[proc_macro_attribute]
584pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
585    let f = parse_macro_input!(input as ItemFn);
586
587    // check the function signature
588    let valid_signature = f.sig.constness.is_none()
589        && f.vis == Visibility::Inherited
590        && f.sig.unsafety.is_some()
591        && f.sig.abi.is_none()
592        && f.sig.inputs.is_empty()
593        && f.sig.generics.params.is_empty()
594        && f.sig.generics.where_clause.is_none()
595        && f.sig.variadic.is_none()
596        && match f.sig.output {
597            ReturnType::Default => true,
598            ReturnType::Type(_, ref ty) => match **ty {
599                Type::Tuple(ref tuple) => tuple.elems.is_empty(),
600                _ => false,
601            },
602        };
603
604    if !valid_signature {
605        return parse::Error::new(
606            f.sig.span(),
607            "`#[pre_init]` function must have signature `unsafe fn()`",
608        )
609        .to_compile_error()
610        .into();
611    }
612
613    if !args.is_empty() {
614        return parse::Error::new(Span::call_site(), "this attribute accepts no arguments")
615            .to_compile_error()
616            .into();
617    }
618
619    // XXX should we blacklist other attributes?
620    let attrs = f.attrs;
621    let ident = f.sig.ident;
622    let block = f.block;
623
624    quote!(
625        #[export_name = "__pre_init"]
626        #(#attrs)*
627        pub unsafe fn #ident() #block
628    )
629    .into()
630}
631
632// Parses an optional `<name>: CriticalSection` from a list of function arguments.
633// Additional arguments are considered invalid
634fn extract_critical_section_arg(list: &Punctuated<FnArg, Token![,]>) -> Result<ParamArgPair, ()> {
635    let num_args = list.len();
636    if num_args == 0 {
637        return Ok(ParamArgPair::default());
638    } else if num_args == 1 {
639        if let FnArg::Typed(pat_type) = list.first().unwrap() {
640            if let (
641                Pat::Ident(PatIdent {
642                    ident: name,
643                    by_ref: None,
644                    mutability: None,
645                    subpat: None,
646                    attrs,
647                }),
648                Type::Path(TypePath { qself: None, path }),
649                _,
650                [],
651            ) = (
652                &*pat_type.pat,
653                &*pat_type.ty,
654                pat_type.colon_token,
655                &*pat_type.attrs,
656            ) {
657                if path.segments.len() == 1 && attrs.is_empty() {
658                    let seg = path.segments.first().unwrap();
659                    if matches!(
660                        seg,
661                        PathSegment {
662                            ident,
663                            arguments: PathArguments::None,
664                        } if ident == "CriticalSection"
665                    ) {
666                        return Ok(ParamArgPair {
667                            fn_param: Some(
668                                quote! { #name: msp430::interrupt::CriticalSection<'a> },
669                            ),
670                            fn_arg: Some(
671                                quote! { unsafe { msp430::interrupt::CriticalSection::new() } },
672                            ),
673                        });
674                    }
675                }
676            }
677        }
678    }
679    Err(())
680}
681
682// Creates a random identifier
683fn random_ident() -> Ident {
684    static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
685
686    let secs = SystemTime::now()
687        .duration_since(UNIX_EPOCH)
688        .unwrap()
689        .as_secs();
690
691    let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
692    let mut seed: [u8; 16] = [0; 16];
693
694    for (i, v) in seed.iter_mut().take(8).enumerate() {
695        *v = ((secs >> (i * 8)) & 0xFF) as u8
696    }
697
698    for (i, v) in seed.iter_mut().skip(8).enumerate() {
699        *v = ((count >> (i * 8)) & 0xFF) as u8
700    }
701
702    let mut rng = rand_xoshiro::Xoshiro128PlusPlus::from_seed(seed);
703    Ident::new(
704        &(0..16)
705            .map(|i| {
706                if i == 0 || rng.gen() {
707                    (b'a' + rng.gen::<u8>() % 25) as char
708                } else {
709                    (b'0' + rng.gen::<u8>() % 10) as char
710                }
711            })
712            .collect::<String>(),
713        Span::call_site(),
714    )
715}
716
717/// Extracts `static mut` vars from the beginning of the given statements
718fn extract_static_muts(stmts: Vec<Stmt>) -> Result<(Vec<ItemStatic>, Vec<Stmt>), parse::Error> {
719    let mut istmts = stmts.into_iter();
720
721    let mut seen = HashSet::new();
722    let mut statics = vec![];
723    let mut stmts = vec![];
724    for stmt in istmts.by_ref() {
725        match stmt {
726            Stmt::Item(Item::Static(var)) => {
727                if var.mutability.is_some() {
728                    if seen.contains(&var.ident) {
729                        return Err(parse::Error::new(
730                            var.ident.span(),
731                            format!("the name `{}` is defined multiple times", var.ident),
732                        ));
733                    }
734
735                    seen.insert(var.ident.clone());
736                    statics.push(var);
737                } else {
738                    stmts.push(Stmt::Item(Item::Static(var)));
739                }
740            }
741            _ => {
742                stmts.push(stmt);
743                break;
744            }
745        }
746    }
747
748    stmts.extend(istmts);
749
750    Ok((statics, stmts))
751}