Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

[wip] implement the new attribute syntax #313

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 9 additions & 6 deletions examples/cfg-static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ extern crate panic_halt;
use rt::{entry, exception};

#[entry]
fn main() -> ! {
fn main(
#[cfg(never)]
static mut COUNT: u32 = 0;

#[init(0)]
count: &mut u32,
) -> ! {
loop {}
}

#[exception]
fn SysTick() {
#[exception(SysTick)]
fn on_systick(
#[cfg(never)]
static mut FOO: u32 = 0;
#[init(0)]
foo: &mut u32,
) {
}
4 changes: 2 additions & 2 deletions examples/pre_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ extern crate panic_halt;

use rt::{entry, pre_init};

#[pre_init]
unsafe fn disable_watchdog() {
#[pre_init(unsafe)]
fn disable_watchdog() {
// Do what you need to disable the watchdog.
}

Expand Down
7 changes: 3 additions & 4 deletions examples/warnings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ extern crate panic_halt;

use cortex_m_rt::{entry, exception, interrupt, pre_init, ExceptionFrame};

#[allow(non_camel_case_types)]
enum interrupt {
enum Interrupt {
INT,
}

Expand All @@ -33,8 +32,8 @@ union Vector {
static __INTERRUPTS: [Vector; 1] = [Vector { handler: INT }];

/// Dummy interrupt.
#[interrupt]
fn INT() {}
#[interrupt(Interrupt::INT)]
fn interrupt_handler(#[init(0)] resource: &mut u8) {}

#[exception]
fn HardFault(_eh: &ExceptionFrame) -> ! {
Expand Down
141 changes: 141 additions & 0 deletions macros/src/codegen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::spanned::Spanned;

use crate::input::{
ExceptionArgs, ExceptionHandler, HandlerParamKind, InterruptArgs, ResourceParam, SimpleHandler,
};

/// Creates `static mut` items for every resource in `res`.
fn declare_resources<'a>(
res: impl Iterator<Item = &'a ResourceParam> + 'a,
) -> impl Iterator<Item = TokenStream> + 'a {
res.enumerate().map(|(i, res)| {
let init = &res.init;
let ty = &res.ty;
let name = Ident::new(&format!("RESOURCE_{}", i), init.span());
quote! {
static mut #name: #ty = #init;
}
})
}

/// Generates a list of expressions that refer to the resources in `res`.
fn resource_arguments<'a>(
res: impl Iterator<Item = &'a ResourceParam> + 'a,
) -> impl Iterator<Item = TokenStream> + 'a {
res.enumerate().map(|(i, res)| {
let res_ident = Ident::new(&format!("RESOURCE_{}", i), res.init.span());
let cfgs = &res.cfgs;

quote! {
#(#cfgs)*
&mut #res_ident
}
})
}

pub(crate) fn codegen_simple_handler(
export_name: &str,
must_diverge: bool,
handler: &SimpleHandler,
) -> TokenStream {
let resource_decls = declare_resources(handler.params.iter());

let call = {
let callee = &handler.func.sig.ident;
let arguments = resource_arguments(handler.params.iter());

quote! {
#callee(
#(#arguments),*
)
}
};

let ret_ty = match must_diverge {
false => quote!(),
true => quote!(-> !),
};

let handler_fn = &handler.func;

quote! {
const _: () = {
#[export_name = #export_name]
unsafe extern "C" fn cmrt_handler() #ret_ty {
#(#resource_decls)*

#call
}
};

#handler_fn
}
}

pub(crate) fn codegen_interrupt_handler(
args: &InterruptArgs,
handler: &SimpleHandler,
) -> TokenStream {
let variant_path = args.path.clone();
let mut interrupt_enum_type = args.path.clone();
let variant = interrupt_enum_type.segments.pop().unwrap().into_value(); // remove variant

let handler = codegen_simple_handler(&variant.ident.to_string(), false, handler);

// FIXME: You can still define something like
// ```
// struct Trick;
//
// impl Trick {
// const RenamedVariant: Interrupt = Interrupt::Variant;
// }
// ```
// and then use it via `#[interrupt(Trick::RenamedVariant)]`. We can fix this once cortex-m-rt
// and cortex-m are merged, by requiring `Interrupt` to implement `cortex_m::InterruptNumber`,
// which has a safety contract.

quote! {
const _: () = {
// Assert that `interrupt_enum_type` is a type, and `variant_path` is an instance of it.
let _: #interrupt_enum_type = #variant_path;
};

#handler
}
}

pub(crate) fn codegen_exception_handler(
args: &ExceptionArgs,
must_diverge: bool,
handler: &ExceptionHandler,
) -> TokenStream {
let resource_decls =
declare_resources(handler.params.iter().filter_map(|param| match &param.kind {
HandlerParamKind::Resource(res) => Some(res),
_ => None,
}));

let ret_ty = match must_diverge {
false => quote!(),
true => quote!(-> !),
};

let handler_fn = &handler.func;
let export_name = args.name.to_string();

quote! {
const _: () = {
#[export_name = #export_name]
unsafe extern "C" fn cmrt_handler() #ret_ty {
#(#resource_decls)*

// TODO
//#call
}
};

#handler_fn
}
}