#![recursion_limit="128"] #![feature(proc_macro_span)]
mod safe_wrap; mod infer_type;
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::{quote};
use syn::{
parse_macro_input,
};
#[proc_macro_attribute]
pub fn safe_wrap(attr: TokenStream, item: TokenStream) -> TokenStream {
safe_wrap::safe_wrap_internal(attr, item)
}
#[proc_macro_attribute]
pub fn infer_type(attr: TokenStream, item: TokenStream) -> TokenStream {
infer_type::infer_type_internal(attr, item)
}
#[proc_macro]
pub fn out(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as syn::Ident);
let ident = input.to_string();
let expanded = format!(r#"unsafe {{ &mut {} }}"#, ident); expanded.parse().unwrap()
}
#[proc_macro]
pub fn strn(item: TokenStream) -> TokenStream {
let item_str = item.to_string();
let span = proc_macro2::Span::call_site();
if item_str.replace(" ", "") == "()" {
let expanded = quote! {
&Strn::new( b"\0" )
};
return expanded.into();
} else if item_str.contains("parse!") {
return item;
} else if item_str.starts_with("\"") && item_str.ends_with("\"") {
let item_split: Vec<&str> = item_str.splitn(3, "\"").collect();
let lit = item_split[1].to_string() + "\0";
let bytestr = syn::LitByteStr::new(lit.as_bytes(), span);
let expanded = quote! {
&Strn::new( #bytestr )
};
return expanded.into();
}
let expr = parse_macro_input!(item as syn::Expr);
let expr_str = quote! { #expr }.to_string();
match expr {
syn::Expr::Macro(_expr) => {
let expr_split: Vec<&str> = expr_str.splitn(2, "stringify ! (").collect();
let ident = expr_split[1].trim();
let ident_split: Vec<&str> = ident.splitn(2, ")").collect();
let ident = ident_split[0].trim().to_string() + "\0";
let bytestr = syn::LitByteStr::new(ident.as_bytes(), span);
let expanded = quote! {
&Strn::new( #bytestr )
};
return expanded.into();
}
syn::Expr::Lit(_expr) => {
assert!(false, "strn lit"); let expanded = quote! { &Strn::new( b"\0" ) };
return expanded.into();
}
syn::Expr::Try(expr) => {
let expanded = quote! { &Strn::new( #expr ) };
return expanded.into();
}
_ => {}
};
assert!(false, "strn!() pattern not supported: {}", item_str); let expanded = quote! { &Strn::new( b"\0" ) };
expanded.into()
}
#[proc_macro]
pub fn init_strn(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as syn::LitStr);
let span = proc_macro2::Span::call_site();
let val = input.value().to_string() + "\0";
let bytestr = syn::LitByteStr::new(val.as_bytes(), span);
let expanded = quote! {
Strn {
rep: mynewt::StrnRep::ByteStr(#bytestr)
}
};
return expanded.into();
}
#[proc_macro]
pub fn try_cbor(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as syn::Block);
let mut expanded = proc_macro2::TokenStream::new();
for stmt in input.stmts { let stmt_tokens = quote! { #stmt };
match stmt {
syn::Stmt::Semi(expr, _semi) => {
match expr {
syn::Expr::Call(expr) => {
let func = *expr.func; let func = quote! { #func }; if func.to_string().starts_with("cbor_encode_") ||
func.to_string().starts_with("cbor_encoder_") {
let updated_stmt = quote! {
let res = mynewt::encoding::tinycbor::#stmt_tokens;
COAP_CONTEXT.check_result(res);
};
expanded.extend(updated_stmt);
continue; }
}
_ => {} }
}
syn::Stmt::Expr(_expr) => {} syn::Stmt::Local(_local) => {} syn::Stmt::Item(_item) => {} }
expanded.extend(stmt_tokens); }
expanded = quote! {
unsafe {
#expanded
}
};
TokenStream::from(expanded)
}