mod misc;
mod selectors;
mod classes;
mod instances;
mod flatten;
mod strings;
mod export_name;
mod declarations;
use proc_macro::{TokenStream, TokenTree};
use misc::{error, parse_literal_string,parse_ident,parse_type};
use crate::misc::ParsedLiteral;
#[proc_macro]
#[doc(hidden)]
pub fn _objc_selector_decl(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
use crate::selectors::{sel_to_rust_name, make_fn_partial};
let selector = match parse_literal_string(&mut iter) {
Ok(s) => s,
Err(e) => return error(&format!("Expected selector, but {}",e))
};
let rust_name = sel_to_rust_name(&selector.unwrap_literal());
let fn_decl = make_fn_partial(&rust_name) + ";";
match iter.next() {
None => (),
Some(other) => {
return error(&format!("Unexpected token {}",other));
}
}
fn_decl.parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn _objc_selector_impl(stream: TokenStream) -> TokenStream {
use selectors::{sel_to_rust_name,make_fn_partial,sel_expression};
let mut iter = stream.into_iter();
let selector = match parse_literal_string(&mut iter) {
Ok(s) => s,
Err(e) => return error(&format!("Expected selector literal, but {}",e))
}.unwrap_literal();
let rust_name = sel_to_rust_name(&selector);
let mut decl = make_fn_partial(&rust_name);
decl += &sel_expression(&selector);
match iter.next() {
None => (),
Some(other) => {
return error(&format!("Unexpected token {}",other));
}
}
decl.parse().unwrap()
}
#[proc_macro_derive(ObjcInstance)]
pub fn derive_objc_instance(stream: TokenStream) -> TokenStream {
let mut parse_ident = false;
let mut parsed_name = None;
let mut item_help = None;
use flatten::{FlatIterator,FlatTree};
for item in FlatIterator::new(stream.into_iter()) {
match &item {
FlatTree::Ident(i) if !parse_ident && i.to_string() == "struct" => {
parse_ident = true; }
FlatTree::Ident(i) if parse_ident => {
parsed_name = Some(i.to_string());
break;
}
_ => ()
}
item_help = Some(item);
}
if parsed_name.is_none() {
return error(&format!("Looking for `struct Identifier` near {:?}",item_help))
}
instances::instance_impl(&parsed_name.unwrap()).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __objc_implement_class(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let rust_identifier = match parse_ident(&mut iter) {
Ok(i)=> i,
Err(err) => { return error(&format!("Expected rust identifier {:?}",err))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let objc_identifier = match parse_ident(&mut iter) {
Ok(ident) => ident,
Err(e) => { return error(&format!("Expected objc identifier, got {}",e))}
};
match iter.next() {
None => (),
Some(e) => { return error(&format!("Expected end of macro invocation, got {:?}",e))}
};
let result = classes::implement_class(&rust_identifier, &objc_identifier);
result.parse().unwrap()
}
#[proc_macro]
pub fn objc_nsstring(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let literal = match parse_literal_string(&mut iter) {
Ok(literal) => literal,
Err(str) => {return error(&format!("Expected a literal {}",str)) }
}.unwrap_literal();
let extra = iter.next();
if extra.is_some() {
return error(&format!("Expected end of macro near {:?}",extra.unwrap()));
}
strings::static_string(&literal).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __static_asciiz(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_section = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected link section literal, got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident = match parse_ident(&mut iter) {
Ok(ident) => ident,
Err(e) => { return error(&format!("Expected identifier, got {}",e))}
};
let (ident,l_pub) = if ident == "pub" {
let new_ident = match parse_ident(&mut iter) {
Ok(ident) => ident,
Err(e) => { return error(&format!("Expected identifier after 'pub', got {}",e))}
};
(new_ident,true)
}
else {
(ident,false)
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ascii = match misc::parse_ident_or_literal(&mut iter) {
Ok(l) => {l}
Err(e) => { return error(&format!("Expected literal or ident for ascii, {}",e)); }
};
match iter.next() {
None => (),
Some(e) => { return error(&format!("Expected end of macro invocation, got {:?}",e))}
};
export_name::export_ascii(&link_section, l_pub,&ident, &ascii).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __static_asciiz_ident2(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_section = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected link section literal, got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident_1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => { return error(&format!("Expected identifier prefix (literal), got {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident_2 = match parse_ident(&mut iter) {
Ok(l) => {l}
o => { return error(&format!("Expected identifier suffix (ident), got {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ascii = match misc::parse_ident_or_literal(&mut iter) {
Ok(l) => {l}
Err(e) => { return error(&format!("Expected literal or ident for ascii, {}",e)); }
};
match iter.next() {
None => (),
Some(e) => { return error(&format!("Expected end of macro invocation, got {:?}",e))}
};
export_name::export_ascii(&link_section, false,&(ident_1 + &ident_2), &ascii).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __static_asciiz_ident_as_selector(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_section = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected link section literal, got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident_1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => { return error(&format!("Expected identifier prefix (literal), got {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident_2 = match parse_ident(&mut iter) {
Ok(l) => {l}
o => { return error(&format!("Expected identifier suffix (ident), got {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let declaration = match misc::parse_ident_or_literal(&mut iter) {
Ok(l) => {l}
Err(e) => { return error(&format!("Expected literal or ident for ascii, {}",e)); }
};
match iter.next() {
None => (),
Some(e) => { return error(&format!("Expected end of macro invocation, got {:?}",e))}
};
let selector = declarations::parse_to_selector(&declaration);
if selector.is_err() {
return error(&selector.err().unwrap());
}
export_name::export_ascii(&link_section, false,&(ident_1 + &ident_2), &selector.unwrap()).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __static_asciiz_ident_as_type_encoding(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_section = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected link section literal, got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident_1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => { return error(&format!("Expected identifier prefix (literal), got {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident_2 = match parse_ident(&mut iter) {
Ok(l) => {l}
o => { return error(&format!("Expected identifier suffix (ident), got {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let declaration = match misc::parse_ident_or_literal(&mut iter) {
Ok(l) => {l}
Err(e) => { return error(&format!("Expected literal or ident for ascii, {}",e)); }
};
match iter.next() {
None => (),
Some(e) => { return error(&format!("Expected end of macro invocation, got {:?}",e))}
};
let type_encoding = declarations::parse_to_type_encoding(&declaration);
if type_encoding.is_err() {
return error(&type_encoding.err().unwrap());
}
export_name::export_ascii(&link_section, false,&(ident_1 + &ident_2), &type_encoding.unwrap()).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __static_expr(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_section = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected link section literal, got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let export_name_1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected export name literal (prefix), got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let export_name_2 = match misc::parse_ident(&mut iter) {
Ok(i) => {i}
other => {return error(&format!("Expected export name (suffix) ident/literal, {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let attrs = export_name::export_name_attrs(&link_section, &export_name_1, &export_name_2);
let mut attr_stream: TokenStream = attrs.parse().unwrap();
attr_stream.extend(iter);
attr_stream
}
#[doc(hidden)]
#[proc_macro]
pub fn __static_expr3(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_section = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected link section literal, got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let export_name_1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
other => {return error(&format!("Expected export name literal (prefix), got {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let export_name_2 = match misc::parse_ident(&mut iter) {
Ok(i) => {i}
other => {return error(&format!("Expected export name (suffix) ident/literal, {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let export_name_3 = match misc::parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(i)) => {i}
other => {return error(&format!("Expected export name (suffix) ident/literal, {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let attrs = export_name::export_name_attrs3(&link_section, &export_name_1, &export_name_2, &export_name_3);
let mut attr_stream: TokenStream = attrs.parse().unwrap();
attr_stream.extend(iter);
attr_stream
}
#[proc_macro]
pub fn __static_extern(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let link_1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(s)) => s,
other => { return error(&format!("Expected link_name (prefix) literal, {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let link_2 = match parse_ident(&mut iter) {
Ok(s) => s,
other => { return error(&format!("Expected link_name (prefix) literal, {:?}",other))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let initial_str = format!(r#"
#[link_name="{LINK_1}{LINK_2}"]
"#, LINK_1 = link_1, LINK_2 = link_2);
let mut attr_stream: TokenStream = initial_str.parse().unwrap();
attr_stream.extend(iter);
attr_stream
}
#[doc(hidden)]
#[proc_macro]
pub fn __count(stream: TokenStream) -> TokenStream {
let mut count = 1;
for item in stream {
match item {
TokenTree::Punct(p) if p == ',' => {count += 1},
_ => {}
}
}
count.to_string().parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __concat_idents(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let item1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => { return error(&format!("Expected first ident part, {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let item2 = match parse_ident(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected second ident part, {}",e))}
};
return format!("{ITEM1}{ITEM2}",ITEM1=item1,ITEM2=item2).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __concat_3_idents(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let item1 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => { return error(&format!("Expected first ident part, {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let item2 = match parse_ident(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected second ident part, {}",e))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let item3 = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => { return error(&format!("Expected third ident part, {:?}",o))}
};
return format!("{ITEM1}{ITEM2}{item3}",ITEM1=item1,ITEM2=item2).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __mod(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let item1 = match parse_ident(&mut iter) {
Ok(l) => {l}
o => { return error(&format!("Expected first ident part, {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let item2 = match parse_ident(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected second ident part, {}",e))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let group = match iter.next() {
Some(TokenTree::Group(g)) => {
g.to_string()
},
o => { return error(&format!("Expected block, got {:?}",o))}
};
let s = format!("mod {ID1}{ID2} {BLOCK}",ID1=item1, ID2=item2,BLOCK=group);
s.parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __use(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let mut item1 = match parse_ident(&mut iter) {
Ok(l) => {l}
_ => {
match parse_ident(&mut iter) {
Ok(l) => l,
o=> return error(&format!("Expected first ident part, {:?}",o))
}
}
};
let is_pub;
if item1.to_string() == "pub" {
is_pub = true;
item1 = match parse_ident(&mut iter) {
Ok(l) => {l}
o => { return error(&format!("Expected first ident part, {:?}",o))}
};
}
else {
is_pub = false;
}
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let item2 = match parse_ident(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected second ident part, {}",e))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let item3 = match parse_ident(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected second ident part, {}",e))}
};
match iter.next() {
None => {}
other => { return error(&format!("Expected end of macro invocation, got {:?}",other));}
}
format!("{PUB} use {ID1}{ID2}::{ID3};", PUB=if is_pub { "pub"} else {""}, ID1=item1, ID2=item2, ID3=item3).parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __parse_declaration_to_sel(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let expr = match parse_literal_string(&mut iter) {
Ok(ParsedLiteral::Literal(l)) => {l}
o => {return error(&format!("Unexpected {:?}",o))}
};
let selector = declarations::parse_to_selector(&expr);
if selector.is_err() {
return error(&selector.err().unwrap());
}
let fmt = format!(r#""{}""#,selector.unwrap());
fmt.parse().unwrap()
}
#[doc(hidden)]
#[proc_macro]
pub fn __type_declr(stream: TokenStream) -> TokenStream {
let mut iter = stream.into_iter();
let prefix = match parse_ident(&mut iter) {
Ok(l) => {l}
o => { return error(&format!("Expected first ident part, {:?}",o))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ident = match parse_ident(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected second ident part, {}",e))}
};
match iter.next() {
Some(TokenTree::Punct(p)) if p == ',' => (),
o => { return error(&format!("Expected comma, got {:?}",o))}
};
let ty = match parse_type(&mut iter) {
Ok(i) => i,
Err(e) => { return error(&format!("Expected type part, {}",e))}
};
match iter.next() {
None => {}
other => { return error(&format!("Expected end of macro invocation, got {:?}",other));}
}
format!("type {PREFIX}{IDENT} = {TYPE};", PREFIX=prefix, IDENT=ident, TYPE=ty).parse().unwrap()
}